mirror of
https://github.com/prometheus/prometheus.git
synced 2025-02-21 03:16:00 -08:00
Improves upon #15434, better resolves #15433. This commit introduces a few changes to ensure safer handling of the JSONFileLogger: - the JSONFileLogger struct now implements the slog.Handler interface, so it can directly be used to create slog Loggers. This pattern more closely aligns with upstream slog usage (which is generally based around handlers), as well as making it clear that devs are creating a whole new logger when interacting with it (vs silently modifying internal configs like it did previously). - updates the `promql.QueryLogger` interface to be a union of the methods of both the `io.Closer` interface and the `slog.Handler` interface. This allows for plugging in/using slog-compatible loggers other than the JSONFileLogger, if desired (ie, for downstream projects). - introduces new `scrape.FailureLogger` interface; just like `promql.QueryLogger`, it is a union of `io.Closer` and `slog.Handler` interfaces. Similar logic applies to reasoning. - updates tests where needed; have the `FakeQueryLogger` from promql's engine_test implement the `slog.Handler`, improve JSONFileLogger test suite, etc. Signed-off-by: TJ Hoplock <t.hoplock@gmail.com>
104 lines
2.9 KiB
Go
104 lines
2.9 KiB
Go
// Copyright 2020 The Prometheus Authors
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package logging
|
|
|
|
import (
|
|
"log/slog"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/grafana/regexp"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func getLogLines(t *testing.T, name string) []string {
|
|
content, err := os.ReadFile(name)
|
|
require.NoError(t, err)
|
|
|
|
lines := strings.Split(string(content), "\n")
|
|
for i := len(lines) - 1; i >= 0; i-- {
|
|
if lines[i] == "" {
|
|
lines = append(lines[:i], lines[i+1:]...)
|
|
}
|
|
}
|
|
return lines
|
|
}
|
|
|
|
func TestJSONFileLogger_basic(t *testing.T) {
|
|
f, err := os.CreateTemp("", "logging")
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
require.NoError(t, f.Close())
|
|
require.NoError(t, os.Remove(f.Name()))
|
|
}()
|
|
|
|
logHandler, err := NewJSONFileLogger(f.Name())
|
|
require.NoError(t, err)
|
|
require.NotNil(t, logHandler, "logger handler can't be nil")
|
|
|
|
logger := slog.New(logHandler)
|
|
logger.Info("test", "hello", "world")
|
|
|
|
r := getLogLines(t, f.Name())
|
|
require.Len(t, r, 1, "expected 1 log line")
|
|
result, err := regexp.Match(`^{"time":"[^"]+","level":"INFO","source":"\w+.go:\d+","msg":"test","hello":"world"}`, []byte(r[0]))
|
|
require.NoError(t, err)
|
|
require.True(t, result, "unexpected content: %s", r)
|
|
|
|
err = logHandler.Close()
|
|
require.NoError(t, err)
|
|
|
|
err = logHandler.file.Close()
|
|
require.Error(t, err)
|
|
require.True(t, strings.HasSuffix(err.Error(), os.ErrClosed.Error()), "file not closed")
|
|
}
|
|
|
|
func TestJSONFileLogger_parallel(t *testing.T) {
|
|
f, err := os.CreateTemp("", "logging")
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
require.NoError(t, f.Close())
|
|
require.NoError(t, os.Remove(f.Name()))
|
|
}()
|
|
|
|
logHandler, err := NewJSONFileLogger(f.Name())
|
|
require.NoError(t, err)
|
|
require.NotNil(t, logHandler, "logger handler can't be nil")
|
|
|
|
logger := slog.New(logHandler)
|
|
logger.Info("test", "hello", "world")
|
|
|
|
logHandler2, err := NewJSONFileLogger(f.Name())
|
|
require.NoError(t, err)
|
|
require.NotNil(t, logHandler2, "logger handler can't be nil")
|
|
|
|
logger2 := slog.New(logHandler2)
|
|
logger2.Info("test", "hello", "world")
|
|
|
|
err = logHandler.Close()
|
|
require.NoError(t, err)
|
|
|
|
err = logHandler.file.Close()
|
|
require.Error(t, err)
|
|
require.True(t, strings.HasSuffix(err.Error(), os.ErrClosed.Error()), "file not closed")
|
|
|
|
err = logHandler2.Close()
|
|
require.NoError(t, err)
|
|
|
|
err = logHandler2.file.Close()
|
|
require.Error(t, err)
|
|
require.True(t, strings.HasSuffix(err.Error(), os.ErrClosed.Error()), "file not closed")
|
|
}
|