| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 log |
| |
| import ( |
| "context" |
| "io" |
| "os" |
| ) |
| |
| import ( |
| "github.com/go-logr/logr" |
| |
| "github.com/go-logr/zapr" |
| |
| "github.com/pkg/errors" |
| |
| "go.opentelemetry.io/otel/trace" |
| |
| "go.uber.org/zap" |
| "go.uber.org/zap/zapcore" |
| |
| "gopkg.in/natefinch/lumberjack.v2" |
| |
| kube_log_zap "sigs.k8s.io/controller-runtime/pkg/log/zap" |
| ) |
| |
| import ( |
| logger_extensions "github.com/apache/dubbo-kubernetes/pkg/plugins/extensions/logger" |
| ) |
| |
| type LogLevel int |
| |
| const ( |
| OffLevel LogLevel = iota |
| InfoLevel |
| DebugLevel |
| ) |
| |
| func (l LogLevel) String() string { |
| switch l { |
| case OffLevel: |
| return "off" |
| case InfoLevel: |
| return "info" |
| case DebugLevel: |
| return "debug" |
| default: |
| return "unknown" |
| } |
| } |
| |
| func ParseLogLevel(text string) (LogLevel, error) { |
| switch text { |
| case "off": |
| return OffLevel, nil |
| case "info": |
| return InfoLevel, nil |
| case "debug": |
| return DebugLevel, nil |
| default: |
| return OffLevel, errors.Errorf("unknown log level %q", text) |
| } |
| } |
| |
| func NewLogger(level LogLevel) logr.Logger { |
| return NewLoggerTo(os.Stderr, level) |
| } |
| |
| func NewLoggerWithRotation(level LogLevel, outputPath string, maxSize int, maxBackups int, maxAge int) logr.Logger { |
| return NewLoggerTo(&lumberjack.Logger{ |
| Filename: outputPath, |
| MaxSize: maxSize, |
| MaxBackups: maxBackups, |
| MaxAge: maxAge, |
| }, level) |
| } |
| |
| func NewLoggerTo(destWriter io.Writer, level LogLevel) logr.Logger { |
| return zapr.NewLogger(newZapLoggerTo(destWriter, level)) |
| } |
| |
| func newZapLoggerTo(destWriter io.Writer, level LogLevel, opts ...zap.Option) *zap.Logger { |
| var lvl zap.AtomicLevel |
| switch level { |
| case OffLevel: |
| return zap.NewNop() |
| case DebugLevel: |
| // The value we pass here is the most verbose level that |
| // will end up being emitted through the `V(level int)` |
| // accessor. Passing -10 ensures that levels up to `V(10)` |
| // will work, which seems like plenty. |
| lvl = zap.NewAtomicLevelAt(-10) |
| opts = append(opts, zap.AddStacktrace(zap.ErrorLevel)) |
| default: |
| lvl = zap.NewAtomicLevelAt(zap.InfoLevel) |
| } |
| encCfg := zap.NewDevelopmentEncoderConfig() |
| enc := zapcore.NewConsoleEncoder(encCfg) |
| sink := zapcore.AddSync(destWriter) |
| opts = append(opts, zap.AddCallerSkip(1), zap.ErrorOutput(sink)) |
| return zap.New(zapcore.NewCore(&kube_log_zap.KubeAwareEncoder{Encoder: enc, Verbose: level == DebugLevel}, sink, lvl)). |
| WithOptions(opts...) |
| } |
| |
| // AddFieldsFromCtx will check if provided context contain tracing span and |
| // if the span is currently recording. If so, it will call spanLogValuesProcessor |
| // function if it's also present in the context. If not it will add trace_id |
| // and span_id to logged values. It will also add the tenant id to the logged |
| // values. |
| func AddFieldsFromCtx( |
| logger logr.Logger, |
| ctx context.Context, |
| extensions context.Context, |
| ) logr.Logger { |
| return addSpanValuesToLogger(logger, ctx, extensions) |
| } |
| |
| func addSpanValuesToLogger( |
| logger logr.Logger, |
| ctx context.Context, |
| extensions context.Context, |
| ) logr.Logger { |
| if span := trace.SpanFromContext(ctx); span.IsRecording() { |
| if fn, ok := logger_extensions.FromSpanLogValuesProcessorContext(extensions); ok { |
| return logger.WithValues(fn(span)...) |
| } |
| |
| return logger.WithValues( |
| "trace_id", span.SpanContext().TraceID(), |
| "span_id", span.SpanContext().SpanID(), |
| ) |
| } |
| |
| return logger |
| } |