Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
package logger
import "context"
type loggerKey struct{}
func FromContext(ctx context.Context) (Logger, bool) {
l, ok := ctx.Value(loggerKey{}).(Logger)
return l, ok
}
func NewContext(ctx context.Context, l Logger) context.Context {
return context.WithValue(ctx, loggerKey{}, l)
}
+213
View File
@@ -0,0 +1,213 @@
package logger
import (
"context"
"fmt"
"os"
"runtime"
"sort"
"strings"
"sync"
"time"
dlog "go-micro.dev/v4/debug/log"
)
func init() {
lvl, err := GetLevel(os.Getenv("MICRO_LOG_LEVEL"))
if err != nil {
lvl = InfoLevel
}
DefaultLogger = NewLogger(WithLevel(lvl))
}
type defaultLogger struct {
opts Options
sync.RWMutex
}
// Init (opts...) should only overwrite provided options.
func (l *defaultLogger) Init(opts ...Option) error {
for _, o := range opts {
o(&l.opts)
}
return nil
}
func (l *defaultLogger) String() string {
return "default"
}
func (l *defaultLogger) Fields(fields map[string]interface{}) Logger {
l.Lock()
nfields := make(map[string]interface{}, len(l.opts.Fields))
for k, v := range l.opts.Fields {
nfields[k] = v
}
l.Unlock()
for k, v := range fields {
nfields[k] = v
}
return &defaultLogger{opts: Options{
Level: l.opts.Level,
Fields: nfields,
Out: l.opts.Out,
CallerSkipCount: l.opts.CallerSkipCount,
Context: l.opts.Context,
}}
}
func copyFields(src map[string]interface{}) map[string]interface{} {
dst := make(map[string]interface{}, len(src))
for k, v := range src {
dst[k] = v
}
return dst
}
// logCallerfilePath returns a package/file:line description of the caller,
// preserving only the leaf directory name and file name.
func logCallerfilePath(loggingFilePath string) string {
// To make sure we trim the path correctly on Windows too, we
// counter-intuitively need to use '/' and *not* os.PathSeparator here,
// because the path given originates from Go stdlib, specifically
// runtime.Caller() which (as of Mar/17) returns forward slashes even on
// Windows.
//
// See https://github.com/golang/go/issues/3335
// and https://github.com/golang/go/issues/18151
//
// for discussion on the issue on Go side.
idx := strings.LastIndexByte(loggingFilePath, '/')
if idx == -1 {
return loggingFilePath
}
idx = strings.LastIndexByte(loggingFilePath[:idx], '/')
if idx == -1 {
return loggingFilePath
}
return loggingFilePath[idx+1:]
}
func (l *defaultLogger) Log(level Level, v ...interface{}) {
// TODO decide does we need to write message if log level not used?
if !l.opts.Level.Enabled(level) {
return
}
l.RLock()
fields := copyFields(l.opts.Fields)
l.RUnlock()
fields["level"] = level.String()
if _, file, line, ok := runtime.Caller(l.opts.CallerSkipCount); ok {
fields["file"] = fmt.Sprintf("%s:%d", logCallerfilePath(file), line)
}
rec := dlog.Record{
Timestamp: time.Now(),
Message: fmt.Sprint(v...),
Metadata: make(map[string]string, len(fields)),
}
keys := make([]string, 0, len(fields))
for k, v := range fields {
keys = append(keys, k)
rec.Metadata[k] = fmt.Sprintf("%v", v)
}
sort.Strings(keys)
metadata := ""
for _, k := range keys {
metadata += fmt.Sprintf(" %s=%v", k, fields[k])
}
dlog.DefaultLog.Write(rec)
t := rec.Timestamp.Format("2006-01-02 15:04:05")
fmt.Printf("%s %s %v\n", t, metadata, rec.Message)
}
func (l *defaultLogger) Logf(level Level, format string, v ...interface{}) {
// TODO decide does we need to write message if log level not used?
if !l.opts.Level.Enabled(level) {
return
}
l.RLock()
fields := copyFields(l.opts.Fields)
l.RUnlock()
fields["level"] = level.String()
if _, file, line, ok := runtime.Caller(l.opts.CallerSkipCount); ok {
fields["file"] = fmt.Sprintf("%s:%d", logCallerfilePath(file), line)
}
rec := dlog.Record{
Timestamp: time.Now(),
Message: fmt.Sprintf(format, v...),
Metadata: make(map[string]string, len(fields)),
}
keys := make([]string, 0, len(fields))
for k, v := range fields {
keys = append(keys, k)
rec.Metadata[k] = fmt.Sprintf("%v", v)
}
sort.Strings(keys)
metadata := ""
for _, k := range keys {
metadata += fmt.Sprintf(" %s=%v", k, fields[k])
}
dlog.DefaultLog.Write(rec)
t := rec.Timestamp.Format("2006-01-02 15:04:05")
fmt.Printf("%s %s %v\n", t, metadata, rec.Message)
}
func (l *defaultLogger) Options() Options {
// not guard against options Context values
l.RLock()
defer l.RUnlock()
opts := l.opts
opts.Fields = copyFields(l.opts.Fields)
return opts
}
// NewLogger builds a new logger based on options.
func NewLogger(opts ...Option) Logger {
// Default options
options := Options{
Level: InfoLevel,
Fields: make(map[string]interface{}),
Out: os.Stderr,
CallerSkipCount: 2,
Context: context.Background(),
}
l := &defaultLogger{opts: options}
if err := l.Init(opts...); err != nil {
l.Log(FatalLevel, err)
}
return l
}
+138
View File
@@ -0,0 +1,138 @@
package logger
import (
"context"
"os"
)
type Helper struct {
logger Logger
}
func NewHelper(logger Logger) *Helper {
return &Helper{logger: logger}
}
// Extract always returns valid Helper with logger from context or with DefaultLogger as fallback.
// Can be used in pair with function Inject.
// Example: propagate RequestID to logger in service handler methods.
func Extract(ctx context.Context) *Helper {
if l, ok := FromContext(ctx); ok {
return NewHelper(l)
}
return NewHelper(DefaultLogger)
}
func (h *Helper) Inject(ctx context.Context) context.Context {
return NewContext(ctx, h.logger)
}
func (h *Helper) Log(level Level, args ...interface{}) {
h.logger.Log(level, args...)
}
func (h *Helper) Logf(level Level, template string, args ...interface{}) {
h.logger.Logf(level, template, args...)
}
func (h *Helper) Info(args ...interface{}) {
if !h.logger.Options().Level.Enabled(InfoLevel) {
return
}
h.logger.Log(InfoLevel, args...)
}
func (h *Helper) Infof(template string, args ...interface{}) {
if !h.logger.Options().Level.Enabled(InfoLevel) {
return
}
h.logger.Logf(InfoLevel, template, args...)
}
func (h *Helper) Trace(args ...interface{}) {
if !h.logger.Options().Level.Enabled(TraceLevel) {
return
}
h.logger.Log(TraceLevel, args...)
}
func (h *Helper) Tracef(template string, args ...interface{}) {
if !h.logger.Options().Level.Enabled(TraceLevel) {
return
}
h.logger.Logf(TraceLevel, template, args...)
}
func (h *Helper) Debug(args ...interface{}) {
if !h.logger.Options().Level.Enabled(DebugLevel) {
return
}
h.logger.Log(DebugLevel, args...)
}
func (h *Helper) Debugf(template string, args ...interface{}) {
if !h.logger.Options().Level.Enabled(DebugLevel) {
return
}
h.logger.Logf(DebugLevel, template, args...)
}
func (h *Helper) Warn(args ...interface{}) {
if !h.logger.Options().Level.Enabled(WarnLevel) {
return
}
h.logger.Log(WarnLevel, args...)
}
func (h *Helper) Warnf(template string, args ...interface{}) {
if !h.logger.Options().Level.Enabled(WarnLevel) {
return
}
h.logger.Logf(WarnLevel, template, args...)
}
func (h *Helper) Error(args ...interface{}) {
if !h.logger.Options().Level.Enabled(ErrorLevel) {
return
}
h.logger.Log(ErrorLevel, args...)
}
func (h *Helper) Errorf(template string, args ...interface{}) {
if !h.logger.Options().Level.Enabled(ErrorLevel) {
return
}
h.logger.Logf(ErrorLevel, template, args...)
}
func (h *Helper) Fatal(args ...interface{}) {
if !h.logger.Options().Level.Enabled(FatalLevel) {
return
}
h.logger.Log(FatalLevel, args...)
os.Exit(1)
}
func (h *Helper) Fatalf(template string, args ...interface{}) {
if !h.logger.Options().Level.Enabled(FatalLevel) {
return
}
h.logger.Logf(FatalLevel, template, args...)
os.Exit(1)
}
func (h *Helper) WithError(err error) *Helper {
return &Helper{logger: h.logger.Fields(map[string]interface{}{"error": err})}
}
func (h *Helper) WithFields(fields map[string]interface{}) *Helper {
return &Helper{logger: h.logger.Fields(fields)}
}
func HelperOrDefault(h *Helper) *Helper {
if h == nil {
return DefaultHelper
}
return h
}
+126
View File
@@ -0,0 +1,126 @@
package logger
import (
"fmt"
"os"
)
type Level int8
const (
// TraceLevel level. Designates finer-grained informational events than the Debug.
TraceLevel Level = iota - 2
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
DebugLevel
// InfoLevel is the default logging priority.
// General operational entries about what's going on inside the application.
InfoLevel
// WarnLevel level. Non-critical entries that deserve eyes.
WarnLevel
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
ErrorLevel
// FatalLevel level. Logs and then calls `logger.Exit(1)`. highest level of severity.
FatalLevel
)
func (l Level) String() string {
switch l {
case TraceLevel:
return "trace"
case DebugLevel:
return "debug"
case InfoLevel:
return "info"
case WarnLevel:
return "warn"
case ErrorLevel:
return "error"
case FatalLevel:
return "fatal"
}
return ""
}
// Enabled returns true if the given level is at or above this level.
func (l Level) Enabled(lvl Level) bool {
return lvl >= l
}
// GetLevel converts a level string into a logger Level value.
// returns an error if the input string does not match known values.
func GetLevel(levelStr string) (Level, error) {
switch levelStr {
case TraceLevel.String():
return TraceLevel, nil
case DebugLevel.String():
return DebugLevel, nil
case InfoLevel.String():
return InfoLevel, nil
case WarnLevel.String():
return WarnLevel, nil
case ErrorLevel.String():
return ErrorLevel, nil
case FatalLevel.String():
return FatalLevel, nil
}
return InfoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to InfoLevel", levelStr)
}
func Info(args ...interface{}) {
DefaultLogger.Log(InfoLevel, args...)
}
func Infof(template string, args ...interface{}) {
DefaultLogger.Logf(InfoLevel, template, args...)
}
func Trace(args ...interface{}) {
DefaultLogger.Log(TraceLevel, args...)
}
func Tracef(template string, args ...interface{}) {
DefaultLogger.Logf(TraceLevel, template, args...)
}
func Debug(args ...interface{}) {
DefaultLogger.Log(DebugLevel, args...)
}
func Debugf(template string, args ...interface{}) {
DefaultLogger.Logf(DebugLevel, template, args...)
}
func Warn(args ...interface{}) {
DefaultLogger.Log(WarnLevel, args...)
}
func Warnf(template string, args ...interface{}) {
DefaultLogger.Logf(WarnLevel, template, args...)
}
func Error(args ...interface{}) {
DefaultLogger.Log(ErrorLevel, args...)
}
func Errorf(template string, args ...interface{}) {
DefaultLogger.Logf(ErrorLevel, template, args...)
}
func Fatal(args ...interface{}) {
DefaultLogger.Log(FatalLevel, args...)
os.Exit(1)
}
func Fatalf(template string, args ...interface{}) {
DefaultLogger.Logf(FatalLevel, template, args...)
os.Exit(1)
}
// Returns true if the given level is at or lower the current logger level.
func V(lvl Level, log Logger) bool {
l := DefaultLogger
if log != nil {
l = log
}
return l.Options().Level <= lvl
}
+53
View File
@@ -0,0 +1,53 @@
// Package log provides a log interface
package logger
var (
// Default logger.
DefaultLogger Logger = NewLogger()
// Default logger helper.
DefaultHelper *Helper = NewHelper(DefaultLogger)
)
// Logger is a generic logging interface.
type Logger interface {
// Init initializes options
Init(options ...Option) error
// The Logger options
Options() Options
// Fields set fields to always be logged
Fields(fields map[string]interface{}) Logger
// Log writes a log entry
Log(level Level, v ...interface{})
// Logf writes a formatted log entry
Logf(level Level, format string, v ...interface{})
// String returns the name of logger
String() string
}
func Init(opts ...Option) error {
return DefaultLogger.Init(opts...)
}
func Fields(fields map[string]interface{}) Logger {
return DefaultLogger.Fields(fields)
}
func Log(level Level, v ...interface{}) {
DefaultLogger.Log(level, v...)
}
func Logf(level Level, format string, v ...interface{}) {
DefaultLogger.Logf(level, format, v...)
}
func String() string {
return DefaultLogger.String()
}
func LoggerOrDefault(l Logger) Logger {
if l == nil {
return DefaultLogger
}
return l
}
+58
View File
@@ -0,0 +1,58 @@
package logger
import (
"context"
"io"
)
type Option func(*Options)
type Options struct {
// It's common to set this to a file, or leave it default which is `os.Stderr`
Out io.Writer
// Alternative options
Context context.Context
// fields to always be logged
Fields map[string]interface{}
// Caller skip frame count for file:line info
CallerSkipCount int
// The logging level the logger should log at. default is `InfoLevel`
Level Level
}
// WithFields set default fields for the logger.
func WithFields(fields map[string]interface{}) Option {
return func(args *Options) {
args.Fields = fields
}
}
// WithLevel set default level for the logger.
func WithLevel(level Level) Option {
return func(args *Options) {
args.Level = level
}
}
// WithOutput set default output writer for the logger.
func WithOutput(out io.Writer) Option {
return func(args *Options) {
args.Out = out
}
}
// WithCallerSkipCount set frame count to skip.
func WithCallerSkipCount(c int) Option {
return func(args *Options) {
args.CallerSkipCount = c
}
}
func SetOption(k, v interface{}) Option {
return func(o *Options) {
if o.Context == nil {
o.Context = context.Background()
}
o.Context = context.WithValue(o.Context, k, v)
}
}