diff --git a/opentelemetry/proto/metrics/v1/gen.go b/opentelemetry/proto/metrics/v1/gen.go new file mode 100644 index 00000000..ca1ee4fe --- /dev/null +++ b/opentelemetry/proto/metrics/v1/gen.go @@ -0,0 +1,106 @@ +// Copyright 2020, OpenTelemetry 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. + +// Notes: This code generates the Kind enum hex in metrics.proto. To +// run this code, execute: +// +// go run gen.go > out.go && go run out.go +// +// The output of this program MUST be tested in an external module, +// using the output of protoc. + +package main + +import ( + "bytes" + "fmt" + "go/format" + "os" + "strconv" + "strings" +) + +var ( + cumulativeProps = []string{"Instantaneous", "Delta", "Cumulative"} + structureProps = []string{"Adding_Monotonic", "Adding", "Grouping"} + syncProps = []string{"Continuous", "Snapshot"} +) + +func main() { + var buf bytes.Buffer + buf.WriteString(`package main + +import "fmt" + + +type ( + Kind int +) + +const ( + INVALID = 0 + + // One of the following three MUST be set. There are 3 exclusive Temporality kinds. + INSTANTANEOUS = 1 << 0 + DELTA = 2 << 0 + CUMULATIVE = 3 << 0 + + // One of the following three MUST be set. There are 3 exclusive Structure kinds. + GROUPING = 1 << 2 + ADDING = 2 << 2 + ADDING_MONOTONIC = 3 << 2 + + // May be set for any instrument. + SNAPSHOT = 1 << 4 +) + +var ( +`) + var fullnames []string + var fullvalues []string + + for _, c := range cumulativeProps { + for _, a := range structureProps { + for _, s := range syncProps { + sfrag := "" + if s == "Snapshot" { + sfrag = fmt.Sprint("|", strings.ToUpper(s)) + } + fullname := fmt.Sprint(strings.ToUpper(c), "_", strings.ToUpper(a), "_", strings.ToUpper(s)) + fullnames = append(fullnames, fullname) + fullvalue := fmt.Sprint(strings.ToUpper(c), "|", strings.ToUpper(a), sfrag) + fullvalues = append(fullvalues, fullvalue) + buf.WriteString(fmt.Sprint(fullname, " Kind = ", fullvalue, "\n")) + } + } + } + buf.WriteString(`) + +func main() { +`) + + for i, fn := range fullnames { + buf.WriteString(fmt.Sprint(`fmt.Printf(" %s = %s; // %s\n", `, strconv.Quote(fn), ",", `fmt.Sprintf("%#x",`, fn, `)`, ",", strconv.Quote(fullvalues[i]), ")\n")) + } + buf.WriteRune('}') + + src, err := format.Source(buf.Bytes()) + if err != nil { + fmt.Println("SOURCE WAS\n", string(buf.Bytes())) + panic(err) + } + if nwritten, err := os.Stdout.Write(src); err != nil || nwritten != len(src) { + panic(err) + } +} diff --git a/opentelemetry/proto/metrics/v1/metrics.proto b/opentelemetry/proto/metrics/v1/metrics.proto index 66207e1a..470685fa 100644 --- a/opentelemetry/proto/metrics/v1/metrics.proto +++ b/opentelemetry/proto/metrics/v1/metrics.proto @@ -44,7 +44,7 @@ message InstrumentationLibraryMetrics { repeated Metric metrics = 2; } -// Defines a Metric which has one or more timeseries. +// Metric contains one or more timeseries. // // The data model and relation between entities is shown in the // diagram below. Here, "DataPoint" is the term used to refer to any @@ -100,7 +100,11 @@ message InstrumentationLibraryMetrics { // - the end of the interval (CUMULATIVE or DELTA) // - the instantaneous time of the event (INSTANTANEOUS). message Metric { - // metric_descriptor describes the Metric. + // Descriptor describes the Metric. + // + // N.B. "Descriptor" is a reserved term in protobuf, protoc + // generates a field named "Descriptor_" thus we use + // "metric_descriptor". MetricDescriptor metric_descriptor = 1; // Data is a list of one or more DataPoints for a single metric. Only one of the @@ -110,76 +114,205 @@ message Metric { repeated DoubleDataPoint double_data_points = 3; repeated HistogramDataPoint histogram_data_points = 4; repeated SummaryDataPoint summary_data_points = 5; + + // TODO(#159) Use for exemplars of aggregated metrics or for + // RAW_INT64 or RAW_DOUBLE metrics: + // repeated RawDataPoint raw_data_points = 3; } // Defines a metric type and its schema. message MetricDescriptor { - // name of the metric, including its DNS name prefix. It must be unique. + // Name of the metric, including its DNS name prefix. It must be unique. string name = 1; - // description of the metric, which can be used in documentation. + // Description of the metric, which can be used in documentation. string description = 2; - // unit in which the metric value is reported. Follows the format + // Unit in which the metric value is reported. Follows the format // described by http://unitsofmeasure.org/ucum.html. string unit = 3; - // Type is the type of values a metric has. - enum Type { - // INVALID_TYPE is the default Type, it MUST not be used. - INVALID_TYPE = 0; + // ValueType is the type of value(s) a metric represents. ValueType + // determines which field of the DataPoint will be used for Metrics + // with this descriptor. See the definition of Kind for detail on + // which aggregations may be expressed for which instruments using + // which value types. + // + // ValueTypes are distinguished by whether a data point of its type + // can _possibly_ represent more than one individual input + // measurement. Single-value data points have a definite one-to-one + // relationship with input measurements. Multi-value data points, + // by contrast, represent one or more input measurements. + // + // ValueTypes are also distinguished by whether the value supports + // subtraction. Not all value types support subtraction, but types + // which do can be converted from CUMULATIVE kind into DELTA kind. + enum ValueType { + // INVALID_TYPE is the default ValueType, it MUST not be used. + INVALID_VALUE_TYPE = 0; + + // ScalarInt64 implies that the value is found in + // Metric.int64_data_points[].value. This indicates a + // single-value data point. Supports subtraction when the Kind is + // ADDING or ADDING_MONOTONIC. + SCALAR_INT64 = 1; + + // ScalarDouble implies that the value is found in + // Metric.double_data_points[].value. This indicates a + // single-value data point. Supports subtraction when the Kind is + // ADDING or ADDING_MONOTONIC. + SCALAR_DOUBLE = 2; + + // Histogram implies that the value is found in + // Metric.histogram_data_points[].histogram. This indicates a + // multi-value data point. Supports subtraction for Kinds. + HISTOGRAM = 3; + + // Summary implies that the value is found in + // Metric.summary_data_points[].summary. This indicates a + // multi-value data point. Does not support subtraction. + SUMMARY = 4; + + // TODO(#159): add RAW_INT64 and RAW_DOUBLE value types. These + // indicate single-value data points. + } - // INT64 values are signed 64-bit integers. - // - // A Metric of this Type MUST store its values as Int64DataPoint. - INT64 = 1; + // ValueType is the type of values this metric has. + ValueType value_type = 4; - // MONOTONIC_INT64 values are monotonically increasing signed 64-bit - // integers. - // - // A Metric of this Type MUST store its values as Int64DataPoint. - MONOTONIC_INT64 = 2; + // KindElement contains a set of bit masks used to construct Kind + // enum values, broken into groups: + // + // "Temporality" is the temporal quality of a metric, indicating the + // time interval over which they are reported. One of the 3 + // Temporality values MUST be set: CUMULATIVE, DELTA, or + // INSTANTANEOUS. + // + // "Structure" is the structural quality of a metric, indicating + // whether the input measurements represent part of an individual + // sum or are considered individual measurements. One of the 3 + // Structure values MUST be set: ADDING_MONOTONIC, ADDING, or + // GROUPING. + // + // "Continuity" describes how the measurement was captured, + // indicating whether measurements represent application-level + // events or were generated through a callback invoked by the SDK. + // One of the 2 Continuity values MUST be set: CONTINUOUS or + // SNAPSHOT. + // + // All 18 combinations of Temporality, Structure, and Coninuity + // describe a meaningful expression of metric data. Users familiar + // with the user-facing OpenTelemetry Metrics API will recognize + // these 18 values as comprised of 6 kinds of instrument combined + // with 3 values of temporality. Structure and Continuity form the + // semantic basis of the various metric instruments, while + // Temporality is an orthogonal concept. The instrument mapping: + // + // Instrument Structure Continuity + // ---------------------------------------------- + // Counter ADDING_MONOTONIC CONTINUOUS + // UpDownCounter ADDING CONTINUOUS + // ValueRecorder GROUPING CONTINUOUS + // SumObserver ADDING_MONOTONIC SNAPSHOT + // UpDownSumObserver ADDING SNAPSHOT + // ValueObserver GROUPING SNAPSHOT + // + // Although the number of KindElement combinations is large, several + // observations help simplify our understanding of Temporality and + // Structure. + // + // About Temporality: + // + // DELTA and CUMULATIVE temporalities are practically identical in + // interpretation, though they differ in intention. In both + // cases, the data point represents data collected across an + // interval of time. The CUMULATIVE kind indicates that the + // client does not reset and that StartTimeUnixNano will be held + // as a constant across data points for a single process. + // + // INSTANTANEOUS data points represent one (or more) data points + // measured at the same (logical) instant in time. For SNAPSHOT + // metrics, these may be represented by multi-value data points, + // but for CONTINUOUS metrics these MUST be represented as + // single-value data points. + // + // About Structure: + // + // ADDING_MONOTONIC and ADDING structures are practically + // identical in form, but commonly differ in interpretation. In + // both cases, individual data points are meant to be combined + // into a sum. In the monotonic case, the sum has a useful + // non-negative-rate property. When represented by a single-value + // DELTA or CONTINUOUS data point, the point represents a sum + // across the interval; when INSTANTANEOUS, the single-value point + // represents an instantaneous change in sum or a pre-computed + // sum, depending on Continuity. + // + // GROUPING structure data points represent individual + // measurements, meant to be combined into a distribution. The + // sum of these data may be meaningful, but individual + // measurements are the focus of these metrics. When represented + // by a single-value data point, the value is the individual + // measurement regardless of Temporality or Continuity. + // + // About Continuity: + // + // CONTINUOUS kind data points result directly from + // application-level events, therefore the count of events defines + // a meaningful rate to the user. Identical CONTINUOUS data + // points (with the same Resource and TimeUnixNano) are considered + // conincidental, therefore instantaneous CONTINUOUS kinds do not + // meaningfully pair with multi-value data points. + // + // SNAPSHOT kind data points result from callbacks invoked by the + // SDK, therefore are called in SDK context (i.e., not traced) and + // the rate of measurements does not define a meaningful rate to + // the user. Identical SNAPSHOT data points (with the same + // Resource and TimeUnixNano) are considered invalid, as only one + // Snapshot can be taken per instant per SDK. Measurements of a + // SNAPSHOT metric are recorded for all label sets at the same + // logical time, therefore can be used to calculate meaningful + // point-in-time ratios. + // + // There is a relationship between ADDING (and ADDING_MONOTONIC) + // Structure and INSTANTANEOUS Continuity: + // + // CONTINUOUS-kind ADDING (and ADDING_MONOTONIC) INSTANTANOUS + // values are changes to a sum, such as might originate from an + // OpenTelemetry Counter or UpDownCounter instrument. This metric + // kind must be represented by a single-value data point because + // they are instantaneous (e.g., a LastValue of GROUPING kind, + // a sum of ADDING kind). + // + // SNAPSHOT-kind ADDING (and ADDING_MONOTONIC) INSTANTANEOUS + // values are sums, such as might originate from an OpenTelemetry + // SumObserver or UpDownSumObserver instrument. This metric kind + // can be meaningfully represented by a multi-value data point + // (e.g., a histogram of aggregated instantaneous values produced + // by an Observer callback). + // + enum KindElement { + // INVALID_KIND_ELEMENT is not used. + INVALID_KIND_ELEMENT = 0; - // DOUBLE values are double-precision floating-point numbers. - // - // A Metric of this Type MUST store its values as DoubleDataPoint. - DOUBLE = 3; + // One of the Temporality kind elements MUST be set. - // MONOTONIC_DOUBLE values are monotonically increasing double-precision - // floating-point numbers. + // INSTANTANEOUS is a metric whose values are measured at a + // particular instant. The values are not aggregated over any time + // interval and are unique per timestamp. As such, these metrics + // are not expected to have an associated start time. // - // A Metric of this Type MUST store its values as DoubleDataPoint. - MONOTONIC_DOUBLE = 4; - - // Histogram measurement. - // Corresponding values are stored in HistogramDataPoint. - HISTOGRAM = 5; - - // Summary value. Some frameworks implemented Histograms as a summary of observations - // (usually things like request durations and response sizes). While it - // also provides a total count of observations and a sum of all observed - // values, it calculates configurable quantiles over a sliding time - // window. - // Corresponding values are stored in SummaryDataPoint. - SUMMARY = 6; - } - - // type is the type of values this metric has. - Type type = 4; - - // Temporality is the temporal quality values of a metric have. It - // describes how those values relate to the time interval over which they - // are reported. - enum Temporality { - // INVALID_TEMPORALITY is the default Temporality, it MUST not be - // used. - INVALID_TEMPORALITY = 0; - - // INSTANTANEOUS is a metric whose values are measured at a particular - // instant. The values are not aggregated over any time interval and are - // unique per timestamp. As such, these metrics are not expected to have - // an associated start time. - INSTANTANEOUS = 1; + // When paired with CONTINUOUS kinds, INSTANTANEOUS metrics must + // be represnted by single-value data points (i.e., an individual + // measurement). When also paired with ADDING (or + // ADDING_MONOTONIC) kinds, the individual measurement is defined + // as a change in the sum. + // + // When paired with SNAPSHOT kinds, INSTANTANEOUS metrics may be + // represented by multi-value data points. When also paired with + // ADDING (or ADDING_MONOTONIC) kinds, the individual measurement + // is defined as a sum. + INSTANTANEOUS = 0x1; // DELTA is a metric whose values are the aggregation of measurements // made over a time interval. Successive metrics contain aggregation of @@ -205,7 +338,7 @@ message MetricDescriptor { // 8. The 1 second collection cycle ends. A metric is exported for the // number of requests received over the interval of time t_0+1 to // t_0+2 with a value of 2. - DELTA = 2; + DELTA = 0x2; // CUMULATIVE is a metric whose values are the aggregation of // successively made measurements from a fixed start time until the last @@ -238,11 +371,175 @@ message MetricDescriptor { // 12. The 1 second collection cycle ends. A metric is exported for the // number of requests received over the interval of time t_1 to // t_0+1 with a value of 1. - CUMULATIVE = 3; + // + // Note that the first value in a sequence of CUMULATIVE metrics + // after a reset is equivalent in value to a DELTA metric for the + // period since the reset. Although a CUMULATIVE metric could + // technically be reset after every collection event and still be + // described as CUMULATIVE, exporters should use DELTA if there is + // no intention of repeating the StartTimeUnixNano timestamp. + CUMULATIVE = 0x3; + + // One of the Structure kind elements MUST be set. + + // GROUPING structure means the value has been computed from + // individual input values considered part of a distribution. + // GROUPING structure implies the sum of measurements is not + // necessarily meaningful. + // + // Value of this kind are defined as a current measurement of the + // metric when represented by single-value data points. + GROUPING = 0x4; + + // ADDING structure means the measurement determines a sum. For + // DELTA kind this is expressed as the change in sum since the + // last collection. For CUMULATIVE kind this is expressed as the + // last collected value of the sum. For INSTANTANEOUS kind this + // is expressed as a scalar value that would be added into a Sum. + // + // Paired with CONTINUOUS INSTANTANEOUS metrics, values of this + // kind are defined as the change in a sum. + // + // Paired with SNAPSHOT INSTANTANEOUS metrics, values of this kind + // are defined as a precomputed sum (i.e., not the change). + ADDING = 0x8; + + // ADDING_MONOTONIC has ADDING structure with a guaranteed + // monotonic sum. ADDING_MONOTONIC indicates that the calculated + // sum is non-decreasing, therefore can be monitored as a + // non-negative rate of change. + // + // Paired with CONTINUOUS INSTANTANEOUS metrics, values of this + // kind are defined as the change in a sum. + // + // Paired with SNAPSHOT INSTANTANEOUS metrics, values of this kind + // are defined as a precomputed sum (i.e., not the change). + ADDING_MONOTONIC = 0xc; + + // SNAPSHOT may be set for any kind of metric, indicating it + // was generated through a callback invoked deliberately by the + // SDK. In SNAPSHOT measurements, TimeUnixNano values depend + // on the SDK's decision to collect, not the application. + // + // SNAPSHOT measurements may be used to define point-in-time + // ratios, as data points from the same callback execution MUST + // share a single logical timestamp. + // + // When SNAPSHOT is not set, it implies the event originated from + // the application calling the SDK with a measurement and possibly + // a tracing context. These events are CONTINUOUS measurements, + // in that case. + SNAPSHOT = 0x10; + } + + // Kind describes how the metric was produced, according to its + // contituent KindElements. With 18 meaningful combinations of the + // Kind element and a distinction bewteen single-value and + // multi-value data points, there exist 36 possible meaningful + // combinations of kind and value type, with several notes: + // + // Three pairings of INSTANTANEOUS and CONTINUOUS do not admit + // multi-value data points, excluding 3 meaningless Kinds. + // + // The CUMULATIVE kinds are generally paired with value types that + // support subtraction, since they can be used to observe + // differences between cumulative states. + // + // Kinds are described below by reference to the OpenTelemetry API + // instrument that would produce such a point. The use of + // OpenTelemetry instruments in these descriptions is an + // abbreviation technique. Data points imported from external + // systems should be mapped into data points with a compatible value + // type and Kind should be selectedb based on what is known about + // Temporality, Structure, and Continuity. + // + // It is not expected that receivers of this data format will need + // to construct switch statements for all Kind combinations. For + // example, a consumer that demands only CUMULATIVE data is only + // required to handle 6 data point Kinds. For the most part, information about Continuity is only needed in a few places + enum Kind { + // INVALID_KIND is the default Kind, it MUST not be used. + INVALID_KIND = 0; + + // The following hex values are generated by gen.go in this source + // directory. + + // Metric data point contains a single Counter measurement. + // Multi-value type data points are not applicable. + INSTANTANEOUS_ADDING_MONOTONIC_CONTINUOUS = 0xd; + + // Metric data point contains one or more SumObserver measurement + // at the same instant. + INSTANTANEOUS_ADDING_MONOTONIC_SNAPSHOT = 0x1d; + + // Metric data point contains a single UpDownCounter measurement. + // Multi-value type data points are not applicable. + INSTANTANEOUS_ADDING_CONTINUOUS = 0x9; + + // Metric data point contains one or more UpDownSumObserver + // measurement at the same instant. + INSTANTANEOUS_ADDING_SNAPSHOT = 0x19; + + // Metric data point contains one or more ValueRecorder measurement. + // Multi-value type data points are not applicable. + INSTANTANEOUS_GROUPING_CONTINUOUS = 0x5; + + // Metric data point contains one or more ValueObserver measurement + // at the same instant. + INSTANTANEOUS_GROUPING_SNAPSHOT = 0x15; + + // Metric data point contains the accumulated change due to a + // series of Counter measurements across a collection interval. + DELTA_ADDING_MONOTONIC_CONTINUOUS = 0xe; + + // Metric data point contains the change between subsequent + // SubObserver measurements. + DELTA_ADDING_MONOTONIC_SNAPSHOT = 0x1e; + + // Metric data point contains the accumulated change due to a + // series of UpDownCounter measurements across a collection interval. + DELTA_ADDING_CONTINUOUS = 0xa; + + // Metric data point contains the change between subsequent + // UpDownSubObserver measurements. + DELTA_ADDING_SNAPSHOT = 0x1a; + + // Metric data point contains one or more ValueRecorder + // measurement collected during an interval. + DELTA_GROUPING_CONTINUOUS = 0x6; + + // Metric data point contains one or more ValueObserver + // measurement collected during an interval. + DELTA_GROUPING_SNAPSHOT = 0x16; + + // Metric data point contains an accumulation of Counter + // measurements across multiple collection intervals. + CUMULATIVE_ADDING_MONOTONIC_CONTINUOUS = 0xf; + + // Metric data point contains one or more SumObserver + // measurements across multiple collection intervals. + CUMULATIVE_ADDING_MONOTONIC_SNAPSHOT = 0x1f; + + // Metric data point contains an accumulation of UpDownCounter + // measurements across multiple collection intervals. + CUMULATIVE_ADDING_CONTINUOUS = 0xb; + + // Metric data point contains one or more UpDownSumObserver + // measurements across multiple collection intervals. + CUMULATIVE_ADDING_SNAPSHOT = 0x1b; + + // Metric data point contains one or more ValueRecorder + // measurement collected across multiple collection intervals. + CUMULATIVE_GROUPING_CONTINUOUS = 0x7; + + // Metric data point contains one or more ValueObserver + // measurement collected across multiple collection intervals. + CUMULATIVE_GROUPING_SNAPSHOT = 0x17; } - // temporality is the Temporality of values this metric has. - Temporality temporality = 5; + // Kind describes properties of the Metric that are necessary to + // interpret the data and/or describe how it was produced. + Kind kind = 5; } // Int64DataPoint is a single data point in a timeseries that describes the time-varying