[#150] Add dropped logs metric
All checks were successful
/ DCO (pull_request) Successful in 1m24s
/ Vulncheck (pull_request) Successful in 1m34s
/ Builds (pull_request) Successful in 1m54s
/ Lint (pull_request) Successful in 3m10s
/ Tests (pull_request) Successful in 1m55s

Signed-off-by: Pavel Pogodaev <p.pogodaev@yadro.com>
This commit is contained in:
Pavel Pogodaev 2024-11-24 13:32:40 +03:00
parent a2f8cb6735
commit e9692320d6
4 changed files with 83 additions and 35 deletions

View file

@ -177,6 +177,7 @@ func newApp(ctx context.Context, opt ...Option) App {
a.initResolver()
a.initMetrics()
a.initLogs()
a.initTracing(ctx)
return a
@ -340,6 +341,11 @@ func (a *app) initMetrics() {
a.metrics.SetHealth(metrics.HealthStatusStarting)
}
func (a *app) initLogs() {
coreWithContext := applyZapCoreMiddlewares(a.log.Core(), a.cfg, a.metrics.provider)
a.log = zap.New(coreWithContext, zap.AddStacktrace(zap.NewAtomicLevelAt(zap.FatalLevel)))
}
func newGateMetrics(logger *zap.Logger, provider *metrics.GateMetrics, enabled bool) *gateMetrics {
if !enabled {
logger.Warn(logs.MetricsAreDisabled)

View file

@ -17,6 +17,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/cache"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/logs"
internalnet "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/net"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/metrics"
"git.frostfs.info/TrueCloudLab/frostfs-http-gw/resolver"
grpctracing "git.frostfs.info/TrueCloudLab/frostfs-observability/tracing/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/pool"
@ -428,9 +429,9 @@ func pickLogger(v *viper.Viper) (*zap.Logger, zap.AtomicLevel) {
switch dest {
case destinationStdout:
return newStdoutLogger(v, lvl)
return newStdoutLogger(lvl)
case destinationJournald:
return newJournaldLogger(v, lvl)
return newJournaldLogger(lvl)
default:
panic(fmt.Sprintf("wrong destination for logger: %s", dest))
}
@ -447,18 +448,17 @@ func pickLogger(v *viper.Viper) (*zap.Logger, zap.AtomicLevel) {
// Logger records a stack trace for all messages at or above fatal level.
//
// See also zapcore.Level, zap.NewProductionConfig, zap.AddStacktrace.
func newStdoutLogger(v *viper.Viper, lvl zapcore.Level) (*zap.Logger, zap.AtomicLevel) {
func newStdoutLogger(lvl zapcore.Level) (*zap.Logger, zap.AtomicLevel) {
stdout := zapcore.AddSync(os.Stderr)
level := zap.NewAtomicLevelAt(lvl)
consoleOutCore := zapcore.NewCore(newLogEncoder(), stdout, level)
consoleOutCore = samplingEnabling(v, consoleOutCore)
l := zap.New(consoleOutCore, zap.AddStacktrace(zap.NewAtomicLevelAt(zap.FatalLevel)))
return l, level
}
func newJournaldLogger(v *viper.Viper, lvl zapcore.Level) (*zap.Logger, zap.AtomicLevel) {
func newJournaldLogger(lvl zapcore.Level) (*zap.Logger, zap.AtomicLevel) {
level := zap.NewAtomicLevelAt(lvl)
encoder := zapjournald.NewPartialEncoder(newLogEncoder(), zapjournald.SyslogFields)
@ -470,8 +470,6 @@ func newJournaldLogger(v *viper.Viper, lvl zapcore.Level) (*zap.Logger, zap.Atom
zapjournald.SyslogPid(),
})
coreWithContext = samplingEnabling(v, coreWithContext)
l := zap.New(coreWithContext, zap.AddStacktrace(zap.NewAtomicLevelAt(zap.FatalLevel)))
return l, level
@ -484,19 +482,17 @@ func newLogEncoder() zapcore.Encoder {
return zapcore.NewConsoleEncoder(c)
}
func samplingEnabling(v *viper.Viper, core zapcore.Core) zapcore.Core {
// Zap samples by logging the first cgfLoggerSamplingInitial entries with a given level
// and message within the specified time interval.
// In the above config, only the first cgfLoggerSamplingInitial log entries with the same level and message
// are recorded in cfgLoggerSamplingInterval interval. Every other log entry will be dropped within the interval since
// cfgLoggerSamplingThereafter is specified here.
func applyZapCoreMiddlewares(core zapcore.Core, v *viper.Viper, appMetrics *metrics.GateMetrics) zapcore.Core {
if v.GetBool(cfgLoggerSamplingEnabled) {
core = zapcore.NewSamplerWithOptions(
core,
core = zapcore.NewSamplerWithOptions(core,
v.GetDuration(cfgLoggerSamplingInterval),
v.GetInt(cfgLoggerSamplingInitial),
v.GetInt(cfgLoggerSamplingThereafter),
)
zapcore.SamplerHook(func(_ zapcore.Entry, dec zapcore.SamplingDecision) {
if dec&zapcore.LogDropped > 0 {
appMetrics.IncDroppedLogs()
}
}))
}
return core

View file

@ -76,6 +76,15 @@ var appMetricsDesc = map[string]map[string]Description{
VariableLabels: []string{"endpoint"},
},
},
statisticSubsystem: {
droppedLogs: Description{
Type: dto.MetricType_COUNTER,
Namespace: namespace,
Subsystem: statisticSubsystem,
Name: droppedLogs,
Help: "Dropped logs (by sampling) count",
},
},
}
type Description struct {
@ -148,3 +157,12 @@ func mustNewGaugeVec(description Description) *prometheus.GaugeVec {
description.VariableLabels,
)
}
func mustNewCounter(description Description) prometheus.Counter {
if description.Type != dto.MetricType_COUNTER {
panic("invalid metric type")
}
return prometheus.NewCounter(
prometheus.CounterOpts(newOpts(description)),
)
}

View file

@ -14,11 +14,13 @@ const (
stateSubsystem = "state"
poolSubsystem = "pool"
serverSubsystem = "server"
statisticSubsystem = "statistic"
)
const (
healthMetric = "health"
versionInfoMetric = "version_info"
droppedLogs = "dropped_logs"
)
const (
@ -35,8 +37,6 @@ const (
methodGetContainer = "get_container"
methodListContainer = "list_container"
methodDeleteContainer = "delete_container"
methodGetContainerEacl = "get_container_eacl"
methodSetContainerEacl = "set_container_eacl"
methodEndpointInfo = "endpoint_info"
methodNetworkInfo = "network_info"
methodPutObject = "put_object"
@ -69,6 +69,7 @@ type GateMetrics struct {
stateMetrics
poolMetricsCollector
serverMetrics
statisticMetrics
}
type stateMetrics struct {
@ -76,6 +77,10 @@ type stateMetrics struct {
versionInfo *prometheus.GaugeVec
}
type statisticMetrics struct {
droppedLogs prometheus.Counter
}
type poolMetricsCollector struct {
scraper StatisticScraper
overallErrors prometheus.Gauge
@ -96,10 +101,14 @@ func NewGateMetrics(p StatisticScraper) *GateMetrics {
serverMetric := newServerMetrics()
serverMetric.register()
statsMetric := newStatisticMetrics()
statsMetric.register()
return &GateMetrics{
stateMetrics: *stateMetric,
poolMetricsCollector: *poolMetric,
serverMetrics: *serverMetric,
statisticMetrics: *statsMetric,
}
}
@ -107,6 +116,7 @@ func (g *GateMetrics) Unregister() {
g.stateMetrics.unregister()
prometheus.Unregister(&g.poolMetricsCollector)
g.serverMetrics.unregister()
g.statisticMetrics.unregister()
}
func newStateMetrics() *stateMetrics {
@ -116,6 +126,20 @@ func newStateMetrics() *stateMetrics {
}
}
func newStatisticMetrics() *statisticMetrics {
return &statisticMetrics{
droppedLogs: mustNewCounter(appMetricsDesc[statisticSubsystem][droppedLogs]),
}
}
func (s statisticMetrics) register() {
prometheus.MustRegister(s.droppedLogs)
}
func (s statisticMetrics) unregister() {
prometheus.Unregister(s.droppedLogs)
}
func (m stateMetrics) register() {
prometheus.MustRegister(m.healthCheck)
prometheus.MustRegister(m.versionInfo)
@ -134,6 +158,10 @@ func (m stateMetrics) SetVersion(ver string) {
m.versionInfo.WithLabelValues(ver).Set(1)
}
func (s statisticMetrics) IncDroppedLogs() {
s.droppedLogs.Inc()
}
func newPoolMetricsCollector(p StatisticScraper) *poolMetricsCollector {
return &poolMetricsCollector{
scraper: p,