Documentation
¶
Overview ¶
Package logx is the Aisphere Kernel logging package.
logx is the ONLY logger that business code (handler/service/repository/worker) should use. Direct usage of log.Printf, fmt.Println, log/slog, or go.uber.org/zap in business code is forbidden and will fail CI.
Design principle ¶
logx keeps log/slog as the internal engine (so Kernel is stdlib-only), but exposes a Kernel-facing API that does NOT leak slog.Logger or slog.Attr to business packages. Other Kernel modules (errorx, httpx, grpcx, auditx, metricsx) consume logx through the stable Logger interface + Field type.
logx does NOT call os.Exit, does NOT write to network, does NOT do audit-grade recording. It only emits structured logs; other modules consume.
30-second quickstart ¶
cfg := logx.DefaultConfig("dev")
cfg.ServiceName = "aihub"
logger, levelCtl, err := logx.New(cfg)
if err != nil { panic(err) }
defer logger.Sync()
logger.Info("service started",
logx.String("addr", ":8000"),
logx.String("version", "v0.1.0"),
)
_ = levelCtl.SetLevel("debug") // dynamically lower to debug
In a handler with request-scoped context:
ctx = logx.Inject(ctx, logger,
logx.String("request_id", reqID),
logx.String("trace_id", traceID),
logx.String("subject_id", userID),
)
logx.FromContext(ctx).Info("request accepted")
Logger API ¶
Bootstrap:
logx.New(cfg) → (Logger, LevelController, error) logx.DefaultConfig(env) → Config with sane defaults logx.Noop() → discard all logs (tests, disabled features) logx.FromContext(ctx) → request-scoped logger (Noop if none) logx.Inject(ctx, logger, fields...) → attach logger + fields to ctx logx.Sync(logger) → flush buffers before exit
Logger interface methods:
type Logger interface {
Debug(msg string, fields ...Field)
Info(msg string, fields ...Field)
Warn(msg string, fields ...Field)
Error(msg string, fields ...Field)
With(fields ...Field) Logger // add persistent fields
Named(name string) Logger // add module tag
WithContext(ctx context.Context) Logger
Enabled(level LogLevel) bool
Sync() error
}
Field constructors ¶
All structured fields use these constructors — never slog.Any directly:
logx.String(k, v) logx.Int(k, v) logx.Int64(k, v) logx.Uint64(k, v) logx.Bool(k, v) logx.Float64(k, v) logx.Duration(k, v) logx.Time(k, v) logx.Any(k, v) logx.Event(name) logx.Err(err) logx.Group(k, fields...)
logx.Err(err) is special: it auto-extracts error_code, error_reason, http_status, grpc_code, retryable from any error implementing those methods (works with errorx without importing it — no cycle).
Pre-built log helpers ¶
For standardized log shapes, use these instead of building fields manually:
logx.LogAccess(logger, e logx.AccessEvent) // HTTP access log logx.LogExternalCall(logger, c logx.ExternalCall) // upstream API call logx.LogError(logger, msg, e logx.ErrorLog) // standardized error log logx.LogAuditHint(logger, h logx.AuditHint) // audit breadcrumb
HTTP / RPC middleware ¶
logx.HTTPAccessLog(base, cfg, opts...) → http middleware logx.Recovery(base, opts...) → http panic recovery middleware logx.ServerLogging(base, extract) → RPC server logging middleware logx.ClientLogging(base, extract) → RPC client logging middleware logx.RPCRecovery(base, handler) → RPC panic recovery middleware logx.LevelHTTPHandler(controller) → runtime level control HTTP handler
Redaction ¶
logx automatically redacts sensitive field keys (password, token, secret, authorization, cookie, credential, private_key, api_key, etc.). Customize via Config.Redact. NEVER log credentials directly — redaction only works through logx.
Sampling ¶
For high-QPS logs, enable sampling via Config.Sampling. Only logs at or below MinLevel are sampled; warn and error are never sampled.
Test logger ¶
In tests, use logx.NewTestLogger to capture log entries and assert on them:
logger := logx.NewTestLogger(t)
svc := NewService(logger)
svc.Create(ctx, req)
logger.AssertLogged(t, "skill created", logx.String("skill_id", "skill_001"))
Forbidden in business code ¶
Handler / service / repository / worker code MUST NOT use:
log.Printf("...")
fmt.Println("...")
fmt.Printf("...")
slog.Info("...")
slog.Default().Info("...")
zap.L().Info("...")
logrus.Info("...")
Use logx.FromContext(ctx) or an injected logx.Logger instead.
Further reading ¶
See logx/README.md for the single-source-of-truth user guide, and docs/ai/logx.md for the AI coding recipe.
Example (BusinessAuditHint) ¶
ExampleBusiness_auditHint shows how to leave an audit breadcrumb for sensitive operations. NOTE: this is a log breadcrumb only; compliance-grade audit records go through auditx (when it exists).
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
logx.LogAuditHint(logger, logx.AuditHint{
Action: "aihub.skill.delete",
ActorID: "user_123",
ResourceType: "skill",
ResourceID: "skill_001",
Result: "success",
})
entries := logger.Entries()
fmt.Println(entries[0].Message)
}
Output: audit hint
Example (BusinessErrorLog) ¶
ExampleBusiness_errorLog shows how logx.Err auto-extracts structured fields from any error implementing Code/HTTPStatus/Retryable (works with errorx without importing it).
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
// Simulate an errorx-style error (in real code, import errorx).
err := &fakeError{
msg: "skill not found",
code: "AIHUB_SKILL_NOT_FOUND",
status: 404,
retry: false,
}
logger.Error("create skill failed",
logx.String("operation", "aihub.skill.create"),
logx.Err(err),
)
entries := logger.Entries()
// First field is operation; verify shape.
fmt.Println(entries[0].Message)
}
// fakeError simulates an errorx-style error without importing errorx.
type fakeError struct {
msg string
code string
status int
retry bool
}
func (e *fakeError) Error() string { return e.msg }
func (e *fakeError) Code() string { return e.code }
func (e *fakeError) HTTPStatus() int { return e.status }
func (e *fakeError) Retryable() bool { return e.retry }
Output: create skill failed
Example (BusinessHTTPAccess) ¶
ExampleBusiness_httpAccess shows the standard access log shape produced by HTTPAccessLog middleware.
package main
import (
"fmt"
"time"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
logx.LogAccess(logger, logx.AccessEvent{
Side: "server",
Protocol: "http",
Operation: "POST /v1/skills",
Method: "POST",
Path: "/v1/skills",
StatusCode: 201,
Latency: 42 * time.Millisecond,
})
entries := logger.Entries()
fmt.Println(entries[0].Message)
}
Output: POST /v1/skills completed
Example (BusinessRepositoryLog) ¶
ExampleBusiness_repositoryLog shows the standard pattern for logging database queries in repository code — use FromContext to get the request-scoped logger with request_id / trace_id / subject_id already attached.
package main
import (
"context"
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
ctx := logx.Inject(context.Background(), logger,
logx.String("request_id", "req_abc"),
)
repo := &fakeSkillRepo{logger: logger}
_, _ = repo.Find(ctx, "skill_001")
entries := logger.Entries()
fmt.Println(entries[0].Message)
}
type fakeSkillRepo struct {
logger logx.Logger
}
func (r *fakeSkillRepo) Find(ctx context.Context, id string) (*struct{}, error) {
logger := r.logger
if l := logx.FromContext(ctx); l != logx.Noop() {
logger = l
}
logger.Debug("querying skill",
logx.String("skill_id", id),
logx.String("table", "aihub_skills"),
)
return &struct{}{}, nil
}
Output: querying skill
Example (BusinessRequestScoped) ¶
ExampleBusiness_requestScoped shows the full handler pattern: inject request_id / trace_id / subject_id once at the handler boundary, then every downstream log automatically includes them.
package main
import (
"context"
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
ctx := context.Background()
// Handler boundary: inject request-scoped fields.
ctx = logx.Inject(ctx, logger,
logx.String("request_id", "req_abc"),
logx.String("trace_id", "trace_xyz"),
logx.String("subject_id", "u_123"),
)
// Downstream code just calls FromContext — fields are auto-attached.
logx.FromContext(ctx).Info("request accepted")
// Even deep in the repo layer:
repo := &fakeSkillRepo{logger: logger}
_, _ = repo.Find(ctx, "skill_001")
entries := logger.Entries()
fmt.Println(len(entries) >= 2)
}
type fakeSkillRepo struct {
logger logx.Logger
}
func (r *fakeSkillRepo) Find(ctx context.Context, id string) (*struct{}, error) {
logger := r.logger
if l := logx.FromContext(ctx); l != logx.Noop() {
logger = l
}
logger.Debug("querying skill",
logx.String("skill_id", id),
logx.String("table", "aihub_skills"),
)
return &struct{}{}, nil
}
Output: true
Example (BusinessSampling) ¶
ExampleBusiness_sampling shows how to enable sampling for high-QPS logs so log pipelines aren't overwhelmed.
package main
import (
"errors"
"fmt"
"io"
"time"
"github.com/aisphereio/kernel/logx"
)
func main() {
cfg := logx.DefaultConfig("prod")
cfg.Sampling = logx.SamplingConfig{
Enabled: true,
Every: 100, // keep 1 of every 100 after First
First: 10, // always keep first 10 per level+message
Window: time.Second, // reset counters every second
MinLevel: logx.DebugLevel.String(), // sample debug/info only; warn+ always kept
}
logger, _, _ := logx.New(cfg, logx.WithWriter(io.Discard))
// High-QPS debug logs get sampled; errors always go through.
for i := 0; i < 1000; i++ {
logger.Debug("ping", logx.Int("seq", i))
}
logger.Error("critical", logx.Err(errors.New("boom")))
fmt.Println("ok")
}
Output: ok
Example (BusinessServiceLog) ¶
ExampleBusiness_serviceLog shows service-layer logging with operation and resource fields for searchability.
package main
import (
"context"
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
svc := &fakeSkillService{logger: logger}
_ = svc.Create(context.Background(), "demo")
entries := logger.Entries()
fmt.Println(entries[0].Message)
}
type fakeSkillService struct {
logger logx.Logger
}
func (s *fakeSkillService) Create(ctx context.Context, name string) error {
logger := s.logger
if l := logx.FromContext(ctx); l != logx.Noop() {
logger = l
}
logger.Info("skill created",
logx.Event("skill_created"),
logx.String("skill_id", name),
logx.String("operation", "aihub.skill.create"),
)
return nil
}
Output: skill created
Example (BusinessTestLogger) ¶
ExampleBusiness_testLogger shows the standard test pattern: capture log entries and assert specific fields were logged.
package main
import (
"context"
"fmt"
"testing"
"github.com/aisphereio/kernel/logx"
)
func main() {
t := &testing.T{}
logger := logx.NewTestLogger(t)
svc := &fakeSkillService{logger: logger}
_ = svc.Create(context.Background(), "demo")
// Assert the expected log was emitted with the right fields.
logger.AssertLogged(t, "skill created",
logx.String("skill_id", "demo"),
)
fmt.Println("ok")
}
type fakeSkillService struct {
logger logx.Logger
}
func (s *fakeSkillService) Create(ctx context.Context, name string) error {
logger := s.logger
if l := logx.FromContext(ctx); l != logx.Noop() {
logger = l
}
logger.Info("skill created",
logx.Event("skill_created"),
logx.String("skill_id", name),
logx.String("operation", "aihub.skill.create"),
)
return nil
}
Output: ok
Example (BusinessUpstreamCall) ¶
ExampleBusiness_upstreamCall shows how to log calls to upstream services (LLM APIs, third-party HTTP) using LogExternalCall.
package main
import (
"fmt"
"time"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
callUpstreamLLM(logger, "gpt-4", 200, 850*time.Millisecond)
entries := logger.Entries()
fmt.Println(entries[0].Fields[0].Key) // first field is event=external_call... actually "event"
}
func callUpstreamLLM(logger logx.Logger, model string, status int, latency time.Duration) {
logx.LogExternalCall(logger, logx.ExternalCall{
Provider: "openai",
Service: "chat-completions",
Operation: "create",
Model: model,
Endpoint: "https://api.openai.com/v1/chat/completions",
StatusCode: status,
Latency: latency,
})
}
Output: event
Example (BusinessWorkerLog) ¶
ExampleBusiness_workerLog shows a background worker logging progress with auto-redaction of sensitive fields.
package main
import (
"fmt"
"io"
"github.com/aisphereio/kernel/logx"
)
func main() {
// Build a logger with redaction enabled.
cfg := logx.DefaultConfig("test")
cfg.Redact = logx.RedactConfig{Enabled: true, Keys: logx.DefaultRedactKeys(), Value: "***"}
logger, _, _ := logx.New(cfg, logx.WithWriter(io.Discard))
// Even if a worker accidentally passes a credential, it's redacted.
logger.Info("worker processing",
logx.String("task_id", "task_001"),
logx.String("api_key", "sk_live_abc123"), // redacted to ***
)
fmt.Println("ok")
}
Output: ok
Index ¶
- Constants
- func AttrsFromContext(ctx context.Context) []slog.Attr
- func ContextWithAttrs(ctx context.Context, attrs ...slog.Attr) context.Context
- func ContextWithFields(ctx context.Context, fields ...Field) context.Context
- func Debug(msg string, args ...any)
- func DebugContext(ctx context.Context, msg string, args ...any)
- func Default() *slog.Logger
- func DefaultRedactKeys() []string
- func Enabled(ctx context.Context, level Level) bool
- func Error(msg string, args ...any)
- func ErrorContext(ctx context.Context, msg string, args ...any)
- func HTTPAccessLog(base Logger, cfg AccessLogConfig, opts ...HTTPAccessOption) func(http.Handler) http.Handler
- func Handler() slog.Handler
- func Info(msg string, args ...any)
- func InfoContext(ctx context.Context, msg string, args ...any)
- func Inject(ctx context.Context, logger Logger, fields ...Field) context.Context
- func LevelHTTPHandler(controller LevelController) http.Handler
- func Log(ctx context.Context, level Level, msg string, args ...any)
- func LogAccess(logger Logger, e AccessEvent)
- func LogAttrs(ctx context.Context, level Level, msg string, attrs ...slog.Attr)
- func LogAuditHint(logger Logger, hint AuditHint)
- func LogError(logger Logger, msg string, e ErrorLog)
- func LogExternalCall(logger Logger, call ExternalCall)
- func New(cfg Config, opts ...Option) (Logger, LevelController, error)
- func NewHandler(opts ...Option) slog.Handler
- func NewLogger(handler slog.Handler, opts ...Option) *slog.Logger
- func NewSlog(cfg Config, opts ...Option) (Logger, LevelController, error)
- func Recovery(base Logger, opts ...RecoveryOption) func(http.Handler) http.Handler
- func SetDefault(logger *slog.Logger)
- func Slog(logger Logger) (*slog.Logger, error)
- func Sync(logger Logger) error
- func Warn(msg string, args ...any)
- func WarnContext(ctx context.Context, msg string, args ...any)
- func With(args ...any) *slog.Logger
- func WithGroup(name string) *slog.Logger
- func WithHTTPContext(ctx context.Context, logger Logger, r *http.Request, fields ...Field) context.Context
- type AccessEvent
- type AccessLogConfig
- type AuditHint
- type Config
- type DropFilter
- type Entry
- type ErrorLog
- type ExternalCall
- type Extractor
- type Field
- func Any(key string, value any) Field
- func Bool(key string, value bool) Field
- func Duration(key string, value time.Duration) Field
- func Err(err error) Field
- func Event(name string) Field
- func FieldsFromContext(ctx context.Context) []Field
- func Float64(key string, value float64) Field
- func Group(key string, fields ...Field) Field
- func Int(key string, value int) Field
- func Int64(key string, value int64) Field
- func String(key, value string) Field
- func Time(key string, value time.Time) Field
- func Uint64(key string, value uint64) Field
- type FieldExtractor
- type FilterOption
- type Format
- type HTTPAccessOption
- type Level
- type LevelController
- type LevelVar
- type Leveler
- type LogLevel
- type Logger
- type Option
- func WithAddSource(b bool) Option
- func WithDropFilter(filters ...DropFilter) Option
- func WithExtractor(extractors ...Extractor) Option
- func WithFieldExtractor(extractors ...FieldExtractor) Option
- func WithFilter(opts ...FilterOption) Option
- func WithFormat(f Format) Option
- func WithLevel(l Leveler) Option
- func WithReplaceAttr(fn func(groups []string, a slog.Attr) slog.Attr) Option
- func WithWriter(w io.Writer) Option
- type Output
- type PanicHandler
- type PrincipalResolver
- type RPCHandler
- type RPCInfo
- type RPCInfoExtractor
- type RPCMiddleware
- type RPCPanicHandler
- type RecoveryOption
- type RedactConfig
- type Redacter
- type Redactor
- type RouteResolver
- type SamplingConfig
- type TestLogger
- func (l *TestLogger) AssertLogged(t testing.TB, msg string, fields ...Field)
- func (l *TestLogger) Debug(msg string, fields ...Field)
- func (l *TestLogger) Enabled(LogLevel) bool
- func (l *TestLogger) Entries() []Entry
- func (l *TestLogger) Error(msg string, fields ...Field)
- func (l *TestLogger) Info(msg string, fields ...Field)
- func (l *TestLogger) Named(name string) Logger
- func (l *TestLogger) Sync() error
- func (l *TestLogger) Warn(msg string, fields ...Field)
- func (l *TestLogger) With(fields ...Field) Logger
- func (l *TestLogger) WithContext(context.Context) Logger
Examples ¶
- Package (BusinessAuditHint)
- Package (BusinessErrorLog)
- Package (BusinessHTTPAccess)
- Package (BusinessRepositoryLog)
- Package (BusinessRequestScoped)
- Package (BusinessSampling)
- Package (BusinessServiceLog)
- Package (BusinessTestLogger)
- Package (BusinessUpstreamCall)
- Package (BusinessWorkerLog)
- Any
- Bool
- ContextWithAttrs
- ContextWithFields
- Default
- DefaultConfig
- DefaultConfig (Dev)
- DefaultRedactKeys
- DropEvents
- DropMessages
- Duration
- Enabled
- Err
- Event
- FieldsFromContext
- FilterFunc
- FilterKey
- Float64
- Format
- FromContext
- FromContext (Nil)
- FromContextOr
- Group
- Info
- Inject
- Int
- Int64
- LevelController
- LogAccess
- LogAccess (Error)
- LogAuditHint
- LogError
- LogExternalCall
- LogLevel
- LogLevel.String
- New
- NewHandler
- NewLogger
- NewRedactor
- NewSlog
- NewTestLogger
- Noop
- ParseLevel
- ParseLogLevel
- ParseLogLevel (Invalid)
- SetDefault
- Slog
- String
- Sync
- TestLogger.AssertLogged
- TestLogger.Entries
- Time
- With
- WithAddSource
- WithDropFilter
- WithFilter
- WithFormat
- WithLevel
- WithWriter
Constants ¶
const LevelKey = slog.LevelKey
LevelKey is logger level key.
Variables ¶
This section is empty.
Functions ¶
func AttrsFromContext ¶
AttrsFromContext returns the attrs previously attached with ContextWithAttrs. The returned slice must not be mutated by callers.
func ContextWithAttrs ¶
ContextWithAttrs returns a copy of ctx with the given attrs attached. Attrs already on the context are preserved; new attrs are appended.
Use NewLogger or NewHandler so these attrs are automatically added to every record handled with that context.
Example ¶
package main
import (
"context"
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// ContextWithAttrs is the slog-level primitive (kernel internals).
ctx := context.Background()
// (use slog.Any to make attrs; omitted for brevity)
attrs := logx.AttrsFromContext(ctx)
fmt.Println(len(attrs))
}
Output: 0
func ContextWithFields ¶
Example ¶
package main
import (
"context"
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
ctx := context.Background()
ctx = logx.ContextWithFields(ctx,
logx.String("request_id", "req_123"),
logx.String("user_id", "u_123"),
)
fields := logx.FieldsFromContext(ctx)
fmt.Println(len(fields))
}
Output: 2
func Debug ¶
Debug logs at debug level. Signature mirrors slog.Logger.Debug.
func DebugContext ¶
DebugContext logs at debug level with the provided context.
func Default ¶
Default returns the default logger.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// Default returns the default slog logger.
logx.SetDefault(logx.NewLogger(logx.NewHandler()))
l := logx.Default()
if l != nil {
fmt.Println("ok")
}
}
Output: ok
func DefaultRedactKeys ¶
func DefaultRedactKeys() []string
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
keys := logx.DefaultRedactKeys()
// Default list includes password, token, secret, authorization, cookie,
// credential, private_key, api_key, ak, sk, etc.
fmt.Println(len(keys) > 5)
}
Output: true
func Enabled ¶
Enabled reports whether the default logger emits log records at the given context and level. It mirrors slog.Logger.Enabled on the default logger.
Example ¶
package main
import (
"context"
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logx.SetDefault(logx.NewLogger(logx.NewHandler(logx.WithLevel(logx.LevelInfo))))
fmt.Println(logx.Enabled(context.Background(), logx.LevelInfo))
}
Output: true
func Error ¶
Error logs at error level. Signature mirrors slog.Logger.Error.
func ErrorContext ¶
ErrorContext logs at error level with the provided context.
func HTTPAccessLog ¶
func HTTPAccessLog(base Logger, cfg AccessLogConfig, opts ...HTTPAccessOption) func(http.Handler) http.Handler
func Handler ¶
Handler returns the default logger's handler. It mirrors slog.Logger.Handler on the default logger.
func Info ¶
Info logs at info level. Signature mirrors slog.Logger.Info.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// Package-level helpers use the default logger. Kernel internals only —
// business code should use logx.FromContext(ctx) or an injected logger.
// Set up a default first:
handler := logx.NewHandler(logx.WithFormat(logx.FormatJSON))
logx.SetDefault(logx.NewLogger(handler))
logx.Info("package-level info", "key", "value")
fmt.Println("ok")
}
Output: ok
func InfoContext ¶
InfoContext logs at info level with the provided context.
func Inject ¶
Inject stores request-scoped fields and a context-bound logger in ctx. It is the single primitive adapters should call after extracting request identity, trace identity, tenant/project info, etc.
Example ¶
package main
import (
"context"
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
ctx := context.Background()
ctx = logx.Inject(ctx, logger,
logx.String("request_id", "req_abc"),
logx.String("subject_id", "u_123"),
)
// FromContext now returns a logger with those fields attached.
ctxLogger := logx.FromContext(ctx)
ctxLogger.Info("request accepted")
fmt.Println("ok")
}
Output: ok
func LevelHTTPHandler ¶
func LevelHTTPHandler(controller LevelController) http.Handler
func Log ¶
Log emits a record at the given level. It mirrors slog.Logger.Log on the default logger.
func LogAccess ¶
func LogAccess(logger Logger, e AccessEvent)
Example ¶
package main
import (
"fmt"
"time"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
logx.LogAccess(logger, logx.AccessEvent{
Side: "server",
Protocol: "http",
Operation: "POST /v1/skills",
Method: "POST",
Path: "/v1/skills",
StatusCode: 201,
Latency: 42 * time.Millisecond,
})
fmt.Println("ok")
}
Output: ok
Example (Error) ¶
package main
import (
"errors"
"fmt"
"time"
"github.com/aisphereio/kernel/logx"
)
func main() {
// Access events with status >= 500 or Err != nil auto-log at ERROR level.
logger := logx.NewTestLogger(nil)
logx.LogAccess(logger, logx.AccessEvent{
Operation: "GET /v1/skills/missing",
StatusCode: 500,
Latency: 5 * time.Millisecond,
Err: errors.New("db connection refused"),
})
fmt.Println("ok")
}
Output: ok
func LogAttrs ¶
LogAttrs emits a typed-attr record at the given level. It mirrors slog.Logger.LogAttrs on the default logger.
func LogAuditHint ¶
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
logx.LogAuditHint(logger, logx.AuditHint{
Action: "aihub.skill.delete",
ActorID: "user_123",
ResourceType: "skill",
ResourceID: "skill_001",
Result: "success",
})
fmt.Println("ok")
}
Output: ok
func LogError ¶
Example ¶
package main
import (
"errors"
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
err := errors.New("db timeout")
logx.LogError(logger, "create skill failed", logx.ErrorLog{
Operation: "aihub.skill.create",
ResourceType: "skill",
ResourceID: "skill_001",
Code: "AIHUB_SKILL_CREATE_FAILED",
Reason: "db_error",
Err: err,
})
fmt.Println("ok")
}
Output: ok
func LogExternalCall ¶
func LogExternalCall(logger Logger, call ExternalCall)
Example ¶
package main
import (
"fmt"
"time"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
logx.LogExternalCall(logger, logx.ExternalCall{
Provider: "openai",
Service: "chat-completions",
Operation: "create",
Model: "gpt-4",
Endpoint: "https://api.openai.com/v1/chat/completions",
StatusCode: 200,
Latency: 850 * time.Millisecond,
})
fmt.Println("ok")
}
Output: ok
func New ¶
func New(cfg Config, opts ...Option) (Logger, LevelController, error)
New creates the default slog-backed logx logger.
Example ¶
package main
import (
"fmt"
"io"
"github.com/aisphereio/kernel/logx"
)
func main() {
cfg := logx.DefaultConfig("dev")
cfg.ServiceName = "aihub"
logger, levelCtl, err := logx.New(cfg, logx.WithWriter(io.Discard))
if err != nil {
panic(err)
}
defer logger.Sync()
logger.Info("service started", logx.String("addr", ":8000"))
_ = levelCtl.SetLevel("debug") // dynamically lower level
fmt.Println("ok")
}
Output: ok
func NewHandler ¶
NewHandler builds a composed slog.Handler with kernel defaults:
- text encoding to stderr at LevelInfo
- context attrs from ContextWithAttrs are merged in
Additional decorators are layered as configured.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// NewHandler builds a composed slog.Handler with kernel defaults.
// Business code should use logx.New(cfg) instead.
handler := logx.NewHandler(
logx.WithFormat(logx.FormatJSON),
)
if handler != nil {
fmt.Println("ok")
}
}
Output: ok
func NewLogger ¶
NewLogger returns a slog logger backed by handler with kernel decorators applied.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// NewLogger wraps an existing slog.Handler with kernel decorators.
// Kernel internals only.
handler := logx.NewHandler()
logger := logx.NewLogger(handler)
if logger != nil {
fmt.Println("ok")
}
}
Output: ok
func NewSlog ¶
func NewSlog(cfg Config, opts ...Option) (Logger, LevelController, error)
NewSlog creates a slog-backed logx logger while exposing only the logx.Logger interface to business code.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// NewSlog is the slog-backed implementation. New is an alias.
cfg := logx.DefaultConfig("test")
cfg.Output = "stderr"
logger, _, err := logx.NewSlog(cfg)
if err != nil {
panic(err)
}
logger.Info("ok")
fmt.Println("started")
}
Output: started
func SetDefault ¶
SetDefault sets the default logger used by the package-level helpers and by slog.Default.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
handler := logx.NewHandler()
logx.SetDefault(logx.NewLogger(handler))
fmt.Println("ok")
}
Output: ok
func Slog ¶
Slog returns the underlying slog logger only for framework adapters. Business packages should not call this helper.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// Slog unwraps a logx.Logger to *slog.Logger. ADAPTERS ONLY — business
// code should never need this.
cfg := logx.DefaultConfig("test")
logger, _, _ := logx.New(cfg)
if sl, err := logx.Slog(logger); err == nil && sl != nil {
fmt.Println("unwrapped")
}
}
Output: unwrapped
func Sync ¶
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
cfg := logx.DefaultConfig("test")
logger, _, _ := logx.New(cfg)
// Sync flushes buffers before exit.
_ = logx.Sync(logger)
fmt.Println("ok")
}
Output: ok
func Warn ¶
Warn logs at warn level. Signature mirrors slog.Logger.Warn.
func WarnContext ¶
WarnContext logs at warn level with the provided context.
func With ¶
With returns a logger that includes the given attributes in each output operation. It mirrors slog.Logger.With on the default logger.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// With returns a logger with persistent attrs (slog-level, kernel internals).
logx.SetDefault(logx.NewLogger(logx.NewHandler()))
l := logx.With("service", "aihub")
if l != nil {
fmt.Println("ok")
}
}
Output: ok
func WithGroup ¶
WithGroup returns a logger that starts a group. It mirrors slog.Logger.WithGroup on the default logger.
Types ¶
type AccessEvent ¶
type AccessLogConfig ¶
type AccessLogConfig struct {
Enabled bool `json:"enabled" yaml:"enabled"`
SkipPaths []string `json:"skip_paths" yaml:"skip_paths"`
SlowThreshold time.Duration `json:"slow_threshold" yaml:"slow_threshold"`
RequestIDHeader string `json:"request_id_header" yaml:"request_id_header"`
RouteHeader string `json:"route_header" yaml:"route_header"`
LogUserAgent bool `json:"log_user_agent" yaml:"log_user_agent"`
LogReferer bool `json:"log_referer" yaml:"log_referer"`
}
type AuditHint ¶
type AuditHint struct {
Action string
ActorID string
ResourceType string
ResourceID string
Result string
Fields []Field
}
AuditHint is intentionally not an audit record. It only leaves an operational log breadcrumb saying an auditable operation happened. Compliance-grade records must go through auditx.
type Config ¶
type Config struct {
ServiceName string `json:"service_name" yaml:"service_name"`
Env string `json:"env" yaml:"env"`
Version string `json:"version" yaml:"version"`
NodeID string `json:"node_id" yaml:"node_id"`
Level string `json:"level" yaml:"level"`
Format Format `json:"format" yaml:"format"`
Output string `json:"output" yaml:"output"` // stdout, stderr, or file path
AddSource bool `json:"add_source" yaml:"add_source"`
Redact RedactConfig `json:"redact" yaml:"redact"`
Sampling SamplingConfig `json:"sampling" yaml:"sampling"`
AccessLog AccessLogConfig `json:"access_log" yaml:"access_log"`
}
func DefaultConfig ¶
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
cfg := logx.DefaultConfig("prod")
fmt.Println(cfg.Format)
fmt.Println(cfg.Level)
fmt.Println(cfg.AddSource)
}
Output: json info false
Example (Dev) ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
cfg := logx.DefaultConfig("dev")
fmt.Println(cfg.Format)
fmt.Println(cfg.AddSource)
}
Output: console true
type DropFilter ¶
DropFilter returns true when a structured log entry should be dropped.
func DropEvents ¶
func DropEvents(events ...string) DropFilter
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// DropEvents drops entries with event=<any of given>.
_ = logx.DropEvents("debug_ping", "noisy_loop")
fmt.Println("ok")
}
Output: ok
func DropMessages ¶
func DropMessages(messages ...string) DropFilter
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
_ = logx.DropMessages("noisy library log", "deprecated")
fmt.Println("ok")
}
Output: ok
type ErrorLog ¶
type ErrorLog struct {
Operation string
ResourceType string
ResourceID string
Code string
Reason string
Err error
Fields []Field
}
ErrorLog is a standard helper for business error logs.
type ExternalCall ¶
type Field ¶
Field is the only field type exposed to business code. Do not alias slog.Attr here, otherwise the Kernel ABI leaks the engine.
func Any ¶
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
type User struct{ ID string }
logger := logx.NewTestLogger(nil)
logger.Info("user", logx.Any("user", User{ID: "u_123"}))
fmt.Println("ok")
}
Output: ok
func Bool ¶
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
logger.Info("feature", logx.Bool("enabled", true))
fmt.Println("ok")
}
Output: ok
func Duration ¶
Example ¶
package main
import (
"fmt"
"time"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
logger.Info("request done",
logx.Duration("latency", 42*time.Millisecond),
)
fmt.Println("ok")
}
Output: ok
func Err ¶
Example ¶
package main
import (
"errors"
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// logx.Err auto-extracts error_code, http_status, retryable from any
// error implementing those methods (works with errorx without import).
err := errors.New("db timeout")
logger := logx.NewTestLogger(nil)
logger.Error("query failed", logx.Err(err))
fmt.Println("ok")
}
Output: ok
func Event ¶
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
logger.Info("skill created", logx.Event("skill_created"))
fmt.Println("ok")
}
Output: ok
func FieldsFromContext ¶
Example ¶
package main
import (
"context"
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
ctx := context.Background()
fields := logx.FieldsFromContext(ctx)
fmt.Println(len(fields))
}
Output: 0
func Float64 ¶
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
logger.Info("metric", logx.Float64("rate", 0.95))
fmt.Println("ok")
}
Output: ok
func Group ¶
Group is useful when a value is naturally nested, but most platform fields should stay flat for Loki/ELK/ClickHouse indexing.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
logger.Info("user action",
logx.Group("user",
logx.String("id", "u_123"),
logx.String("name", "alice"),
),
)
fmt.Println("ok")
}
Output: ok
func Int ¶
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
logger.Info("request", logx.Int("status", 200))
fmt.Println("ok")
}
Output: ok
func Int64 ¶
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
logger.Info("file", logx.Int64("bytes", 1024))
fmt.Println("ok")
}
Output: ok
func String ¶
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
logger.Info("user login", logx.String("user_id", "u_123"))
// TestLogger captures entries; see ExampleNewTestLogger for assertion.
fmt.Println("ok")
}
Output: ok
type FieldExtractor ¶
WithExtractor appends attrs extracted from each log call context. FieldExtractor extracts logx fields from a log call context.
type FilterOption ¶
type FilterOption func(*filterConfig)
FilterOption configures filtering in WithFilter.
func FilterFunc ¶
FilterFunc drops records for which fn returns true. fn is evaluated after key redaction.
Example ¶
package main
import (
"context"
"fmt"
"log/slog"
"github.com/aisphereio/kernel/logx"
)
func main() {
// FilterFunc drops records for which fn returns true.
_ = logx.FilterFunc(func(_ context.Context, _ slog.Record) bool {
return false
})
fmt.Println("ok")
}
Output: ok
func FilterKey ¶
func FilterKey(keys ...string) FilterOption
FilterKey redacts the values of attributes whose key matches any of the provided keys. Keys may be leaf names ("password") or dotted group paths ("user.password").
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// FilterKey redacts values for the given keys.
_ = logx.FilterKey("password", "token", "secret")
fmt.Println("ok")
}
Output: ok
type Format ¶
type Format string
Format selects the encoding used by the default handler builder.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
fmt.Println(logx.FormatJSON)
fmt.Println(logx.FormatConsole)
}
Output: json console
const ( // FormatText writes records using [slog.NewTextHandler]. FormatText Format = "console" // FormatConsole is an alias of FormatText for config files. FormatConsole Format = FormatText // FormatJSON writes records using [slog.NewJSONHandler]. FormatJSON Format = "json" )
type HTTPAccessOption ¶
type HTTPAccessOption func(*httpAccessOptions)
func WithPrincipalResolver ¶
func WithPrincipalResolver(fn PrincipalResolver) HTTPAccessOption
func WithRequestIDHeader ¶
func WithRequestIDHeader(header string) HTTPAccessOption
func WithRouteResolver ¶
func WithRouteResolver(fn RouteResolver) HTTPAccessOption
type Level ¶
Level is a logger level.
const ( // LevelDebug is logger debug level. LevelDebug Level = slog.LevelDebug // LevelInfo is logger info level. LevelInfo Level = slog.LevelInfo // LevelWarn is logger warn level. LevelWarn Level = slog.LevelWarn // LevelError is logger error level. LevelError Level = slog.LevelError // LevelFatal is logger fatal level. LevelFatal Level = slog.LevelError + 4 )
func ParseLevel ¶
ParseLevel parses a level string into a logger Level value.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// ParseLevel returns slog.Level (kernel internals).
level := logx.ParseLevel("warn")
fmt.Println(level)
}
Output: WARN
type LevelController ¶
LevelController controls log level at runtime. The slog implementation is backed by slog.LevelVar, which is safe for concurrent use.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
cfg := logx.DefaultConfig("test")
_, levelCtl, _ := logx.New(cfg)
fmt.Println(levelCtl.GetLevel())
_ = levelCtl.SetLevel("debug")
fmt.Println(levelCtl.GetLevel())
}
Output: info debug
type LogLevel ¶
type LogLevel string
LogLevel is the Kernel business-facing log level. It intentionally stays independent from slog.Level so service code can depend on logx without importing the concrete slog engine.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
fmt.Println(logx.DebugLevel)
fmt.Println(logx.InfoLevel)
fmt.Println(logx.WarnLevel)
fmt.Println(logx.ErrorLevel)
}
Output: debug info warn error
func ParseLogLevel ¶
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// ParseLogLevel returns logx.LogLevel (business code).
level, _ := logx.ParseLogLevel("error")
fmt.Println(level)
}
Output: error
Example (Invalid) ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
_, err := logx.ParseLogLevel("invalid")
fmt.Println(err != nil)
}
Output: true
type Logger ¶
type Logger interface {
Debug(msg string, fields ...Field)
Info(msg string, fields ...Field)
Warn(msg string, fields ...Field)
Error(msg string, fields ...Field)
With(fields ...Field) Logger
Named(name string) Logger
WithContext(ctx context.Context) Logger
Enabled(level LogLevel) bool
Sync() error
}
Logger is the business-facing Kernel logger. It does not expose slog.Logger or slog.Attr to application packages.
func DefaultLogger ¶ added in v0.0.5
func DefaultLogger() Logger
DefaultLogger returns slog.Default adapted as a logx.Logger.
func FromContext ¶
Example ¶
package main
import (
"context"
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// FromContext returns the injected logger, or Noop if none.
ctx := context.Background()
logger := logx.FromContext(ctx)
fmt.Println(logger == logx.Noop())
}
Output: true
Example (Nil) ¶
package main
import (
"context"
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// FromContext is nil-safe: returns Noop if ctx has no logger.
logger := logx.FromContext(context.Background())
fmt.Println(logger == logx.Noop())
}
Output: true
func FromContextOr ¶
Example ¶
package main
import (
"context"
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
ctx := context.Background()
// Returns injected logger if present, else fallback.
result := logx.FromContextOr(ctx, logger)
result.Info("ok")
fmt.Println("ok")
}
Output: ok
type Option ¶
type Option func(*handlerConfig)
Option configures NewHandler and the decorators applied by NewLogger.
func WithAddSource ¶
WithAddSource toggles inclusion of the source file/line.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
_ = logx.WithAddSource(true)
fmt.Println("ok")
}
Output: ok
func WithDropFilter ¶
func WithDropFilter(filters ...DropFilter) Option
WithDropFilter appends entry drop filters used by New/NewSlog.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
_ = logx.WithDropFilter(logx.DropEvents("debug_ping"))
fmt.Println("ok")
}
Output: ok
func WithExtractor ¶
func WithFieldExtractor ¶
func WithFieldExtractor(extractors ...FieldExtractor) Option
WithFieldExtractor appends business-facing field extractors used by New/NewSlog.
func WithFilter ¶
func WithFilter(opts ...FilterOption) Option
WithFilter applies the provided filter options on top of the composed handler.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
// WithFilter applies redaction filters.
_ = logx.WithFilter(logx.FilterKey("password"))
fmt.Println("ok")
}
Output: ok
func WithFormat ¶
WithFormat selects between text and JSON encoding. Defaults to FormatText.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
_ = logx.WithFormat(logx.FormatJSON)
_ = logx.WithFormat(logx.FormatConsole)
fmt.Println("ok")
}
Output: ok
func WithLevel ¶
WithLevel sets the minimum level for the base handler.
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
_ = logx.WithLevel(logx.LevelInfo)
fmt.Println("ok")
}
Output: ok
func WithReplaceAttr ¶
WithReplaceAttr installs a custom ReplaceAttr on the base handler.
func WithWriter ¶
WithWriter sets the destination writer for the base handler. Defaults to os.Stderr.
Example ¶
package main
import (
"fmt"
)
func main() {
// WithWriter sets the destination writer for the handler.
// _ = logx.WithWriter(os.Stdout)
fmt.Println("ok")
}
Output: ok
type PanicHandler ¶
type PrincipalResolver ¶
type RPCHandler ¶
Handler and Middleware mirror Kratos's middleware idea without importing Kratos. Kratos/gRPC/Connect adapters can translate their own transport data into this small interface.
type RPCMiddleware ¶
type RPCMiddleware func(RPCHandler) RPCHandler
func ClientLogging ¶
func ClientLogging(base Logger, extract RPCInfoExtractor) RPCMiddleware
func RPCRecovery ¶
func RPCRecovery(base Logger, handler RPCPanicHandler) RPCMiddleware
func ServerLogging ¶
func ServerLogging(base Logger, extract RPCInfoExtractor) RPCMiddleware
type RPCPanicHandler ¶
type RecoveryOption ¶
type RecoveryOption func(*recoveryOptions)
func WithPanicHandler ¶
func WithPanicHandler(handler PanicHandler) RecoveryOption
type RedactConfig ¶
type Redacter ¶
type Redacter interface {
Redact() any
}
Redacter can be implemented by request/response objects that explicitly know how to produce a safe log representation. Unlike Kratos, logx does not print arbitrary request objects by default.
type Redactor ¶
func NewRedactor ¶
func NewRedactor(cfg RedactConfig) Redactor
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
r := logx.NewRedactor(logx.RedactConfig{
Enabled: true,
Keys: []string{"password", "token"},
Value: "***",
})
field := r.Redact(logx.String("password", "s3cr3t"))
fmt.Println(field.Value)
}
Output: ***
type RouteResolver ¶
type SamplingConfig ¶
type SamplingConfig struct {
Enabled bool `json:"enabled" yaml:"enabled"`
Every int `json:"every" yaml:"every"` // keep 1 of every N records after First
First int `json:"first" yaml:"first"` // always keep first N records per level/message key
Window time.Duration `json:"window" yaml:"window"` // reset sampling counters periodically
MinLevel string `json:"min_level" yaml:"min_level"` // only sample levels <= min_level, default debug
}
type TestLogger ¶
type TestLogger struct {
// contains filtered or unexported fields
}
func NewTestLogger ¶
func NewTestLogger(t testing.TB) *TestLogger
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
logger.Info("hello", logx.String("key", "value"))
entries := logger.Entries()
fmt.Println(len(entries))
fmt.Println(entries[0].Message)
}
Output: 1 hello
func (*TestLogger) AssertLogged ¶
func (l *TestLogger) AssertLogged(t testing.TB, msg string, fields ...Field)
Example ¶
package main
import (
"fmt"
"testing"
"github.com/aisphereio/kernel/logx"
)
func main() {
// In real tests, pass *testing.T.
t := &testing.T{}
logger := logx.NewTestLogger(t)
logger.Info("skill created", logx.String("skill_id", "skill_001"))
logger.AssertLogged(t, "skill created", logx.String("skill_id", "skill_001"))
fmt.Println("ok")
}
Output: ok
func (*TestLogger) Debug ¶
func (l *TestLogger) Debug(msg string, fields ...Field)
func (*TestLogger) Enabled ¶
func (l *TestLogger) Enabled(LogLevel) bool
func (*TestLogger) Entries ¶
func (l *TestLogger) Entries() []Entry
Example ¶
package main
import (
"fmt"
"github.com/aisphereio/kernel/logx"
)
func main() {
logger := logx.NewTestLogger(nil)
logger.Info("first")
logger.Info("second")
fmt.Println(len(logger.Entries()))
}
Output: 2
func (*TestLogger) Error ¶
func (l *TestLogger) Error(msg string, fields ...Field)
func (*TestLogger) Info ¶
func (l *TestLogger) Info(msg string, fields ...Field)
func (*TestLogger) Named ¶
func (l *TestLogger) Named(name string) Logger
func (*TestLogger) Sync ¶
func (l *TestLogger) Sync() error
func (*TestLogger) Warn ¶
func (l *TestLogger) Warn(msg string, fields ...Field)
func (*TestLogger) With ¶
func (l *TestLogger) With(fields ...Field) Logger
func (*TestLogger) WithContext ¶
func (l *TestLogger) WithContext(context.Context) Logger