diff --git a/stats/init.go b/stats/init.go index d9d64b9..3a2bae7 100644 --- a/stats/init.go +++ b/stats/init.go @@ -1,31 +1,106 @@ +// Stats package has implementations of events.Observers for different +// monitoring systems. +// +// Observer is a consumer of events produced by mtg. Consumers, defined +// in this package, process these events and provide information used by +// different monitoring system or time series databases. package stats const ( + // DefaultMetricPrefix defines a base prefix for all metrics. DefaultMetricPrefix = "mtg" + // DefaultStatsdMetricPrefix defines a base prefix for metrics + // which are passed to statsd. DefaultStatsdMetricPrefix = DefaultMetricPrefix + "." - DefaultStatsdTagFormat = "datadog" - MetricClientConnections = "client_connections" - MetricTelegramConnections = "telegram_connections" + // DefaultStatsdTagFormat defines a format of tags for statsd + // observer. + DefaultStatsdTagFormat = "datadog" + + // MetricClientConnections defines a metric which is responsible for a + // number of currently active connections established by client. + // + // Type: gauge + // Tags: + // ip_family | A type of ip (ipv4 or ipv6) of the client. + MetricClientConnections = "client_connections" + + // MetricTelegramConnections defines a metric which is responsible for + // a count of active connections to Telegram servers. + // + // Type: gauge + // Tags: + // telegram_ip | IP address of the telegram server. + // dc | Index of the datacenter to connect to. + MetricTelegramConnections = "telegram_connections" + + // MetricDomainFrontingConnections defines a metric which is + // responsible for a count of active connections to a fronting domain. + // Fronting domain is that one that is encoded in a secret. + // + // Type: gauge + // Tags: + // ip_family | A type of IP (ipv4 or ipv6) that was used. MetricDomainFrontingConnections = "domain_fronting_connections" - MetricTelegramTraffic = "telegram_traffic" + // MetricTelegramTraffic defines a metric for traffic (in bytes) that + // is sent to and from Telegram servers. + // + // Type: counter + // Tags: + // telegram_ip | IP address of the telegram server. + // dc | Index of the datacenter + // direction | Direction of the traffc flow. Values are + // | 'to_client' and 'from_client' + MetricTelegramTraffic = "telegram_traffic" + + // MetricDomainFrontingTraffic defines a metric for traffic (in bytes) + // that is sent to and from fronting domain. + // + // Type: counter + // Tags: + // direction | Direction of the traffc flow. Values are + // | 'to_client' and 'from_client' MetricDomainFrontingTraffic = "domain_fronting_traffic" - MetricDomainFronting = "domain_fronting" - MetricConcurrencyLimited = "concurrency_limited" - MetricIPBlocklisted = "ip_blocklisted" - MetricReplayAttacks = "replay_attacks" + // MetricDomainFronting defines a metric for a number of domain + // fronting routing events. + // + // Type: counter + MetricDomainFronting = "domain_fronting" + // MetricConcurrencyLimited defines a metric for a count of events, + // when the client was blocked due to the concurrency limit. + // + // Type: counter + MetricConcurrencyLimited = "concurrency_limited" + + // MetricIPBlocklisted defines a metric for a count of events, when + // client was blocked because her IP address was found in blocklists. + // + // Type: counter + MetricIPBlocklisted = "ip_blocklisted" + + // MetricReplayAttacks defines a metric for a count of events, when + // mtg has detected a replay attack. Just a reminder: mtg immediately + // routes a connection to a fronting domain if such event is detected. + // + // Type: counter + MetricReplayAttacks = "replay_attacks" + + // TagIPFamily defines a name of the 'ip_family' tag and all values. TagIPFamily = "ip_family" TagIPFamilyIPv4 = "ipv4" TagIPFamilyIPv6 = "ipv6" + // TagTelegramIP defines a name of the 'telegram_ip' tag. TagTelegramIP = "telegram_ip" + // TagDC defines a name of the 'dc' tag. TagDC = "dc" + // TagDirection defines a name of the 'direction' tag. TagDirection = "direction" TagDirectionToClient = "to_client" TagDirectionFromClient = "from_client" diff --git a/stats/prometheus.go b/stats/prometheus.go index aa2933d..634be95 100644 --- a/stats/prometheus.go +++ b/stats/prometheus.go @@ -126,6 +126,12 @@ func (p prometheusProcessor) Shutdown() { p.streams = make(map[string]*streamInfo) } +// PrometheusFactory is a factory of events.Observers which collect +// information in a format suitable for Prometheus. +// +// This factory can also serve on a given listener. In that case it +// starts HTTP server with a single endpoint - a Prometheus-compatible +// scrape output. type PrometheusFactory struct { httpServer *http.Server @@ -142,6 +148,7 @@ type PrometheusFactory struct { metricReplayAttacks prometheus.Counter } +// Make builds a new observer. func (p *PrometheusFactory) Make() events.Observer { return prometheusProcessor{ streams: make(map[string]*streamInfo), @@ -149,14 +156,19 @@ func (p *PrometheusFactory) Make() events.Observer { } } +// Serve starts an HTTP server on a given listener. func (p *PrometheusFactory) Serve(listener net.Listener) error { return p.httpServer.Serve(listener) } +// Close stops a factory. Please pay attention that underlying listener +// is not closed. func (p *PrometheusFactory) Close() error { return p.httpServer.Shutdown(context.Background()) } +// NewPrometheus builds an events.ObserverFactory which can serve HTTP +// endpoint with Prometheus scrape data. func NewPrometheus(metricPrefix, httpPath string) *PrometheusFactory { // nolint: funlen registry := prometheus.NewPedanticRegistry() httpHandler := promhttp.HandlerFor(registry, promhttp.HandlerOpts{ diff --git a/stats/statsd.go b/stats/statsd.go index a1f0ca4..63bc005 100644 --- a/stats/statsd.go +++ b/stats/statsd.go @@ -138,14 +138,23 @@ func (s statsdProcessor) Shutdown() { } } +// StatsdFactory is a factory of events.Observers which dumps +// information to statsd. +// +// Please beware that we support ONLY UDP endpoints there. And this +// factory won't use mtglib.Network so it won't use a proxy if you +// provide any. If you need it, I would recommend starting a local +// statsd and route metrics further by features of the chosen server. type StatsdFactory struct { client *statsd.Client } +// Close stops sending requests to statsd. func (s StatsdFactory) Close() error { return s.client.Close() } +// Make build a new observer. func (s StatsdFactory) Make() events.Observer { return statsdProcessor{ client: s.client, @@ -153,6 +162,10 @@ func (s StatsdFactory) Make() events.Observer { } } +// NewStatsd builds an events.ObserverFactory that sends events +// to statsd. +// +// Valid tagFormats are 'datadog', 'influxdb' and 'graphite'. func NewStatsd(address string, log logger.StdLikeLogger, metricPrefix, tagFormat string) (StatsdFactory, error) { options := []statsd.Option{ diff --git a/timeattack/init.go b/timeattack/init.go index 1c66919..e2f9788 100644 --- a/timeattack/init.go +++ b/timeattack/init.go @@ -1,4 +1,4 @@ -// TimeAttack has implementation of mtglib.TimeAttackDetector> +// TimeAttack has implementation of mtglib.TimeAttackDetector. package timeattack import "time"