Codevault initial commit

This commit is contained in:
2026-08-16 16:23:14 +03:00
commit 6ee80f1c8f
47 changed files with 3177 additions and 0 deletions

View File

@@ -0,0 +1,139 @@
package logging
import (
"context"
"errors"
"fmt"
"os"
"time"
"go.opentelemetry.io/contrib/bridges/otelzap"
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
"go.opentelemetry.io/otel/log/global"
"go.opentelemetry.io/otel/sdk/log"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"github.com/kanootoko/codevault/internal"
"github.com/kanootoko/codevault/internal/config"
"github.com/kanootoko/codevault/internal/observability"
)
func ConfigureLogger(ctx context.Context, cfg config.LoggingConfig, isProductionEnv bool) (logger *zap.Logger, closeFunc func(), err error) {
stderrLevel, err := cfg.Stderr.ToZapLevel()
if err != nil && !errors.Is(err, config.ErrLoggingDisabled) {
return nil, nil, fmt.Errorf("error on getting stderr logging level: %w", err)
}
fileLoggers := make(map[string]zapcore.Level)
for level, file := range cfg.Files {
l, err := level.ToZapLevel()
if err != nil {
return nil, nil, fmt.Errorf("error on getting file logging level: %w", err)
}
fileLoggers[file] = l
}
var stderrEncoder zapcore.Encoder
var fileEncoder zapcore.Encoder
{
var fileLoggerCfg zapcore.EncoderConfig
var stderrLoggerCfg zapcore.EncoderConfig
if isProductionEnv {
fileLoggerCfg = zap.NewProductionEncoderConfig()
stderrLoggerCfg = zap.NewProductionEncoderConfig()
} else {
fileLoggerCfg = zap.NewDevelopmentEncoderConfig()
stderrLoggerCfg = zap.NewDevelopmentEncoderConfig()
}
fileLoggerCfg.TimeKey = "timestamp"
fileLoggerCfg.EncodeTime = zapcore.ISO8601TimeEncoder
stderrLoggerCfg.EncodeLevel = zapcore.CapitalColorLevelEncoder
stderrEncoder = zapcore.NewConsoleEncoder(stderrLoggerCfg)
fileEncoder = zapcore.NewJSONEncoder(fileLoggerCfg)
}
fileHandlers := make([]*os.File, 0, len(fileLoggers))
zapWriters := make([]zapcore.Core, 0, len(fileLoggers)+1)
for filename, level := range fileLoggers {
fileHandler, err := os.Create(filename)
if err != nil {
for _, file := range fileHandlers[:len(fileHandlers)-1] {
_ = file.Close()
}
return nil, nil, fmt.Errorf("error on log file creation: %w", err)
}
fileHandlers = append(fileHandlers, fileHandler)
fileSync := zapcore.AddSync(fileHandler)
zapWriters = append(zapWriters, zapcore.NewCore(fileEncoder, fileSync, zap.NewAtomicLevelAt(level)))
}
stderrSync := zapcore.AddSync(os.Stderr)
if stderrLevel != zapcore.InvalidLevel {
zapWriters = append(zapWriters, zapcore.NewCore(stderrEncoder, stderrSync, zap.NewAtomicLevelAt(stderrLevel)))
}
var otlpCloseFunc func()
if cfg.Exporter.Level != "" {
var otlpWriter zapcore.Core
var err error
otlpWriter, otlpCloseFunc, err = configureOtelLogging(ctx, cfg.Exporter)
if err != nil {
return nil, nil, fmt.Errorf("cannot configure OpenTelemetry log exporter: %w", err)
}
zapWriters = append(zapWriters, otlpWriter)
}
core := zapcore.NewTee(
zapWriters...,
)
logger = zap.New(core)
closeFunc = func() {
_ = logger.Sync()
for _, file := range fileHandlers {
_ = file.Close()
}
if otlpCloseFunc != nil {
otlpCloseFunc()
}
}
logger.Info("configured logging", zap.Any("config", cfg))
return
}
func configureOtelLogging(ctx context.Context, cfg config.LogsExporterConfig) (zapcore.Core, func(), error) {
var exporter log.Exporter
var err error
if cfg.Transport == config.HTTPTransportType {
exporter, err = otlploghttp.New(ctx, otlploghttp.WithEndpointURL(cfg.Endpoint))
} else {
exporter, err = otlploggrpc.New(ctx, otlploggrpc.WithEndpointURL(cfg.Endpoint))
}
if err != nil {
return nil, nil, fmt.Errorf("cannot create OpenTelemetry logs exporter: %w", err)
}
res, err := observability.GetOtelResource()
if err != nil {
return nil, nil, fmt.Errorf("cannot get OpenTelemetry resource: %w", err)
}
provider := log.NewLoggerProvider(
log.WithProcessor(log.NewBatchProcessor(exporter)),
log.WithResource(res),
)
closeFunc := func() {
shutdownContext, cancel := context.WithTimeout(context.Background(), time.Millisecond*300)
defer cancel()
_ = provider.ForceFlush(shutdownContext)
_ = provider.Shutdown(shutdownContext)
<-shutdownContext.Done()
}
global.SetLoggerProvider(provider)
return otelzap.NewCore(internal.PackageName, otelzap.WithLoggerProvider(provider)), closeFunc, nil
}