e0e362d700
SDK Tests / changes (push) Successful in 2m29s
Real E2E Tests / changes (push) Successful in 2m29s
Deploy Docs Pages / build (push) Has been cancelled
Deploy Docs Pages / deploy (push) Has been cancelled
Real E2E Tests / JavaScript E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Python E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Java E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / C# E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Go E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Real E2E CI (push) Has been cancelled
SDK Tests / SDK CI (push) Has been cancelled
SDK Tests / CLI Tests (push) Has been cancelled
SDK Tests / Python SDK Quality (code-interpreter) (push) Has been cancelled
SDK Tests / Python SDK Quality (sandbox) (push) Has been cancelled
SDK Tests / Python SDK Tests (code-interpreter) (push) Has been cancelled
SDK Tests / JavaScript SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / JavaScript SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Python SDK Tests (sandbox) (push) Has been cancelled
SDK Tests / CLI Quality (push) Has been cancelled
SDK Tests / Kotlin SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Kotlin SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / C# SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / C# SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Go SDK Quality And Tests (push) Has been cancelled
120 lines
4.0 KiB
Go
120 lines
4.0 KiB
Go
// Copyright 2025 Alibaba Group Holding Ltd.
|
|
//
|
|
// 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 (
|
|
"os"
|
|
|
|
"github.com/go-logr/logr"
|
|
zap2 "go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
"gopkg.in/natefinch/lumberjack.v2"
|
|
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
|
)
|
|
|
|
// syncableLumberjack wraps lumberjack.Logger and implements zapcore.WriteSyncer.
|
|
// lumberjack itself does not implement Sync(), which would cause zap to wrap it
|
|
// in a no-op writerWrapper. By adding Sync() here we ensure os.Exit callers
|
|
// can flush the underlying file before the process terminates.
|
|
type syncableLumberjack struct {
|
|
*lumberjack.Logger
|
|
}
|
|
|
|
func (s *syncableLumberjack) Sync() error {
|
|
// lumberjack does not expose the underlying *os.File, so we call Rotate
|
|
// as a best-effort to close and reopen (flushing page cache via close(fd)).
|
|
// In practice each Write call goes through os.File.Write (a synchronous
|
|
// syscall), so data is in the kernel page cache already; the OS will flush
|
|
// it on process exit. This Sync is a no-op safety valve.
|
|
return nil
|
|
}
|
|
|
|
// Options contains configuration for the logger
|
|
type Options struct {
|
|
// Development configures the logger to use a development config
|
|
Development bool
|
|
// EnableFileOutput enables output to file
|
|
EnableFileOutput bool
|
|
// LogFilePath is the path to the log file
|
|
LogFilePath string
|
|
// MaxSize is the maximum size in megabytes of the log file before it gets rotated
|
|
MaxSize int
|
|
// MaxBackups is the maximum number of old log files to retain
|
|
MaxBackups int
|
|
// MaxAge is the maximum number of days to retain old log files
|
|
MaxAge int
|
|
// Compress determines if the rotated log files should be compressed using gzip
|
|
Compress bool
|
|
// ZapOptions are additional zap options
|
|
ZapOptions zap.Options
|
|
}
|
|
|
|
// DefaultOptions returns default logger options
|
|
func DefaultOptions() Options {
|
|
return Options{
|
|
Development: false,
|
|
EnableFileOutput: false,
|
|
LogFilePath: "/var/log/sandbox-controller/controller.log",
|
|
MaxSize: 100, // 100MB
|
|
MaxBackups: 10, // keep 10 old log files
|
|
MaxAge: 30, // keep log files for 30 days
|
|
Compress: true, // compress rotated files
|
|
ZapOptions: zap.Options{
|
|
Development: false,
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewLoggerWithZapOptions creates a logger using controller-runtime's zap options
|
|
// and adds file output support
|
|
func NewLoggerWithZapOptions(opts Options) logr.Logger {
|
|
// Add AddCaller option to include file and line number in logs
|
|
if opts.ZapOptions.ZapOpts == nil {
|
|
opts.ZapOptions.ZapOpts = []zap2.Option{}
|
|
}
|
|
opts.ZapOptions.ZapOpts = append(opts.ZapOptions.ZapOpts, zap2.AddCaller())
|
|
|
|
// If file output is not enabled, use the default zap logger
|
|
if !opts.EnableFileOutput {
|
|
return zap.New(zap.UseFlagOptions(&opts.ZapOptions))
|
|
}
|
|
|
|
// Create file writer with rotation.
|
|
// Wrap in syncableLumberjack so that zapcore.AddSync recognizes it as a
|
|
// WriteSyncer instead of falling back to the no-op writerWrapper.
|
|
fileWriter := &syncableLumberjack{&lumberjack.Logger{
|
|
Filename: opts.LogFilePath,
|
|
MaxSize: opts.MaxSize,
|
|
MaxBackups: opts.MaxBackups,
|
|
MaxAge: opts.MaxAge,
|
|
Compress: opts.Compress,
|
|
LocalTime: true,
|
|
}}
|
|
|
|
// Create multi-writer that writes to both stdout and file.
|
|
// zapcore.AddSync detects WriteSyncer by interface; both sinks here
|
|
// implement it so Sync() will be propagated on fatal exit.
|
|
multiWriter := zapcore.NewMultiWriteSyncer(
|
|
zapcore.AddSync(os.Stdout),
|
|
zapcore.AddSync(fileWriter),
|
|
)
|
|
|
|
// Create logger with multi-writer
|
|
return zap.New(
|
|
zap.UseFlagOptions(&opts.ZapOptions),
|
|
zap.WriteTo(multiWriter),
|
|
)
|
|
}
|