mirror of
https://github.com/openziti/ziti.git
synced 2026-09-10 00:35:41 +00:00
0aefe599c9
- adds BuildPrettyHandler and BuildHandlerForFormat in common/logging: pretty output wraps the hand-rolled logging.PrettyHandler (a direct port of pfxlog's; df/dl was dropped after review found level-label gaps, so there is no github.com/michaelquigley/df dependency) in the AsyncHandler chain; the format-aware builder picks pretty / json / text by --log-formatter so default look matches pre-slog - adds BuildTextHandler so --log-formatter=text emits logrus-TextFormatter- style key=value output (level=info msg=...) via a slog TextHandler rather than the colored pretty handler, restoring the pre-slog meaning of text - adds logging.Fatal: a slog-world fatal (slog provides none) that emits at LevelFatal durably via SyncEmit, then exits, so hard-exit paths do not lose the record to the async queue; converts the controller and router startup hard-exit sites from Error+os.Exit / Error+panic to it, dropping the router's startup panic - rewires agentlog.DefaultLogLevelCallbacks onto common/logging: SetLogLevel drives logging.SetGlobalLevel (lockstep slog + logrus), SetChannelLogLevel and ClearChannelLogLevel drive SetNamedLevel / ClearNamedLevel; per-channel overrides become slog-only per design - adds agentToSlog mapping across the seven canonical levels with an Info fallback for forward-compat - ziti/run Options.PreRun and ziti/tunnel rootPreRun build the slog handler chain via logging.BuildHandlerForFormat and call Install; --verbose seeds the initial level instead of mutating logrus directly; AsyncOptions flags exposed via logging.AddFlags on each persistent flag set - hardens the run command's logging flags: PreRun reads --verbose / --log-formatter across the command chain so they are honored at either the alias-parent (ziti controller run) or child position, and the ziti controller / ziti router alias parents skip their legacy pfxlog/logrus PersistentPreRun setup for the run subcommand (which installs the slog chain itself), keeping it for sibling subcommands - adds Phase 7 acceptance tests in common/agentlog: TestInstallInvariant covers Out=io.Discard, noop formatter, ReportCaller, and the lockstep level mirror after Install; TestEndToEnd_AgentSetLogLevel walks the agent set-log-level path end to end across bridged-logrus and direct-slog routes; TestPerChannelOverride_AppliesToSlogOnly_NotPfxlog confirms the design's slog-only channel semantics - adds Fatal/Panic durability subprocess tests in common/logging that fork the test binary, Install the production handler chain, then call logrus.Fatal / logrus.Panic and assert the records reach stderr before exit/panic; proves the bridge's SyncEmit path flushes before os.Exit - adds doc/logging.md developer note covering how to write a slog line, channel-naming convention, the no-Warn/Error-in-hot-paths rule, the operator surface, the migration checklist, AsyncOptions tunables, and what's deliberately deferred - adds doc/design/slog-conversion-plan.md with the code-grounded per-package channel inventory, the sdk-golang embedder-injection pattern, conversion order with deep analysis for the first four chunks, and cross-repo coordination notes
125 lines
4.6 KiB
Go
125 lines
4.6 KiB
Go
/*
|
|
Copyright NetFoundry Inc.
|
|
|
|
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
|
|
|
|
https://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 agentlog
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"testing"
|
|
|
|
"github.com/openziti/ziti/v2/common/agent"
|
|
"github.com/openziti/ziti/v2/common/logging"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestAgentToSlogMapping covers the seven canonical levels by name so a
|
|
// future renumbering of either enum is caught here, not silently downstream.
|
|
func TestAgentToSlogMapping(t *testing.T) {
|
|
cases := []struct {
|
|
agentLvl agent.LogLevel
|
|
slogLvl slog.Level
|
|
}{
|
|
{agent.PanicLevel, logging.LevelPanic},
|
|
{agent.FatalLevel, logging.LevelFatal},
|
|
{agent.ErrorLevel, slog.LevelError},
|
|
{agent.WarnLevel, slog.LevelWarn},
|
|
{agent.InfoLevel, slog.LevelInfo},
|
|
{agent.DebugLevel, slog.LevelDebug},
|
|
{agent.TraceLevel, logging.LevelTrace},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.agentLvl.String(), func(t *testing.T) {
|
|
require.Equal(t, c.slogLvl, agentToSlog(c.agentLvl))
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestAgentToSlogUnknownFallsBackToInfo proves an out-of-range LogLevel does
|
|
// not silence logging; it falls back to Info so log output is preserved.
|
|
func TestAgentToSlogUnknownFallsBackToInfo(t *testing.T) {
|
|
require.Equal(t, slog.LevelInfo, agentToSlog(agent.LogLevel(99)))
|
|
}
|
|
|
|
// TestDefaultCallbacks_SetLogLevel proves SetLogLevel drives the slog global
|
|
// AND logrus.SetLevel via the package-level lockstep helper. This is the path
|
|
// `ziti agent set-log-level info` takes.
|
|
func TestDefaultCallbacks_SetLogLevel(t *testing.T) {
|
|
prevLogrus := logrus.StandardLogger().Level
|
|
t.Cleanup(func() { logrus.StandardLogger().SetLevel(prevLogrus) })
|
|
|
|
configureForTest(t)
|
|
cbs := DefaultLogLevelCallbacks()
|
|
|
|
cbs.SetLogLevel(agent.DebugLevel)
|
|
require.Equal(t, slog.LevelDebug, logging.GlobalLevel())
|
|
require.Equal(t, logrus.DebugLevel, logrus.StandardLogger().Level)
|
|
|
|
cbs.SetLogLevel(agent.WarnLevel)
|
|
require.Equal(t, slog.LevelWarn, logging.GlobalLevel())
|
|
require.Equal(t, logrus.WarnLevel, logrus.StandardLogger().Level)
|
|
}
|
|
|
|
// TestDefaultCallbacks_SetChannelLogLevel proves the channel callback drives
|
|
// the named-logger override; the slog Logger returned by logging.For honors
|
|
// the override on its next Enabled check.
|
|
func TestDefaultCallbacks_SetChannelLogLevel(t *testing.T) {
|
|
configureForTest(t)
|
|
cbs := DefaultLogLevelCallbacks()
|
|
|
|
// Global Warn; channel "router.link" overridden to Debug.
|
|
cbs.SetLogLevel(agent.WarnLevel)
|
|
cbs.SetChannelLogLevel("router.link", agent.DebugLevel)
|
|
|
|
logger := logging.For("router.link")
|
|
require.True(t, logger.Enabled(context.Background(), slog.LevelDebug), "override must lift the channel above the global level")
|
|
|
|
// Another channel without an override stays at global Warn.
|
|
other := logging.For("router.xgress")
|
|
require.False(t, other.Enabled(context.Background(), slog.LevelDebug), "non-overridden channels must follow the global level")
|
|
}
|
|
|
|
// TestDefaultCallbacks_ClearChannelLogLevel proves Clear restores the channel
|
|
// to the global level live; the channel logger's next Enabled check uses the
|
|
// global, even if it was below the previously-overridden level.
|
|
func TestDefaultCallbacks_ClearChannelLogLevel(t *testing.T) {
|
|
configureForTest(t)
|
|
cbs := DefaultLogLevelCallbacks()
|
|
|
|
cbs.SetLogLevel(agent.WarnLevel)
|
|
cbs.SetChannelLogLevel("router.link", agent.DebugLevel)
|
|
cbs.ClearChannelLogLevel("router.link")
|
|
|
|
logger := logging.For("router.link")
|
|
require.False(t, logger.Enabled(context.Background(), slog.LevelDebug), "Clear must drop the channel back to the global level")
|
|
}
|
|
|
|
// configureForTest wires a no-op default Registry so the package-level
|
|
// logging functions don't panic. The Registry's root is a discard handler
|
|
// because tests here only assert level state, not record dispatch.
|
|
func configureForTest(t *testing.T) {
|
|
t.Helper()
|
|
logging.Configure(discardHandler{})
|
|
}
|
|
|
|
type discardHandler struct{}
|
|
|
|
func (discardHandler) Enabled(context.Context, slog.Level) bool { return true }
|
|
func (discardHandler) Handle(context.Context, slog.Record) error { return nil }
|
|
func (h discardHandler) WithAttrs([]slog.Attr) slog.Handler { return h }
|
|
func (h discardHandler) WithGroup(string) slog.Handler { return h }
|