pkg/models/metrics.go (231 lines of code) (raw):
// Copyright 2022 iLogtail 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 models
import (
"fmt"
"strings"
)
type MetricType int
const (
// Common metrics types
_ MetricType = iota
MetricTypeUntyped
MetricTypeCounter
MetricTypeGauge
MetricTypeHistogram
MetricTypeSummary
// Extended metrics types
MetricTypeMeter // In bytetsd, meter is an extension of the counter type, which contains a counter value and a rate value within a period
MetricTypeRateCounter // In bytetsd, ratecounter is an extension of the counter type, which contains a rate value within a period
)
var (
MetricTypeTexts = map[MetricType]string{
MetricTypeCounter: "Counter",
MetricTypeGauge: "Gauge",
MetricTypeHistogram: "Histogram",
MetricTypeSummary: "Summary",
MetricTypeUntyped: "Untyped",
MetricTypeMeter: "Meter",
MetricTypeRateCounter: "RateCounter",
}
MetricTypeValues = map[string]MetricType{
"Counter": MetricTypeCounter,
"Gauge": MetricTypeGauge,
"Histogram": MetricTypeHistogram,
"Summary": MetricTypeSummary,
"Untyped": MetricTypeUntyped,
"Meter": MetricTypeMeter,
"RateCounter": MetricTypeRateCounter,
}
emptyMetricValue = &EmptyMetricValue{}
)
type MetricValue interface {
IsSingleValue() bool
IsMultiValues() bool
GetSingleValue() float64
GetMultiValues() MetricFloatValues
}
type MetricSingleValue struct {
Value float64
}
func (v *MetricSingleValue) IsSingleValue() bool {
return true
}
func (v *MetricSingleValue) IsMultiValues() bool {
return false
}
func (v *MetricSingleValue) GetSingleValue() float64 {
if v != nil {
return v.Value
}
return 0
}
func (v *MetricSingleValue) GetMultiValues() MetricFloatValues {
return NilFloatValues
}
type MetricMultiValue struct {
Values MetricFloatValues
}
func (v *MetricMultiValue) Add(key string, value float64) {
v.Values.Add(key, value)
}
func (v *MetricMultiValue) IsSingleValue() bool {
return false
}
func (v *MetricMultiValue) IsMultiValues() bool {
return true
}
func (v *MetricMultiValue) GetSingleValue() float64 {
return 0
}
func (v *MetricMultiValue) GetMultiValues() MetricFloatValues {
if v != nil && v.Values != nil {
return v.Values
}
return NilFloatValues
}
type EmptyMetricValue struct {
}
func (v *EmptyMetricValue) IsSingleValue() bool {
return false
}
func (v *EmptyMetricValue) IsMultiValues() bool {
return false
}
func (v *EmptyMetricValue) GetSingleValue() float64 {
return 0
}
func (v *EmptyMetricValue) GetMultiValues() MetricFloatValues {
return NilFloatValues
}
type MetricFloatValues interface {
KeyValues[float64]
}
// MetricTypedValues In TSDB such as influxdb,
// its fields not only have numeric types, also string, bool, and array types.
// MetricTypedValues is used to define types other than numeric values.
type MetricTypedValues interface {
KeyValues[*TypedValue]
}
// Defines a Metric which has one or more timeseries. The following is a
// brief summary of the Metric data model. For more details, see:
// https://github.com/alibaba/ilogtail/discussions/518
// - Metric is composed of a metadata and data.
// - Metadata part contains a name, description, unit, tags
// - Data is one of the possible types (Counter, Gauge, Histogram, Summary).
type Metric struct {
Name string
Unit string
Description string
Timestamp uint64
ObservedTimestamp uint64
Tags Tags
MetricType MetricType
Value MetricValue
TypedValue MetricTypedValues
}
func (m *Metric) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Metric) SetName(name string) {
if m != nil {
m.Name = name
}
}
func (m *Metric) GetTags() Tags {
if m != nil {
return m.Tags
}
return NilStringValues
}
func (m *Metric) GetType() EventType {
return EventTypeMetric
}
func (m *Metric) GetTimestamp() uint64 {
if m != nil {
return m.Timestamp
}
return 0
}
func (m *Metric) GetObservedTimestamp() uint64 {
if m != nil {
return m.ObservedTimestamp
}
return 0
}
func (m *Metric) SetObservedTimestamp(timestamp uint64) {
if m != nil {
m.ObservedTimestamp = timestamp
}
}
func (m *Metric) GetMetricType() MetricType {
if m != nil {
return m.MetricType
}
return MetricTypeUntyped
}
func (m *Metric) GetUnit() string {
if m != nil {
return m.Unit
}
return ""
}
func (m *Metric) GetDescription() string {
if m != nil {
return m.Description
}
return ""
}
func (m *Metric) GetValue() MetricValue {
if m != nil && m.Value != nil {
return m.Value
}
return emptyMetricValue
}
func (m *Metric) GetTypedValue() MetricTypedValues {
if m != nil && m.TypedValue != nil {
return m.TypedValue
}
return NilTypedValues
}
func (m *Metric) GetSize() int64 {
return int64(len(m.String()))
}
func (m *Metric) Clone() PipelineEvent {
if m != nil {
return &Metric{
Name: m.Name,
Description: m.Description,
Timestamp: m.Timestamp,
ObservedTimestamp: m.ObservedTimestamp,
Tags: m.Tags,
MetricType: m.MetricType,
Value: m.Value,
TypedValue: m.TypedValue,
}
}
return nil
}
func (m *Metric) String() string {
var builder strings.Builder
builder.WriteString(m.GetName())
tags := m.GetTags()
if tags.Len() > 0 {
builder.WriteByte('{')
sortedTags := tags.SortTo(nil)
for i, tags := range sortedTags {
builder.WriteString(fmt.Sprintf("%v=%v", tags.Key, tags.Value))
if i < len(sortedTags)-1 {
builder.WriteString(", ")
}
}
builder.WriteString("}")
}
builder.WriteString("[Type=")
builder.WriteString(MetricTypeTexts[m.MetricType])
builder.WriteString(", Ts=")
builder.WriteString(fmt.Sprintf("%v", m.Timestamp))
builder.WriteString("] ")
if m.Value.IsSingleValue() {
builder.WriteString(fmt.Sprintf("value=%v", m.Value.GetSingleValue()))
} else {
sortedValues := m.Value.GetMultiValues().SortTo(nil)
for i, values := range sortedValues {
builder.WriteString(fmt.Sprintf("%v=%v", values.Key, values))
if i < len(sortedValues)-1 {
builder.WriteString(", ")
}
}
}
return builder.String()
}