summaryrefslogtreecommitdiffhomepage
path: root/pkg/metric
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/metric')
-rw-r--r--pkg/metric/metric.go250
-rwxr-xr-xpkg/metric/metric_go_proto/metric.pb.go297
-rwxr-xr-xpkg/metric/metric_state_autogen.go4
3 files changed, 551 insertions, 0 deletions
diff --git a/pkg/metric/metric.go b/pkg/metric/metric.go
new file mode 100644
index 000000000..803709cc4
--- /dev/null
+++ b/pkg/metric/metric.go
@@ -0,0 +1,250 @@
+// Copyright 2018 The gVisor Authors.
+//
+// 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 metric provides primitives for collecting metrics.
+package metric
+
+import (
+ "errors"
+ "fmt"
+ "sync"
+ "sync/atomic"
+
+ "gvisor.googlesource.com/gvisor/pkg/eventchannel"
+ "gvisor.googlesource.com/gvisor/pkg/log"
+ pb "gvisor.googlesource.com/gvisor/pkg/metric/metric_go_proto"
+)
+
+var (
+ // ErrNameInUse indicates that another metric is already defined for
+ // the given name.
+ ErrNameInUse = errors.New("metric name already in use")
+
+ // ErrInitializationDone indicates that the caller tried to create a
+ // new metric after initialization.
+ ErrInitializationDone = errors.New("metric cannot be created after initialization is complete")
+)
+
+// Uint64Metric encapsulates a uint64 that represents some kind of metric to be
+// monitored.
+//
+// All metrics must be cumulative, meaning that their values will only increase
+// over time.
+//
+// Metrics are not saved across save/restore and thus reset to zero on restore.
+//
+// TODO(b/67298402): Support non-cumulative metrics.
+// TODO(b/67298427): Support metric fields.
+//
+type Uint64Metric struct {
+ // value is the actual value of the metric. It must be accessed
+ // atomically.
+ value uint64
+}
+
+var (
+ // initialized indicates that all metrics are registered. allMetrics is
+ // immutable once initialized is true.
+ initialized bool
+
+ // allMetrics are the registered metrics.
+ allMetrics = makeMetricSet()
+)
+
+// Initialize sends a metric registration event over the event channel.
+//
+// Precondition:
+// * All metrics are registered.
+// * Initialize/Disable has not been called.
+func Initialize() {
+ if initialized {
+ panic("Initialize/Disable called more than once")
+ }
+ initialized = true
+
+ m := pb.MetricRegistration{}
+ for _, v := range allMetrics.m {
+ m.Metrics = append(m.Metrics, v.metadata)
+ }
+ eventchannel.Emit(&m)
+}
+
+// Disable sends an empty metric registration event over the event channel,
+// disabling metric collection.
+//
+// Precondition:
+// * All metrics are registered.
+// * Initialize/Disable has not been called.
+func Disable() {
+ if initialized {
+ panic("Initialize/Disable called more than once")
+ }
+ initialized = true
+
+ m := pb.MetricRegistration{}
+ if err := eventchannel.Emit(&m); err != nil {
+ panic("unable to emit metric disable event: " + err.Error())
+ }
+}
+
+type customUint64Metric struct {
+ // metadata describes the metric. It is immutable.
+ metadata *pb.MetricMetadata
+
+ // value returns the current value of the metric.
+ value func() uint64
+}
+
+// RegisterCustomUint64Metric registers a metric with the given name.
+//
+// Register must only be called at init and will return and error if called
+// after Initialized.
+//
+// All metrics must be cumulative, meaning that the return values of value must
+// only increase over time.
+//
+// Preconditions:
+// * name must be globally unique.
+// * Initialize/Disable have not been called.
+func RegisterCustomUint64Metric(name string, sync bool, description string, value func() uint64) error {
+ if initialized {
+ return ErrInitializationDone
+ }
+
+ if _, ok := allMetrics.m[name]; ok {
+ return ErrNameInUse
+ }
+
+ allMetrics.m[name] = customUint64Metric{
+ metadata: &pb.MetricMetadata{
+ Name: name,
+ Description: description,
+ Cumulative: true,
+ Sync: sync,
+ Type: pb.MetricMetadata_UINT64,
+ },
+ value: value,
+ }
+ return nil
+}
+
+// MustRegisterCustomUint64Metric calls RegisterCustomUint64Metric and panics
+// if it returns an error.
+func MustRegisterCustomUint64Metric(name string, sync bool, description string, value func() uint64) {
+ if err := RegisterCustomUint64Metric(name, sync, description, value); err != nil {
+ panic(fmt.Sprintf("Unable to register metric %q: %v", name, err))
+ }
+}
+
+// NewUint64Metric creates and registers a new metric with the given name.
+//
+// Metrics must be statically defined (i.e., at init).
+func NewUint64Metric(name string, sync bool, description string) (*Uint64Metric, error) {
+ var m Uint64Metric
+ return &m, RegisterCustomUint64Metric(name, sync, description, m.Value)
+}
+
+// MustCreateNewUint64Metric calls NewUint64Metric and panics if it returns an
+// error.
+func MustCreateNewUint64Metric(name string, sync bool, description string) *Uint64Metric {
+ m, err := NewUint64Metric(name, sync, description)
+ if err != nil {
+ panic(fmt.Sprintf("Unable to create metric %q: %v", name, err))
+ }
+ return m
+}
+
+// Value returns the current value of the metric.
+func (m *Uint64Metric) Value() uint64 {
+ return atomic.LoadUint64(&m.value)
+}
+
+// Increment increments the metric by 1.
+func (m *Uint64Metric) Increment() {
+ atomic.AddUint64(&m.value, 1)
+}
+
+// IncrementBy increments the metric by v.
+func (m *Uint64Metric) IncrementBy(v uint64) {
+ atomic.AddUint64(&m.value, v)
+}
+
+// metricSet holds named metrics.
+type metricSet struct {
+ m map[string]customUint64Metric
+}
+
+// makeMetricSet returns a new metricSet.
+func makeMetricSet() metricSet {
+ return metricSet{
+ m: make(map[string]customUint64Metric),
+ }
+}
+
+// Values returns a snapshot of all values in m.
+func (m *metricSet) Values() metricValues {
+ vals := make(metricValues)
+ for k, v := range m.m {
+ vals[k] = v.value()
+ }
+ return vals
+}
+
+// metricValues contains a copy of the values of all metrics.
+type metricValues map[string]uint64
+
+var (
+ // emitMu protects metricsAtLastEmit and ensures that all emitted
+ // metrics are strongly ordered (older metrics are never emitted after
+ // newer metrics).
+ emitMu sync.Mutex
+
+ // metricsAtLastEmit contains the state of the metrics at the last emit event.
+ metricsAtLastEmit metricValues
+)
+
+// EmitMetricUpdate emits a MetricUpdate over the event channel.
+//
+// Only metrics that have changed since the last call are emitted.
+//
+// EmitMetricUpdate is thread-safe.
+//
+// Preconditions:
+// * Initialize has been called.
+func EmitMetricUpdate() {
+ emitMu.Lock()
+ defer emitMu.Unlock()
+
+ snapshot := allMetrics.Values()
+
+ m := pb.MetricUpdate{}
+ for k, v := range snapshot {
+ // On the first call metricsAtLastEmit will be empty. Include
+ // all metrics then.
+ if prev, ok := metricsAtLastEmit[k]; !ok || prev != v {
+ m.Metrics = append(m.Metrics, &pb.MetricValue{
+ Name: k,
+ Value: &pb.MetricValue_Uint64Value{v},
+ })
+ }
+ }
+
+ metricsAtLastEmit = snapshot
+ if len(m.Metrics) == 0 {
+ return
+ }
+
+ log.Debugf("Emitting metrics: %v", m)
+ eventchannel.Emit(&m)
+}
diff --git a/pkg/metric/metric_go_proto/metric.pb.go b/pkg/metric/metric_go_proto/metric.pb.go
new file mode 100755
index 000000000..553236535
--- /dev/null
+++ b/pkg/metric/metric_go_proto/metric.pb.go
@@ -0,0 +1,297 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: pkg/metric/metric.proto
+
+package gvisor
+
+import (
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+type MetricMetadata_Type int32
+
+const (
+ MetricMetadata_UINT64 MetricMetadata_Type = 0
+)
+
+var MetricMetadata_Type_name = map[int32]string{
+ 0: "UINT64",
+}
+
+var MetricMetadata_Type_value = map[string]int32{
+ "UINT64": 0,
+}
+
+func (x MetricMetadata_Type) String() string {
+ return proto.EnumName(MetricMetadata_Type_name, int32(x))
+}
+
+func (MetricMetadata_Type) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_87b8778a4ff2ab5c, []int{0, 0}
+}
+
+type MetricMetadata struct {
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
+ Cumulative bool `protobuf:"varint,3,opt,name=cumulative,proto3" json:"cumulative,omitempty"`
+ Sync bool `protobuf:"varint,4,opt,name=sync,proto3" json:"sync,omitempty"`
+ Type MetricMetadata_Type `protobuf:"varint,5,opt,name=type,proto3,enum=gvisor.MetricMetadata_Type" json:"type,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *MetricMetadata) Reset() { *m = MetricMetadata{} }
+func (m *MetricMetadata) String() string { return proto.CompactTextString(m) }
+func (*MetricMetadata) ProtoMessage() {}
+func (*MetricMetadata) Descriptor() ([]byte, []int) {
+ return fileDescriptor_87b8778a4ff2ab5c, []int{0}
+}
+
+func (m *MetricMetadata) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_MetricMetadata.Unmarshal(m, b)
+}
+func (m *MetricMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_MetricMetadata.Marshal(b, m, deterministic)
+}
+func (m *MetricMetadata) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_MetricMetadata.Merge(m, src)
+}
+func (m *MetricMetadata) XXX_Size() int {
+ return xxx_messageInfo_MetricMetadata.Size(m)
+}
+func (m *MetricMetadata) XXX_DiscardUnknown() {
+ xxx_messageInfo_MetricMetadata.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MetricMetadata proto.InternalMessageInfo
+
+func (m *MetricMetadata) GetName() string {
+ if m != nil {
+ return m.Name
+ }
+ return ""
+}
+
+func (m *MetricMetadata) GetDescription() string {
+ if m != nil {
+ return m.Description
+ }
+ return ""
+}
+
+func (m *MetricMetadata) GetCumulative() bool {
+ if m != nil {
+ return m.Cumulative
+ }
+ return false
+}
+
+func (m *MetricMetadata) GetSync() bool {
+ if m != nil {
+ return m.Sync
+ }
+ return false
+}
+
+func (m *MetricMetadata) GetType() MetricMetadata_Type {
+ if m != nil {
+ return m.Type
+ }
+ return MetricMetadata_UINT64
+}
+
+type MetricRegistration struct {
+ Metrics []*MetricMetadata `protobuf:"bytes,1,rep,name=metrics,proto3" json:"metrics,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *MetricRegistration) Reset() { *m = MetricRegistration{} }
+func (m *MetricRegistration) String() string { return proto.CompactTextString(m) }
+func (*MetricRegistration) ProtoMessage() {}
+func (*MetricRegistration) Descriptor() ([]byte, []int) {
+ return fileDescriptor_87b8778a4ff2ab5c, []int{1}
+}
+
+func (m *MetricRegistration) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_MetricRegistration.Unmarshal(m, b)
+}
+func (m *MetricRegistration) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_MetricRegistration.Marshal(b, m, deterministic)
+}
+func (m *MetricRegistration) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_MetricRegistration.Merge(m, src)
+}
+func (m *MetricRegistration) XXX_Size() int {
+ return xxx_messageInfo_MetricRegistration.Size(m)
+}
+func (m *MetricRegistration) XXX_DiscardUnknown() {
+ xxx_messageInfo_MetricRegistration.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MetricRegistration proto.InternalMessageInfo
+
+func (m *MetricRegistration) GetMetrics() []*MetricMetadata {
+ if m != nil {
+ return m.Metrics
+ }
+ return nil
+}
+
+type MetricValue struct {
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ // Types that are valid to be assigned to Value:
+ // *MetricValue_Uint64Value
+ Value isMetricValue_Value `protobuf_oneof:"value"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *MetricValue) Reset() { *m = MetricValue{} }
+func (m *MetricValue) String() string { return proto.CompactTextString(m) }
+func (*MetricValue) ProtoMessage() {}
+func (*MetricValue) Descriptor() ([]byte, []int) {
+ return fileDescriptor_87b8778a4ff2ab5c, []int{2}
+}
+
+func (m *MetricValue) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_MetricValue.Unmarshal(m, b)
+}
+func (m *MetricValue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_MetricValue.Marshal(b, m, deterministic)
+}
+func (m *MetricValue) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_MetricValue.Merge(m, src)
+}
+func (m *MetricValue) XXX_Size() int {
+ return xxx_messageInfo_MetricValue.Size(m)
+}
+func (m *MetricValue) XXX_DiscardUnknown() {
+ xxx_messageInfo_MetricValue.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MetricValue proto.InternalMessageInfo
+
+func (m *MetricValue) GetName() string {
+ if m != nil {
+ return m.Name
+ }
+ return ""
+}
+
+type isMetricValue_Value interface {
+ isMetricValue_Value()
+}
+
+type MetricValue_Uint64Value struct {
+ Uint64Value uint64 `protobuf:"varint,2,opt,name=uint64_value,json=uint64Value,proto3,oneof"`
+}
+
+func (*MetricValue_Uint64Value) isMetricValue_Value() {}
+
+func (m *MetricValue) GetValue() isMetricValue_Value {
+ if m != nil {
+ return m.Value
+ }
+ return nil
+}
+
+func (m *MetricValue) GetUint64Value() uint64 {
+ if x, ok := m.GetValue().(*MetricValue_Uint64Value); ok {
+ return x.Uint64Value
+ }
+ return 0
+}
+
+// XXX_OneofWrappers is for the internal use of the proto package.
+func (*MetricValue) XXX_OneofWrappers() []interface{} {
+ return []interface{}{
+ (*MetricValue_Uint64Value)(nil),
+ }
+}
+
+type MetricUpdate struct {
+ Metrics []*MetricValue `protobuf:"bytes,1,rep,name=metrics,proto3" json:"metrics,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *MetricUpdate) Reset() { *m = MetricUpdate{} }
+func (m *MetricUpdate) String() string { return proto.CompactTextString(m) }
+func (*MetricUpdate) ProtoMessage() {}
+func (*MetricUpdate) Descriptor() ([]byte, []int) {
+ return fileDescriptor_87b8778a4ff2ab5c, []int{3}
+}
+
+func (m *MetricUpdate) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_MetricUpdate.Unmarshal(m, b)
+}
+func (m *MetricUpdate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_MetricUpdate.Marshal(b, m, deterministic)
+}
+func (m *MetricUpdate) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_MetricUpdate.Merge(m, src)
+}
+func (m *MetricUpdate) XXX_Size() int {
+ return xxx_messageInfo_MetricUpdate.Size(m)
+}
+func (m *MetricUpdate) XXX_DiscardUnknown() {
+ xxx_messageInfo_MetricUpdate.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_MetricUpdate proto.InternalMessageInfo
+
+func (m *MetricUpdate) GetMetrics() []*MetricValue {
+ if m != nil {
+ return m.Metrics
+ }
+ return nil
+}
+
+func init() {
+ proto.RegisterEnum("gvisor.MetricMetadata_Type", MetricMetadata_Type_name, MetricMetadata_Type_value)
+ proto.RegisterType((*MetricMetadata)(nil), "gvisor.MetricMetadata")
+ proto.RegisterType((*MetricRegistration)(nil), "gvisor.MetricRegistration")
+ proto.RegisterType((*MetricValue)(nil), "gvisor.MetricValue")
+ proto.RegisterType((*MetricUpdate)(nil), "gvisor.MetricUpdate")
+}
+
+func init() { proto.RegisterFile("pkg/metric/metric.proto", fileDescriptor_87b8778a4ff2ab5c) }
+
+var fileDescriptor_87b8778a4ff2ab5c = []byte{
+ // 288 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0xc1, 0x4b, 0xc3, 0x30,
+ 0x14, 0xc6, 0x17, 0xd7, 0x75, 0xfa, 0x3a, 0x86, 0x44, 0xd0, 0x80, 0x20, 0xa5, 0x5e, 0x7a, 0xb1,
+ 0x93, 0x39, 0x76, 0xf3, 0xe2, 0x41, 0xf4, 0x30, 0x85, 0xb0, 0x79, 0x95, 0xd8, 0x86, 0x12, 0x5c,
+ 0xdb, 0xd0, 0xa4, 0x85, 0xfe, 0x75, 0xfe, 0x6b, 0xd2, 0x17, 0x95, 0x4d, 0x76, 0xca, 0xcb, 0xfb,
+ 0xde, 0xf7, 0xf1, 0xcb, 0x0b, 0x5c, 0xe8, 0xcf, 0x7c, 0x56, 0x48, 0x5b, 0xab, 0xf4, 0xe7, 0x48,
+ 0x74, 0x5d, 0xd9, 0x8a, 0xfa, 0x79, 0xab, 0x4c, 0x55, 0x47, 0x5f, 0x04, 0xa6, 0x2b, 0x14, 0x56,
+ 0xd2, 0x8a, 0x4c, 0x58, 0x41, 0x29, 0x78, 0xa5, 0x28, 0x24, 0x23, 0x21, 0x89, 0x4f, 0x38, 0xd6,
+ 0x34, 0x84, 0x20, 0x93, 0x26, 0xad, 0x95, 0xb6, 0xaa, 0x2a, 0xd9, 0x11, 0x4a, 0xbb, 0x2d, 0x7a,
+ 0x05, 0x90, 0x36, 0x45, 0xb3, 0x15, 0x56, 0xb5, 0x92, 0x0d, 0x43, 0x12, 0x1f, 0xf3, 0x9d, 0x4e,
+ 0x9f, 0x6a, 0xba, 0x32, 0x65, 0x1e, 0x2a, 0x58, 0xd3, 0x19, 0x78, 0xb6, 0xd3, 0x92, 0x8d, 0x42,
+ 0x12, 0x4f, 0xe7, 0x97, 0x89, 0x63, 0x4a, 0xf6, 0x79, 0x92, 0x75, 0xa7, 0x25, 0xc7, 0xc1, 0x88,
+ 0x82, 0xd7, 0xdf, 0x28, 0x80, 0xbf, 0x79, 0x7e, 0x59, 0x2f, 0x17, 0xa7, 0x83, 0xe8, 0x11, 0xa8,
+ 0x33, 0x70, 0x99, 0x2b, 0x63, 0x6b, 0x81, 0x38, 0xb7, 0x30, 0x76, 0xef, 0x35, 0x8c, 0x84, 0xc3,
+ 0x38, 0x98, 0x9f, 0x1f, 0x4e, 0xe7, 0xbf, 0x63, 0xd1, 0x2b, 0x04, 0x4e, 0x7a, 0x13, 0xdb, 0x46,
+ 0x1e, 0xdc, 0xc2, 0x35, 0x4c, 0x1a, 0x55, 0xda, 0xe5, 0xe2, 0xbd, 0xed, 0x67, 0x70, 0x0d, 0xde,
+ 0xd3, 0x80, 0x07, 0xae, 0x8b, 0xc6, 0x87, 0x31, 0x8c, 0x50, 0x8d, 0xee, 0x61, 0xe2, 0x02, 0x37,
+ 0x3a, 0x13, 0x56, 0xd2, 0x9b, 0xff, 0x48, 0x67, 0xfb, 0x48, 0x68, 0xff, 0xe3, 0xf9, 0xf0, 0xf1,
+ 0xa3, 0xee, 0xbe, 0x03, 0x00, 0x00, 0xff, 0xff, 0xcb, 0x7f, 0xcb, 0x46, 0xc3, 0x01, 0x00, 0x00,
+}
diff --git a/pkg/metric/metric_state_autogen.go b/pkg/metric/metric_state_autogen.go
new file mode 100755
index 000000000..985c28832
--- /dev/null
+++ b/pkg/metric/metric_state_autogen.go
@@ -0,0 +1,4 @@
+// automatically generated by stateify.
+
+package metric
+