Add generic collector runtimes
This commit is contained in:
parent
61bbe50a68
commit
5b39a77318
83
collector/collector_manager.go
Normal file
83
collector/collector_manager.go
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// Copyright 2015 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type collectorManager struct {
|
||||||
|
collectors []*collectorData
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ CollectorManager = &collectorManager{}
|
||||||
|
|
||||||
|
type collectorData struct {
|
||||||
|
collector Collector
|
||||||
|
nextCollectionTime time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a new CollectorManager that is thread-compatible.
|
||||||
|
func NewCollectorManager() (CollectorManager, error) {
|
||||||
|
return &collectorManager{
|
||||||
|
collectors: []*collectorData{},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cm *collectorManager) RegisterCollector(collector Collector) error {
|
||||||
|
cm.collectors = append(cm.collectors, &collectorData{
|
||||||
|
collector: collector,
|
||||||
|
nextCollectionTime: time.Now(),
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cm *collectorManager) Collect() (time.Time, error) {
|
||||||
|
var errors []error
|
||||||
|
|
||||||
|
// Collect from all collectors that are ready.
|
||||||
|
var next time.Time
|
||||||
|
for _, c := range cm.collectors {
|
||||||
|
if c.nextCollectionTime.Before(time.Now()) {
|
||||||
|
nextCollection, err := c.collector.Collect()
|
||||||
|
if err != nil {
|
||||||
|
errors = append(errors, err)
|
||||||
|
}
|
||||||
|
c.nextCollectionTime = nextCollection
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep track of the next collector that will be ready.
|
||||||
|
if next.IsZero() || next.After(c.nextCollectionTime) {
|
||||||
|
next = c.nextCollectionTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return next, compileErrors(errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make an error slice into a single error.
|
||||||
|
func compileErrors(errors []error) error {
|
||||||
|
if len(errors) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
res := make([]string, len(errors))
|
||||||
|
for i := range errors {
|
||||||
|
res[i] = fmt.Sprintf("Error %d: %v", i, errors[i].Error())
|
||||||
|
}
|
||||||
|
return fmt.Errorf("%s", strings.Join(res, ","))
|
||||||
|
}
|
70
collector/collector_manager_test.go
Normal file
70
collector/collector_manager_test.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// Copyright 2015 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fakeCollector struct {
|
||||||
|
nextCollectionTime time.Time
|
||||||
|
err error
|
||||||
|
collectedFrom int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fc *fakeCollector) Collect() (time.Time, error) {
|
||||||
|
fc.collectedFrom++
|
||||||
|
return fc.nextCollectionTime, fc.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fc *fakeCollector) Name() string {
|
||||||
|
return "fake-collector"
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCollect(t *testing.T) {
|
||||||
|
cm := &collectorManager{}
|
||||||
|
|
||||||
|
firstTime := time.Now().Add(-time.Hour)
|
||||||
|
secondTime := time.Now().Add(time.Hour)
|
||||||
|
f1 := &fakeCollector{
|
||||||
|
nextCollectionTime: firstTime,
|
||||||
|
}
|
||||||
|
f2 := &fakeCollector{
|
||||||
|
nextCollectionTime: secondTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert := assert.New(t)
|
||||||
|
assert.NoError(cm.RegisterCollector(f1))
|
||||||
|
assert.NoError(cm.RegisterCollector(f2))
|
||||||
|
|
||||||
|
// First collection, everyone gets collected from.
|
||||||
|
nextTime, err := cm.Collect()
|
||||||
|
assert.Equal(firstTime, nextTime)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.Equal(1, f1.collectedFrom)
|
||||||
|
assert.Equal(1, f2.collectedFrom)
|
||||||
|
|
||||||
|
f1.nextCollectionTime = time.Now().Add(2 * time.Hour)
|
||||||
|
|
||||||
|
// Second collection, only the one that is ready gets collected from.
|
||||||
|
nextTime, err = cm.Collect()
|
||||||
|
assert.Equal(secondTime, nextTime)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.Equal(2, f1.collectedFrom)
|
||||||
|
assert.Equal(1, f2.collectedFrom)
|
||||||
|
}
|
31
collector/fakes.go
Normal file
31
collector/fakes.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright 2015 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FakeCollectorManager struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fkm *FakeCollectorManager) RegisterCollector(collector Collector) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fkm *FakeCollectorManager) Collect() (time.Time, error) {
|
||||||
|
var zero time.Time
|
||||||
|
return zero, nil
|
||||||
|
}
|
45
collector/types.go
Normal file
45
collector/types.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Copyright 2015 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package collector
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO(vmarmol): Export to a custom metrics type when that is available.
|
||||||
|
|
||||||
|
// Metric collector.
|
||||||
|
type Collector interface {
|
||||||
|
// Collect metrics from this collector.
|
||||||
|
// Returns the next time this collector should be collected from.
|
||||||
|
// Next collection time is always returned, even when an error occurs.
|
||||||
|
// A collection time of zero means no more collection.
|
||||||
|
Collect() (time.Time, error)
|
||||||
|
|
||||||
|
// Name of this collector.
|
||||||
|
Name() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manages and runs collectors.
|
||||||
|
type CollectorManager interface {
|
||||||
|
// Register a collector.
|
||||||
|
RegisterCollector(collector Collector) error
|
||||||
|
|
||||||
|
// Collect from collectors that are ready and return the next time
|
||||||
|
// at which a collector will be ready to collect from.
|
||||||
|
// Next collection time is always returned, even when an error occurs.
|
||||||
|
// A collection time of zero means no more collection.
|
||||||
|
Collect() (time.Time, error)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user