build(deps): bump github.com/prometheus/client_golang
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.22.0 to 1.23.0. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.22.0...v1.23.0) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-version: 1.23.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
+2
-2
@@ -345,8 +345,8 @@ func (p *TextParser) startLabelName() stateFn {
|
||||
}
|
||||
// Special summary/histogram treatment. Don't add 'quantile' and 'le'
|
||||
// labels to 'real' labels.
|
||||
if !(p.currentMF.GetType() == dto.MetricType_SUMMARY && p.currentLabelPair.GetName() == model.QuantileLabel) &&
|
||||
!(p.currentMF.GetType() == dto.MetricType_HISTOGRAM && p.currentLabelPair.GetName() == model.BucketLabel) {
|
||||
if (p.currentMF.GetType() != dto.MetricType_SUMMARY || p.currentLabelPair.GetName() != model.QuantileLabel) &&
|
||||
(p.currentMF.GetType() != dto.MetricType_HISTOGRAM || p.currentLabelPair.GetName() != model.BucketLabel) {
|
||||
p.currentLabelPairs = append(p.currentLabelPairs, p.currentLabelPair)
|
||||
}
|
||||
// Check for duplicate label names.
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ func (a *Alert) Resolved() bool {
|
||||
return a.ResolvedAt(time.Now())
|
||||
}
|
||||
|
||||
// ResolvedAt returns true off the activity interval ended before
|
||||
// ResolvedAt returns true iff the activity interval ended before
|
||||
// the given timestamp.
|
||||
func (a *Alert) ResolvedAt(ts time.Time) bool {
|
||||
if a.EndsAt.IsZero() {
|
||||
|
||||
+3
-2
@@ -22,7 +22,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// AlertNameLabel is the name of the label containing the an alert's name.
|
||||
// AlertNameLabel is the name of the label containing the alert's name.
|
||||
AlertNameLabel = "alertname"
|
||||
|
||||
// ExportedLabelPrefix is the prefix to prepend to the label names present in
|
||||
@@ -122,7 +122,8 @@ func (ln LabelName) IsValidLegacy() bool {
|
||||
return false
|
||||
}
|
||||
for i, b := range ln {
|
||||
if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || (b >= '0' && b <= '9' && i > 0)) {
|
||||
// TODO: Apply De Morgan's law. Make sure there are tests for this.
|
||||
if !((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_' || (b >= '0' && b <= '9' && i > 0)) { //nolint:staticcheck
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
+20
-8
@@ -27,13 +27,25 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// NameValidationScheme determines the method of name validation to be used by
|
||||
// all calls to IsValidMetricName() and LabelName IsValid(). Setting UTF-8
|
||||
// mode in isolation from other components that don't support UTF-8 may result
|
||||
// in bugs or other undefined behavior. This value can be set to
|
||||
// LegacyValidation during startup if a binary is not UTF-8-aware binaries. To
|
||||
// avoid need for locking, this value should be set once, ideally in an
|
||||
// init(), before multiple goroutines are started.
|
||||
// NameValidationScheme determines the global default method of the name
|
||||
// validation to be used by all calls to IsValidMetricName() and LabelName
|
||||
// IsValid().
|
||||
//
|
||||
// Deprecated: This variable should not be used and might be removed in the
|
||||
// far future. If you wish to stick to the legacy name validation use
|
||||
// `IsValidLegacyMetricName()` and `LabelName.IsValidLegacy()` methods
|
||||
// instead. This variable is here as an escape hatch for emergency cases,
|
||||
// given the recent change from `LegacyValidation` to `UTF8Validation`, e.g.,
|
||||
// to delay UTF-8 migrations in time or aid in debugging unforeseen results of
|
||||
// the change. In such a case, a temporary assignment to `LegacyValidation`
|
||||
// value in the `init()` function in your main.go or so, could be considered.
|
||||
//
|
||||
// Historically we opted for a global variable for feature gating different
|
||||
// validation schemes in operations that were not otherwise easily adjustable
|
||||
// (e.g. Labels yaml unmarshaling). That could have been a mistake, a separate
|
||||
// Labels structure or package might have been a better choice. Given the
|
||||
// change was made and many upgraded the common already, we live this as-is
|
||||
// with this warning and learning for the future.
|
||||
NameValidationScheme = UTF8Validation
|
||||
|
||||
// NameEscapingScheme defines the default way that names will be escaped when
|
||||
@@ -50,7 +62,7 @@ var (
|
||||
type ValidationScheme int
|
||||
|
||||
const (
|
||||
// LegacyValidation is a setting that requirets that metric and label names
|
||||
// LegacyValidation is a setting that requires that all metric and label names
|
||||
// conform to the original Prometheus character requirements described by
|
||||
// MetricNameRE and LabelNameRE.
|
||||
LegacyValidation ValidationScheme = iota
|
||||
|
||||
+22
-3
@@ -201,6 +201,7 @@ var unitMap = map[string]struct {
|
||||
|
||||
// ParseDuration parses a string into a time.Duration, assuming that a year
|
||||
// always has 365d, a week always has 7d, and a day always has 24h.
|
||||
// Negative durations are not supported.
|
||||
func ParseDuration(s string) (Duration, error) {
|
||||
switch s {
|
||||
case "0":
|
||||
@@ -253,18 +254,36 @@ func ParseDuration(s string) (Duration, error) {
|
||||
return 0, errors.New("duration out of range")
|
||||
}
|
||||
}
|
||||
|
||||
return Duration(dur), nil
|
||||
}
|
||||
|
||||
// ParseDurationAllowNegative is like ParseDuration but also accepts negative durations.
|
||||
func ParseDurationAllowNegative(s string) (Duration, error) {
|
||||
if s == "" || s[0] != '-' {
|
||||
return ParseDuration(s)
|
||||
}
|
||||
|
||||
d, err := ParseDuration(s[1:])
|
||||
|
||||
return -d, err
|
||||
}
|
||||
|
||||
func (d Duration) String() string {
|
||||
var (
|
||||
ms = int64(time.Duration(d) / time.Millisecond)
|
||||
r = ""
|
||||
ms = int64(time.Duration(d) / time.Millisecond)
|
||||
r = ""
|
||||
sign = ""
|
||||
)
|
||||
|
||||
if ms == 0 {
|
||||
return "0s"
|
||||
}
|
||||
|
||||
if ms < 0 {
|
||||
sign, ms = "-", -ms
|
||||
}
|
||||
|
||||
f := func(unit string, mult int64, exact bool) {
|
||||
if exact && ms%mult != 0 {
|
||||
return
|
||||
@@ -286,7 +305,7 @@ func (d Duration) String() string {
|
||||
f("s", 1000, false)
|
||||
f("ms", 1, false)
|
||||
|
||||
return r
|
||||
return sign + r
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
|
||||
+149
-75
@@ -25,73 +25,43 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// LogStyle represents the common logging formats in the Prometheus ecosystem.
|
||||
type LogStyle string
|
||||
|
||||
const (
|
||||
SlogStyle LogStyle = "slog"
|
||||
GoKitStyle LogStyle = "go-kit"
|
||||
|
||||
reservedKeyPrefix = "logged_"
|
||||
)
|
||||
|
||||
var (
|
||||
LevelFlagOptions = []string{"debug", "info", "warn", "error"}
|
||||
// LevelFlagOptions represents allowed logging levels.
|
||||
LevelFlagOptions = []string{"debug", "info", "warn", "error"}
|
||||
// FormatFlagOptions represents allowed formats.
|
||||
FormatFlagOptions = []string{"logfmt", "json"}
|
||||
|
||||
callerAddFunc = false
|
||||
defaultWriter = os.Stderr
|
||||
goKitStyleReplaceAttrFunc = func(groups []string, a slog.Attr) slog.Attr {
|
||||
key := a.Key
|
||||
switch key {
|
||||
case slog.TimeKey:
|
||||
a.Key = "ts"
|
||||
|
||||
// This timestamp format differs from RFC3339Nano by using .000 instead
|
||||
// of .999999999 which changes the timestamp from 9 variable to 3 fixed
|
||||
// decimals (.130 instead of .130987456).
|
||||
t := a.Value.Time()
|
||||
a.Value = slog.StringValue(t.UTC().Format("2006-01-02T15:04:05.000Z07:00"))
|
||||
case slog.SourceKey:
|
||||
a.Key = "caller"
|
||||
src, _ := a.Value.Any().(*slog.Source)
|
||||
|
||||
switch callerAddFunc {
|
||||
case true:
|
||||
a.Value = slog.StringValue(filepath.Base(src.File) + "(" + filepath.Base(src.Function) + "):" + strconv.Itoa(src.Line))
|
||||
default:
|
||||
a.Value = slog.StringValue(filepath.Base(src.File) + ":" + strconv.Itoa(src.Line))
|
||||
}
|
||||
case slog.LevelKey:
|
||||
a.Value = slog.StringValue(strings.ToLower(a.Value.String()))
|
||||
default:
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
defaultReplaceAttrFunc = func(groups []string, a slog.Attr) slog.Attr {
|
||||
key := a.Key
|
||||
switch key {
|
||||
case slog.TimeKey:
|
||||
t := a.Value.Time()
|
||||
a.Value = slog.TimeValue(t.UTC())
|
||||
case slog.SourceKey:
|
||||
src, _ := a.Value.Any().(*slog.Source)
|
||||
a.Value = slog.StringValue(filepath.Base(src.File) + ":" + strconv.Itoa(src.Line))
|
||||
default:
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
defaultWriter = os.Stderr
|
||||
)
|
||||
|
||||
// AllowedLevel is a settable identifier for the minimum level a log entry
|
||||
// must be have.
|
||||
type AllowedLevel struct {
|
||||
s string
|
||||
// Level controls a logging level, with an info default.
|
||||
// It wraps slog.LevelVar with string-based level control.
|
||||
// Level is safe to be used concurrently.
|
||||
type Level struct {
|
||||
lvl *slog.LevelVar
|
||||
}
|
||||
|
||||
func (l *AllowedLevel) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
// NewLevel returns a new Level.
|
||||
func NewLevel() *Level {
|
||||
return &Level{
|
||||
lvl: &slog.LevelVar{},
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Level) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var s string
|
||||
type plain string
|
||||
if err := unmarshal((*plain)(&s)); err != nil {
|
||||
@@ -100,55 +70,65 @@ func (l *AllowedLevel) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
if s == "" {
|
||||
return nil
|
||||
}
|
||||
lo := &AllowedLevel{}
|
||||
if err := lo.Set(s); err != nil {
|
||||
if err := l.Set(s); err != nil {
|
||||
return err
|
||||
}
|
||||
*l = *lo
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *AllowedLevel) String() string {
|
||||
return l.s
|
||||
// Level returns the value of the logging level as an slog.Level.
|
||||
func (l *Level) Level() slog.Level {
|
||||
return l.lvl.Level()
|
||||
}
|
||||
|
||||
// Set updates the value of the allowed level.
|
||||
func (l *AllowedLevel) Set(s string) error {
|
||||
if l.lvl == nil {
|
||||
l.lvl = &slog.LevelVar{}
|
||||
// String returns the current level.
|
||||
func (l *Level) String() string {
|
||||
switch l.lvl.Level() {
|
||||
case slog.LevelDebug:
|
||||
return "debug"
|
||||
case slog.LevelInfo:
|
||||
return "info"
|
||||
case slog.LevelWarn:
|
||||
return "warn"
|
||||
case slog.LevelError:
|
||||
return "error"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// Set updates the logging level with the validation.
|
||||
func (l *Level) Set(s string) error {
|
||||
switch strings.ToLower(s) {
|
||||
case "debug":
|
||||
l.lvl.Set(slog.LevelDebug)
|
||||
callerAddFunc = true
|
||||
case "info":
|
||||
l.lvl.Set(slog.LevelInfo)
|
||||
callerAddFunc = false
|
||||
case "warn":
|
||||
l.lvl.Set(slog.LevelWarn)
|
||||
callerAddFunc = false
|
||||
case "error":
|
||||
l.lvl.Set(slog.LevelError)
|
||||
callerAddFunc = false
|
||||
default:
|
||||
return fmt.Errorf("unrecognized log level %s", s)
|
||||
}
|
||||
l.s = s
|
||||
return nil
|
||||
}
|
||||
|
||||
// AllowedFormat is a settable identifier for the output format that the logger can have.
|
||||
type AllowedFormat struct {
|
||||
// Format controls a logging output format.
|
||||
// Not concurrency-safe.
|
||||
type Format struct {
|
||||
s string
|
||||
}
|
||||
|
||||
func (f *AllowedFormat) String() string {
|
||||
// NewFormat creates a new Format.
|
||||
func NewFormat() *Format { return &Format{} }
|
||||
|
||||
func (f *Format) String() string {
|
||||
return f.s
|
||||
}
|
||||
|
||||
// Set updates the value of the allowed format.
|
||||
func (f *AllowedFormat) Set(s string) error {
|
||||
func (f *Format) Set(s string) error {
|
||||
switch s {
|
||||
case "logfmt", "json":
|
||||
f.s = s
|
||||
@@ -160,18 +140,112 @@ func (f *AllowedFormat) Set(s string) error {
|
||||
|
||||
// Config is a struct containing configurable settings for the logger
|
||||
type Config struct {
|
||||
Level *AllowedLevel
|
||||
Format *AllowedFormat
|
||||
Level *Level
|
||||
Format *Format
|
||||
Style LogStyle
|
||||
Writer io.Writer
|
||||
}
|
||||
|
||||
func newGoKitStyleReplaceAttrFunc(lvl *Level) func(groups []string, a slog.Attr) slog.Attr {
|
||||
return func(groups []string, a slog.Attr) slog.Attr {
|
||||
key := a.Key
|
||||
switch key {
|
||||
case slog.TimeKey, "ts":
|
||||
if t, ok := a.Value.Any().(time.Time); ok {
|
||||
a.Key = "ts"
|
||||
|
||||
// This timestamp format differs from RFC3339Nano by using .000 instead
|
||||
// of .999999999 which changes the timestamp from 9 variable to 3 fixed
|
||||
// decimals (.130 instead of .130987456).
|
||||
a.Value = slog.StringValue(t.UTC().Format("2006-01-02T15:04:05.000Z07:00"))
|
||||
} else {
|
||||
// If we can't cast the any from the value to a
|
||||
// time.Time, it means the caller logged
|
||||
// another attribute with a key of `ts`.
|
||||
// Prevent duplicate keys (necessary for proper
|
||||
// JSON) by renaming the key to `logged_ts`.
|
||||
a.Key = reservedKeyPrefix + key
|
||||
}
|
||||
case slog.SourceKey, "caller":
|
||||
if src, ok := a.Value.Any().(*slog.Source); ok {
|
||||
a.Key = "caller"
|
||||
switch lvl.String() {
|
||||
case "debug":
|
||||
a.Value = slog.StringValue(filepath.Base(src.File) + "(" + filepath.Base(src.Function) + "):" + strconv.Itoa(src.Line))
|
||||
default:
|
||||
a.Value = slog.StringValue(filepath.Base(src.File) + ":" + strconv.Itoa(src.Line))
|
||||
}
|
||||
} else {
|
||||
// If we can't cast the any from the value to
|
||||
// an *slog.Source, it means the caller logged
|
||||
// another attribute with a key of `caller`.
|
||||
// Prevent duplicate keys (necessary for proper
|
||||
// JSON) by renaming the key to
|
||||
// `logged_caller`.
|
||||
a.Key = reservedKeyPrefix + key
|
||||
}
|
||||
case slog.LevelKey:
|
||||
if lvl, ok := a.Value.Any().(slog.Level); ok {
|
||||
a.Value = slog.StringValue(strings.ToLower(lvl.String()))
|
||||
} else {
|
||||
// If we can't cast the any from the value to
|
||||
// an slog.Level, it means the caller logged
|
||||
// another attribute with a key of `level`.
|
||||
// Prevent duplicate keys (necessary for proper
|
||||
// JSON) by renaming the key to `logged_level`.
|
||||
a.Key = reservedKeyPrefix + key
|
||||
}
|
||||
default:
|
||||
}
|
||||
return a
|
||||
}
|
||||
}
|
||||
|
||||
func defaultReplaceAttr(_ []string, a slog.Attr) slog.Attr {
|
||||
key := a.Key
|
||||
switch key {
|
||||
case slog.TimeKey:
|
||||
// Note that we do not change the timezone to UTC anymore.
|
||||
if _, ok := a.Value.Any().(time.Time); !ok {
|
||||
// If we can't cast the any from the value to a
|
||||
// time.Time, it means the caller logged
|
||||
// another attribute with a key of `time`.
|
||||
// Prevent duplicate keys (necessary for proper
|
||||
// JSON) by renaming the key to `logged_time`.
|
||||
a.Key = reservedKeyPrefix + key
|
||||
}
|
||||
case slog.SourceKey:
|
||||
if src, ok := a.Value.Any().(*slog.Source); ok {
|
||||
a.Value = slog.StringValue(filepath.Base(src.File) + ":" + strconv.Itoa(src.Line))
|
||||
} else {
|
||||
// If we can't cast the any from the value to
|
||||
// an *slog.Source, it means the caller logged
|
||||
// another attribute with a key of `source`.
|
||||
// Prevent duplicate keys (necessary for proper
|
||||
// JSON) by renaming the key to
|
||||
// `logged_source`.
|
||||
a.Key = reservedKeyPrefix + key
|
||||
}
|
||||
case slog.LevelKey:
|
||||
if _, ok := a.Value.Any().(slog.Level); !ok {
|
||||
// If we can't cast the any from the value to
|
||||
// an slog.Level, it means the caller logged
|
||||
// another attribute with a key of `level`.
|
||||
// Prevent duplicate keys (necessary for proper
|
||||
// JSON) by renaming the key to
|
||||
// `logged_level`.
|
||||
a.Key = reservedKeyPrefix + key
|
||||
}
|
||||
default:
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// New returns a new slog.Logger. Each logged line will be annotated
|
||||
// with a timestamp. The output always goes to stderr.
|
||||
func New(config *Config) *slog.Logger {
|
||||
if config.Level == nil {
|
||||
config.Level = &AllowedLevel{}
|
||||
_ = config.Level.Set("info")
|
||||
config.Level = NewLevel()
|
||||
}
|
||||
|
||||
if config.Writer == nil {
|
||||
@@ -181,11 +255,11 @@ func New(config *Config) *slog.Logger {
|
||||
logHandlerOpts := &slog.HandlerOptions{
|
||||
Level: config.Level.lvl,
|
||||
AddSource: true,
|
||||
ReplaceAttr: defaultReplaceAttrFunc,
|
||||
ReplaceAttr: defaultReplaceAttr,
|
||||
}
|
||||
|
||||
if config.Style == GoKitStyle {
|
||||
logHandlerOpts.ReplaceAttr = goKitStyleReplaceAttrFunc
|
||||
logHandlerOpts.ReplaceAttr = newGoKitStyleReplaceAttrFunc(config.Level)
|
||||
}
|
||||
|
||||
if config.Format != nil && config.Format.s == "json" {
|
||||
@@ -197,5 +271,5 @@ func New(config *Config) *slog.Logger {
|
||||
// NewNopLogger is a convenience function to return an slog.Logger that writes
|
||||
// to io.Discard.
|
||||
func NewNopLogger() *slog.Logger {
|
||||
return slog.New(slog.NewTextHandler(io.Discard, nil))
|
||||
return New(&Config{Writer: io.Discard})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user