This repository has been archived by the owner on Oct 2, 2022. It is now read-only.
generated from ContainerSSH/library-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Janos Pasztor
committed
Nov 23, 2020
1 parent
74925be
commit 63c4cd0
Showing
18 changed files
with
790 additions
and
145 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,132 +1,185 @@ | ||
package metrics | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"net" | ||
"sort" | ||
"sync" | ||
"strings" | ||
"time" | ||
) | ||
|
||
// MetricType is the enum for tye types of metrics supported | ||
type MetricType string | ||
|
||
const ( | ||
// MetricTypeCounter is a data type that contains ever increasing numbers from the start of the server. | ||
MetricTypeCounter MetricType = "counter" | ||
|
||
"github.com/containerssh/geoip" | ||
// MetricTypeGauge is a metric type that can increase or decrease depending on the current value. | ||
MetricTypeGauge MetricType = "gauge" | ||
) | ||
|
||
type MetricCollector struct { | ||
mutex *sync.Mutex | ||
metricKeys map[string]*Metric | ||
metrics map[string]map[string]float64 | ||
help map[string]string | ||
types map[string]MetricType | ||
geoIpLookupProvider geoip.LookupProvider | ||
// Metric is a descriptor for metrics. | ||
type Metric struct { | ||
// Name is the name for the metric. | ||
Name string | ||
|
||
// Help is the help text for this metric. | ||
Help string | ||
|
||
// Unit describes the unit of the metric. | ||
Unit string | ||
|
||
// Created describes the time the metric was created. This is important for counters. | ||
Created time.Time | ||
|
||
// Type describes how the metric behaves. | ||
Type MetricType | ||
} | ||
|
||
func New(geoIpLookupProvider geoip.LookupProvider) *MetricCollector { | ||
return &MetricCollector{ | ||
&sync.Mutex{}, | ||
make(map[string]*Metric, 0), | ||
make(map[string]map[string]float64, 0), | ||
make(map[string]string, 0), | ||
make(map[string]MetricType, 0), | ||
geoIpLookupProvider, | ||
} | ||
// String formats a metric as the OpenMetrics metadata | ||
func (metric Metric) String() string { | ||
return fmt.Sprintf( | ||
"# HELP %s %s\n"+ | ||
"# UNIT %s %s\n"+ | ||
"# TYPE %s %s\n", | ||
metric.Name, | ||
metric.Help, | ||
metric.Name, | ||
metric.Unit, | ||
metric.Name, | ||
metric.Type) | ||
} | ||
|
||
func (collector *MetricCollector) GetHelp(metricName string) string { | ||
if val, ok := collector.help[metricName]; ok { | ||
return val | ||
} | ||
return "" | ||
// MetricValue is a structure that contains a value for a specific metric name and set of values. | ||
type MetricValue struct { | ||
// Name contains the name of the value. | ||
Name string | ||
|
||
// Labels contains a key-value map of labels to which the Value is specific. | ||
Labels map[string]string | ||
|
||
// Value contains the specific value stored. | ||
Value float64 | ||
} | ||
|
||
func (collector *MetricCollector) GetType(metricName string) MetricType { | ||
if val, ok := collector.types[metricName]; ok { | ||
return val | ||
// CombinedName returns the name and labels combined. | ||
func (metricValue MetricValue) CombinedName() string { | ||
var labelList []string | ||
|
||
keys := make([]string, 0, len(metricValue.Labels)) | ||
for k := range metricValue.Labels { | ||
keys = append(keys, k) | ||
} | ||
return "" | ||
} | ||
sort.Strings(keys) | ||
|
||
func (collector *MetricCollector) GetMetricNames() []string { | ||
names := make([]string, len(collector.metrics)) | ||
i := 0 | ||
for k := range collector.metrics { | ||
names[i] = k | ||
i = i + 1 | ||
for _, k := range keys { | ||
// TODO escaping | ||
labelList = append(labelList, k+"=\""+metricValue.Labels[k]+"\"") | ||
} | ||
sort.Slice(names, func(i, j int) bool { | ||
return names[i] < names[j] | ||
}) | ||
return names | ||
} | ||
|
||
func (collector *MetricCollector) GetMetrics(name string) map[string]float64 { | ||
if val, ok := collector.metrics[name]; ok { | ||
return val | ||
var labels string | ||
if len(labelList) > 0 { | ||
labels = "{" + strings.Join(labelList, ",") + "}" | ||
} else { | ||
return make(map[string]float64, 0) | ||
labels = "" | ||
} | ||
} | ||
|
||
func (collector *MetricCollector) SetMetricMeta(metricName string, help string, metricType MetricType) { | ||
collector.mutex.Lock() | ||
collector.help[metricName] = help | ||
collector.types[metricName] = metricType | ||
collector.mutex.Unlock() | ||
return metricValue.Name + labels | ||
} | ||
|
||
func (collector *MetricCollector) Get(metric Metric) float64 { | ||
collector.mutex.Lock() | ||
defer collector.mutex.Unlock() | ||
return collector.get(metric) | ||
} | ||
func (collector *MetricCollector) Set(metric Metric, value float64) { | ||
collector.mutex.Lock() | ||
defer collector.mutex.Unlock() | ||
collector.set(metric, value) | ||
} | ||
func (collector *MetricCollector) Increment(metric Metric) float64 { | ||
collector.mutex.Lock() | ||
defer collector.mutex.Unlock() | ||
value := collector.get(metric) | ||
value = value + 1 | ||
collector.set(metric, value) | ||
return value | ||
// String creates a string out of the name, labels, and value. | ||
func (metricValue MetricValue) String() string { | ||
return fmt.Sprintf("%s %f\n", metricValue.CombinedName(), metricValue.Value) | ||
} | ||
|
||
func (collector *MetricCollector) IncrementGeo(metric Metric, remoteAddr net.IP) float64 { | ||
metric.Labels["country"] = collector.geoIpLookupProvider.Lookup(remoteAddr) | ||
return collector.Increment(metric) | ||
// MetricAlreadyExists is an error that is returned from the Create functions when the metric already exists. | ||
var MetricAlreadyExists = errors.New("the specified metric already exists") | ||
|
||
// CounterCannotBeIncrementedByNegative is an error returned by counters when they are incremented with a negative | ||
// number. | ||
var CounterCannotBeIncrementedByNegative = errors.New("a counter cannot be incremented by a negative number") | ||
|
||
// Collector is the main interface for interacting with the metrics collector. | ||
type Collector interface { | ||
// CreateCounter creates a monotonic (increasing) counter with the specified name and help text. | ||
CreateCounter(name string, unit string, help string) (SimpleCounter, error) | ||
|
||
// CreateCounterGeo creates a monotonic (increasing) counter that is labeled with the country from the GeoIP lookup | ||
// with the specified name and help text. | ||
CreateCounterGeo(name string, unit string, help string) (SimpleGeoCounter, error) | ||
|
||
// CreateGauge creates a freely modifiable numeric gauge with the specified name and help text. | ||
CreateGauge(name string, unit string, help string) (SimpleGauge, error) | ||
|
||
// CreateGaugeGeo creates a freely modifiable numeric gauge that is labeled with the country from the GeoIP lookup | ||
// with the specified name and help text. | ||
CreateGaugeGeo(name string, unit string, help string) (SimpleGeoGauge, error) | ||
|
||
// ListMetrics returns a list of metrics metadata stored in the collector. | ||
ListMetrics() []Metric | ||
|
||
// GetMetric returns a set of values with labels for a specified metric name. | ||
GetMetric(name string) []MetricValue | ||
|
||
// String returns a Prometheus/OpenMetrics-compatible document with all metrics. | ||
String() string | ||
} | ||
|
||
func (collector *MetricCollector) Decrement(metric Metric) float64 { | ||
collector.mutex.Lock() | ||
defer collector.mutex.Unlock() | ||
value := collector.get(metric) | ||
value = value - 1 | ||
collector.set(metric, value) | ||
return value | ||
// SimpleCounter is a simple counter that can only be incremented. | ||
type SimpleCounter interface { | ||
// Increment increments the counter by 1 | ||
Increment() | ||
|
||
// IncrementBy increments the counter by the specified number. Only returns an error if the passed by parameter is | ||
// negative. | ||
IncrementBy(by float64) error | ||
} | ||
|
||
func (collector *MetricCollector) DecrementGeo(metric Metric, remoteAddr net.IP) float64 { | ||
metric.Labels["country"] = collector.geoIpLookupProvider.Lookup(remoteAddr) | ||
return collector.Decrement(metric) | ||
// SimpleGeoCounter is a simple counter that can only be incremented and is labeled with the country from a GeoIP | ||
// lookup. | ||
type SimpleGeoCounter interface { | ||
// Increment increments the counter for the country from the specified ip by 1. | ||
Increment(ip net.IP) | ||
|
||
// IncrementBy increments the counter for the country from the specified ip by the specified value. | ||
// Only returns an error if the passed by parameter is negative. | ||
IncrementBy(ip net.IP, by float64) error | ||
} | ||
|
||
func (collector *MetricCollector) get(metric Metric) float64 { | ||
if _, ok := collector.metricKeys[(&metric).ToString()]; !ok { | ||
collector.metricKeys[(&metric).ToString()] = &metric | ||
} | ||
if _, ok := collector.metrics[metric.Name]; !ok { | ||
collector.metrics[metric.Name] = make(map[string]float64, 0) | ||
return 0 | ||
} | ||
if _, ok := collector.metrics[metric.Name][(&metric).ToString()]; ok { | ||
return collector.metrics[metric.Name][(&metric).ToString()] | ||
} | ||
return 0 | ||
// SimpleGauge is a metric that can be incremented and decremented. | ||
type SimpleGauge interface { | ||
// Increment increments the counter by 1 | ||
Increment() | ||
|
||
// IncrementBy increments the counter by the specified number. | ||
IncrementBy(by float64) | ||
|
||
// Decrement decreases the metric by 1. | ||
Decrement() | ||
|
||
// Decrement decreases the metric by the specified value. | ||
DecrementBy(by float64) | ||
|
||
// Set sets the value of the metric to an exact value. | ||
Set(value float64) | ||
} | ||
func (collector *MetricCollector) set(metric Metric, value float64) { | ||
if _, ok := collector.metricKeys[(&metric).ToString()]; !ok { | ||
collector.metricKeys[(&metric).ToString()] = &metric | ||
} | ||
if _, ok := collector.metrics[metric.Name]; !ok { | ||
collector.metrics[metric.Name] = make(map[string]float64, 0) | ||
} | ||
collector.metrics[metric.Name][(&metric).ToString()] = value | ||
|
||
// SimpleGeoGauge is a metric that can be incremented and decremented and is labeled by the country from a GeoIP lookup. | ||
type SimpleGeoGauge interface { | ||
// Increment increments the counter for the country from the specified ip by 1. | ||
Increment(ip net.IP) | ||
|
||
// IncrementBy increments the counter for the country from the specified ip by the specified value. | ||
IncrementBy(ip net.IP, by float64) | ||
|
||
// Decrement decreases the value for the country looked up from the specified IP by 1. | ||
Decrement(ip net.IP) | ||
|
||
// DecrementBy decreases the value for the country looked up from the specified IP by the specified value. | ||
DecrementBy(ip net.IP, by float64) | ||
|
||
// Set sets the value of the metric for the country looked up from the specified IP. | ||
Set(ip net.IP, value float64) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package metrics | ||
|
||
import ( | ||
"sync" | ||
|
||
"github.com/containerssh/geoip" | ||
) | ||
|
||
// New creates the metric collector. | ||
func New(geoIpLookupProvider geoip.LookupProvider) Collector { | ||
return &collector{ | ||
geoIpLookupProvider: geoIpLookupProvider, | ||
mutex: &sync.Mutex{}, | ||
metricsMap: map[string]Metric{}, | ||
metrics: []Metric{}, | ||
values: map[string]*metricValue{}, | ||
} | ||
} |
Oops, something went wrong.