diff --git a/README.md b/README.md index cb18a5ebcc..b5d5df37c6 100644 --- a/README.md +++ b/README.md @@ -1166,6 +1166,8 @@ Below is the output for `/path/to/vmselect -help`: Allows renaming fields in JSON formatted logs. Example: "ts:timestamp,msg:message" renames "ts" to "timestamp" and "msg" to "message". Supported fields: ts, level, caller, msg -loggerLevel string Minimum level of errors to log. Possible values: INFO, WARN, ERROR, FATAL, PANIC (default "INFO") + -loggerMaxArgLen int + The maximum length of a single logged argument. Longer arguments are replaced with 'arg_start..arg_end', where 'arg_start' and 'arg_end' is prefix and suffix of the arg with the length not exceeding -loggerMaxArgLen / 2 (default 500) -loggerOutput string Output for the logs. Supported values: stderr, stdout (default "stderr") -loggerTimezone string diff --git a/app/vmselect/promql/eval.go b/app/vmselect/promql/eval.go index 06844cbb02..0d703a1184 100644 --- a/app/vmselect/promql/eval.go +++ b/app/vmselect/promql/eval.go @@ -24,6 +24,7 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/lib/memory" "github.com/VictoriaMetrics/VictoriaMetrics/lib/querytracer" "github.com/VictoriaMetrics/VictoriaMetrics/lib/storage" + "github.com/VictoriaMetrics/VictoriaMetrics/lib/stringsutil" "github.com/VictoriaMetrics/metrics" "github.com/VictoriaMetrics/metricsql" ) @@ -274,7 +275,7 @@ func getTimestamps(start, end, step int64, maxPointsPerSeries int) []int64 { func evalExpr(qt *querytracer.Tracer, ec *EvalConfig, e metricsql.Expr) ([]*timeseries, error) { if qt.Enabled() { query := string(e.AppendString(nil)) - query = bytesutil.LimitStringLen(query, 300) + query = stringsutil.LimitStringLen(query, 300) mayCache := ec.mayCache() qt = qt.NewChild("eval: query=%s, timeRange=%s, step=%d, mayCache=%v", query, ec.timeRangeString(), ec.Step, mayCache) } @@ -1431,6 +1432,10 @@ func evalInstantRollup(qt *querytracer.Tracer, ec *EvalConfig, funcName string, } func hasDuplicateSeries(tss []*timeseries) bool { + if len(tss) <= 1 { + return false + } + m := make(map[string]struct{}, len(tss)) bb := bbPool.Get() defer bbPool.Put(bb) diff --git a/app/vmselect/promql/rollup_result_cache.go b/app/vmselect/promql/rollup_result_cache.go index 2cb1fa763e..693e0a7ac7 100644 --- a/app/vmselect/promql/rollup_result_cache.go +++ b/app/vmselect/promql/rollup_result_cache.go @@ -18,6 +18,7 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/lib/memory" "github.com/VictoriaMetrics/VictoriaMetrics/lib/querytracer" "github.com/VictoriaMetrics/VictoriaMetrics/lib/storage" + "github.com/VictoriaMetrics/VictoriaMetrics/lib/stringsutil" "github.com/VictoriaMetrics/VictoriaMetrics/lib/workingsetcache" "github.com/VictoriaMetrics/fastcache" "github.com/VictoriaMetrics/metrics" @@ -159,7 +160,7 @@ func ResetRollupResultCache() { func (rrc *rollupResultCache) GetInstantValues(qt *querytracer.Tracer, at *auth.Token, expr metricsql.Expr, window, step int64, etfss [][]storage.TagFilter) []*timeseries { if qt.Enabled() { query := string(expr.AppendString(nil)) - query = bytesutil.LimitStringLen(query, 300) + query = stringsutil.LimitStringLen(query, 300) qt = qt.NewChild("rollup cache get instant values: query=%s, window=%d, step=%d", query, window, step) defer qt.Done() } @@ -181,7 +182,7 @@ func (rrc *rollupResultCache) GetInstantValues(qt *querytracer.Tracer, at *auth. func (rrc *rollupResultCache) PutInstantValues(qt *querytracer.Tracer, at *auth.Token, expr metricsql.Expr, window, step int64, etfss [][]storage.TagFilter, tss []*timeseries) { if qt.Enabled() { query := string(expr.AppendString(nil)) - query = bytesutil.LimitStringLen(query, 300) + query = stringsutil.LimitStringLen(query, 300) startStr := "" if len(tss) > 0 { startStr = storage.TimestampToHumanReadableFormat(tss[0].Timestamps[0]) @@ -214,7 +215,7 @@ func (rrc *rollupResultCache) DeleteInstantValues(qt *querytracer.Tracer, at *au if qt.Enabled() { query := string(expr.AppendString(nil)) - query = bytesutil.LimitStringLen(query, 300) + query = stringsutil.LimitStringLen(query, 300) qt.Printf("rollup result cache delete instant values: query=%s, window=%d, step=%d", query, window, step) } } @@ -222,7 +223,7 @@ func (rrc *rollupResultCache) DeleteInstantValues(qt *querytracer.Tracer, at *au func (rrc *rollupResultCache) GetSeries(qt *querytracer.Tracer, ec *EvalConfig, expr metricsql.Expr, window int64) (tss []*timeseries, newStart int64) { if qt.Enabled() { query := string(expr.AppendString(nil)) - query = bytesutil.LimitStringLen(query, 300) + query = stringsutil.LimitStringLen(query, 300) qt = qt.NewChild("rollup cache get series: query=%s, timeRange=%s, window=%d, step=%d", query, ec.timeRangeString(), window, ec.Step) defer qt.Done() } @@ -307,7 +308,7 @@ var resultBufPool bytesutil.ByteBufferPool func (rrc *rollupResultCache) PutSeries(qt *querytracer.Tracer, ec *EvalConfig, expr metricsql.Expr, window int64, tss []*timeseries) { if qt.Enabled() { query := string(expr.AppendString(nil)) - query = bytesutil.LimitStringLen(query, 300) + query = stringsutil.LimitStringLen(query, 300) qt = qt.NewChild("rollup cache put series: query=%s, timeRange=%s, step=%d, window=%d, series=%d", query, ec.timeRangeString(), ec.Step, window, len(tss)) defer qt.Done() } diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 17696e6620..fe3b2f2e9f 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -81,6 +81,7 @@ The sandbox cluster installation is running under the constant load generated by * FEATURE: all: track requests with wrong auth key and wrong basic auth at `vm_http_request_errors_total` [metric](https://docs.victoriametrics.com/#monitoring) with `reason="wrong_auth_key"` and `reason="wrong_basic_auth"`. See [this issue](https://github.com/victoriaMetrics/victoriaMetrics/issues/4590). Thanks to @venkatbvc for the [pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/5166). * FEATURE: [vmauth](https://docs.victoriametrics.com/vmauth.html): add `tls_insecure_skip_verify` parameter which allows to disable TLS verification for backend connection. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5240). * FEATURE: `vmstorage`: add `-blockcache.missesBeforeCaching` command-line flag, which can be used for fine-tuning RAM usage for `indexdb/dataBlocks` cache when queries touching big number of time series are executed. +* FEATURE: add `-loggerMaxArgLen` command-line flag for fine-tuning the maximum lengths of logged args. * BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert.html): strip sensitive information such as auth headers or passwords from datasource, remote-read, remote-write or notifier URLs in log messages or UI. This behavior is by default and is controlled via `-datasource.showURL`, `-remoteRead.showURL`, `remoteWrite.showURL` or `-notifier.showURL` cmd-line flags. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5044). * BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert.html): fix vmalert web UI when running on 32-bit architectures machine. diff --git a/docs/README.md b/docs/README.md index 3432fda58d..1f57c0436c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2658,6 +2658,8 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li Allows renaming fields in JSON formatted logs. Example: "ts:timestamp,msg:message" renames "ts" to "timestamp" and "msg" to "message". Supported fields: ts, level, caller, msg -loggerLevel string Minimum level of errors to log. Possible values: INFO, WARN, ERROR, FATAL, PANIC (default "INFO") + -loggerMaxArgLen int + The maximum length of a single logged argument. Longer arguments are replaced with 'arg_start..arg_end', where 'arg_start' and 'arg_end' is prefix and suffix of the arg with the length not exceeding -loggerMaxArgLen / 2 (default 500) -loggerOutput string Output for the logs. Supported values: stderr, stdout (default "stderr") -loggerTimezone string diff --git a/docs/Single-server-VictoriaMetrics.md b/docs/Single-server-VictoriaMetrics.md index 9e16d636b3..5e63299fec 100644 --- a/docs/Single-server-VictoriaMetrics.md +++ b/docs/Single-server-VictoriaMetrics.md @@ -2666,6 +2666,8 @@ Pass `-help` to VictoriaMetrics in order to see the list of supported command-li Allows renaming fields in JSON formatted logs. Example: "ts:timestamp,msg:message" renames "ts" to "timestamp" and "msg" to "message". Supported fields: ts, level, caller, msg -loggerLevel string Minimum level of errors to log. Possible values: INFO, WARN, ERROR, FATAL, PANIC (default "INFO") + -loggerMaxArgLen int + The maximum length of a single logged argument. Longer arguments are replaced with 'arg_start..arg_end', where 'arg_start' and 'arg_end' is prefix and suffix of the arg with the length not exceeding -loggerMaxArgLen / 2 (default 500) -loggerOutput string Output for the logs. Supported values: stderr, stdout (default "stderr") -loggerTimezone string diff --git a/lib/bytesutil/bytesutil.go b/lib/bytesutil/bytesutil.go index 8d9d1c5607..daa01232d5 100644 --- a/lib/bytesutil/bytesutil.go +++ b/lib/bytesutil/bytesutil.go @@ -79,14 +79,3 @@ func ToUnsafeBytes(s string) (b []byte) { slh.Cap = sh.Len return b } - -// LimitStringLen limits the length of s to maxLen. -// -// If len(s) > maxLen, then the function concatenates s prefix with s suffix. -func LimitStringLen(s string, maxLen int) string { - if maxLen <= 4 || len(s) <= maxLen { - return s - } - n := maxLen/2 - 1 - return s[:n] + ".." + s[len(s)-n:] -} diff --git a/lib/logger/logger.go b/lib/logger/logger.go index e5d93660dd..1575e25c37 100644 --- a/lib/logger/logger.go +++ b/lib/logger/logger.go @@ -13,6 +13,7 @@ import ( "time" "github.com/VictoriaMetrics/VictoriaMetrics/lib/buildinfo" + "github.com/VictoriaMetrics/VictoriaMetrics/lib/stringsutil" "github.com/VictoriaMetrics/metrics" ) @@ -23,6 +24,8 @@ var ( loggerTimezone = flag.String("loggerTimezone", "UTC", "Timezone to use for timestamps in logs. Timezone must be a valid IANA Time Zone. "+ "For example: America/New_York, Europe/Berlin, Etc/GMT+3 or Local") disableTimestamps = flag.Bool("loggerDisableTimestamps", false, "Whether to disable writing timestamps in logs") + maxLogArgLen = flag.Int("loggerMaxArgLen", 500, "The maximum length of a single logged argument. Longer arguments are replaced with 'arg_start..arg_end', "+ + "where 'arg_start' and 'arg_end' is prefix and suffix of the arg with the length not exceeding -loggerMaxArgLen / 2") errorsPerSecondLimit = flag.Int("loggerErrorsPerSecondLimit", 0, `Per-second limit on the number of ERROR messages. If more than the given number of errors are emitted per second, the remaining errors are suppressed. Zero values disable the rate limit`) warnsPerSecondLimit = flag.Int("loggerWarnsPerSecondLimit", 0, `Per-second limit on the number of WARN messages. If more than the given number of warns are emitted per second, then the remaining warns are suppressed. Zero values disable the rate limit`) @@ -134,7 +137,7 @@ func logLevelSkipframes(skipframes int, level, format string, args []interface{} if shouldSkipLog(level) { return } - msg := formatLogMessage(500, format, args) + msg := formatLogMessage(*maxLogArgLen, format, args) logMessage(level, msg, 3+skipframes) } @@ -149,23 +152,12 @@ func formatLogMessage(maxArgLen int, format string, args []interface{}) string { x = x[n+1:] if strings.HasPrefix(x, "s") || strings.HasPrefix(x, "q") { s := fmt.Sprintf("%s", args[i]) - args[i] = limitStringLength(maxArgLen, s) + args[i] = stringsutil.LimitStringLen(s, maxArgLen) } } return fmt.Sprintf(format, args...) } -func limitStringLength(maxLen int, s string) string { - if len(s) <= maxLen { - return s - } - n := (maxLen / 2) - 1 - if n < 0 { - n = 0 - } - return s[:n] + ".." + s[len(s)-n:] -} - func logLimiterCleaner() { for { time.Sleep(time.Second) diff --git a/lib/storage/search.go b/lib/storage/search.go index 33f4e8851f..437dc43eb5 100644 --- a/lib/storage/search.go +++ b/lib/storage/search.go @@ -10,6 +10,7 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/lib/fasttime" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/querytracer" + "github.com/VictoriaMetrics/VictoriaMetrics/lib/stringsutil" ) // BlockRef references a Block. @@ -320,7 +321,7 @@ type TagFilter struct { // String returns string representation of tf. func (tf *TagFilter) String() string { op := tf.getOp() - value := bytesutil.LimitStringLen(string(tf.Value), 60) + value := stringsutil.LimitStringLen(string(tf.Value), 60) if len(tf.Key) == 0 { return fmt.Sprintf("__name__%s%q", op, value) } diff --git a/lib/storage/tag_filters.go b/lib/storage/tag_filters.go index c2e4934771..00b4249cde 100644 --- a/lib/storage/tag_filters.go +++ b/lib/storage/tag_filters.go @@ -17,6 +17,7 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/lib/lrucache" "github.com/VictoriaMetrics/VictoriaMetrics/lib/memory" "github.com/VictoriaMetrics/VictoriaMetrics/lib/regexutil" + "github.com/VictoriaMetrics/VictoriaMetrics/lib/stringsutil" ) // convertToCompositeTagFilterss converts tfss to composite filters. @@ -301,7 +302,7 @@ func (tf *tagFilter) Less(other *tagFilter) bool { // String returns human-readable tf value. func (tf *tagFilter) String() string { op := tf.getOp() - value := bytesutil.LimitStringLen(string(tf.value), 60) + value := stringsutil.LimitStringLen(string(tf.value), 60) if bytes.Equal(tf.key, graphiteReverseTagKey) { return fmt.Sprintf("__graphite_reverse__%s%q", op, value) } diff --git a/lib/stringsutil/stringsutil.go b/lib/stringsutil/stringsutil.go new file mode 100644 index 0000000000..cd5754cfd1 --- /dev/null +++ b/lib/stringsutil/stringsutil.go @@ -0,0 +1,16 @@ +package stringsutil + +// LimitStringLen limits the length of s with maxLen. +// +// If len(s) > maxLen, then s is replaced with "s_prefix..s_suffix", +// so the total length of the returned string doesn't exceed maxLen. +func LimitStringLen(s string, maxLen int) string { + if len(s) <= maxLen || maxLen <= 4 { + return s + } + n := (maxLen / 2) - 1 + if n < 0 { + n = 0 + } + return s[:n] + ".." + s[len(s)-n:] +}