package ersteller import ( "context" "fmt" "time" "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc" "go.opentelemetry.io/otel/log" sdklog "go.opentelemetry.io/otel/sdk/log" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.37.0" ) type LoggerImpl struct { logger log.Logger logToStdout bool } type LoggerImplOption func(*LoggerImpl) func PrintToStdout() LoggerImplOption { return func(l *LoggerImpl) { l.logToStdout = true } } func NewLoggerImpl(name string, version string, opts ...LoggerImplOption) *LoggerImpl { // Create an OTLP exporter logExporter, err := otlploggrpc.New(context.Background()) if err != nil { // Fall back to stdout if exporter creation fails Error("Failed to create OTLP log exporter:", err) return &LoggerImpl{} } // Create a resource that identifies your application res, err := resource.Merge( resource.Default(), resource.NewWithAttributes( semconv.SchemaURL, semconv.ServiceName(name), semconv.ServiceVersion(version), ), ) if err != nil { Error("Failed to create resource:", err) return &LoggerImpl{} } // Create a batch processor with the exporter batchProcessor := sdklog.NewBatchProcessor(logExporter) // Create a logger provider with the processor provider := sdklog.NewLoggerProvider( sdklog.WithProcessor(batchProcessor), sdklog.WithResource(res), ) // Create a logger logger := provider.Logger("salezenify.logger") loggerImpl := &LoggerImpl{ logger: logger, } for _, option := range opts { option(loggerImpl) } return loggerImpl } func (l *LoggerImpl) Debug(a ...any) { message := joinStrings(a) // If logger is not initialized, fallback to standard output if l.logger == nil { println(message) return } if l.logToStdout { PrintDebug(a...) } // Use OpenTelemetry logger ctx := context.Background() // Create a Record and emit it record := log.Record{} record.SetSeverity(log.SeverityDebug) record.SetSeverityText("DEBUG") record.SetBody(log.StringValue(message)) record.SetTimestamp(time.Now()) record.SetObservedTimestamp(time.Now()) l.logger.Emit(ctx, record) } func (l *LoggerImpl) Error(a ...any) { // If logger is not initialized, fallback to standard output if l.logger == nil { errorMessage := "Error: " + joinStrings(a) println(errorMessage) return } if l.logToStdout { PrintError(a...) } // Use OpenTelemetry logger ctx := context.Background() message := joinStrings(a) // Create a Record and emit it record := log.Record{} record.SetSeverity(log.SeverityError) record.SetSeverityText("ERROR") record.SetBody(log.StringValue(message)) record.SetTimestamp(time.Now()) record.SetObservedTimestamp(time.Now()) l.logger.Emit(ctx, record) } func (l *LoggerImpl) LogDebug(message string, a ...any) { // If logger is not initialized, fallback to standard output formattedMessage := fmt.Sprintf(message, a...) l.Debug(formattedMessage) } func (l *LoggerImpl) LogError(message string, a ...any) { formattedMessage := fmt.Sprintf(message, a...) l.Error(formattedMessage) }