-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TraceID and SpanID are both "00000...." in otel log export #6114
Labels
Comments
@MrAlias can you please help? |
Missing repro steps |
pellared
added
the
response needed
Waiting on user input before progress can be made
label
Dec 24, 2024
I'm sorry for the delay. Here are the steps for repro.
func newResource(name string) (*resource.Resource, error) {
return resource.Merge(
resource.Default(),
resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName(name),
),
)
}
func NewTracer(ctx context.Context, name string, ex *Exporter) (*Tracer, error) {
// setup exporter based on service choice
e, err := setupTraceExporter(ctx, ex)
if err != nil {
return nil, err
}
provider, err := newTraceProvider(e, name)
if err != nil {
return nil, err
}
// set global provider for all libraries using otel - otelmux etc.
otel.SetTracerProvider(provider)
otel.SetTextMapPropagator(propagation.TraceContext{})
tracer := provider.Tracer(name)
return &Tracer{name: name, tracer: tracer, provider: provider}, nil
}
func newTraceProvider(exp sdktrace.SpanExporter, name string) (*sdktrace.TracerProvider, error) {
r, err := newResource(name)
if err != nil {
return nil, err
}
return sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithBatcher(exp),
sdktrace.WithResource(r),
), nil
}
func setupTraceExporter(ctx context.Context, ex *Exporter) (e sdktrace.SpanExporter, err error) {
switch ex.Type {
case ConsoleExporter:
e, err = newTraceConsoleExporter()
case OTLPHttpExporter:
e, err = newTraceOTLPHttpExporter(ctx, ex.HttpEndpoint)
case OTLPGrpcExporter:
e, err = newTraceOTLPGrpcExporter(ctx, ex.GrcpEndpoint)
default:
e, err = newTraceConsoleExporter()
}
if err != nil {
return nil, err
}
return
}
func newTraceOTLPHttpExporter(ctx context.Context, otlpEndpoint string) (sdktrace.SpanExporter, error) {
insecureOpts := otlptracehttp.WithInsecure()
endpoint := otlptracehttp.WithEndpoint(otlpEndpoint)
return otlptracehttp.New(ctx, endpoint, insecureOpts)
}
func newTraceOTLPGrpcExporter(ctx context.Context, otlpEndpoint string) (sdktrace.SpanExporter, error) {
insecureOpts := otlptracegrpc.WithInsecure()
endpoint := otlptracegrpc.WithEndpoint(otlpEndpoint)
return otlptracegrpc.New(ctx, endpoint, insecureOpts)
}
func newTraceConsoleExporter() (sdktrace.SpanExporter, error) {
return stdouttrace.New(stdouttrace.WithPrettyPrint())
}
func NewLogger(ctx context.Context, name string, exp *Exporter) (*Logger, error) {
ex, err := setupLogExporter(ctx, exp)
if err != nil {
return nil, err
}
provider, err := newLogProvider(ex, name)
if err != nil {
return nil, err
}
return &Logger{name: name, provider: provider}, nil
}
func newLogProvider(exp sdklogs.Exporter, name string) (*sdklogs.LoggerProvider, error) {
r, err := newResource(name)
if err != nil {
return nil, err
}
processor := sdklogs.NewBatchProcessor(exp)
// TODO - add sampling option
return sdklogs.NewLoggerProvider(
sdklogs.WithResource(r),
sdklogs.WithProcessor(processor),
), nil
}
func setupLogExporter(ctx context.Context, ex *Exporter) (e sdklogs.Exporter, err error) {
switch ex.Type {
case ConsoleExporter:
e, err = newLogConsoleExporter()
case OTLPHttpExporter:
e, err = newLogOTLPHttpExporter(ctx, ex.HttpEndpoint)
case OTLPGrpcExporter:
e, err = newLogOTLPGrpcExporter(ctx, ex.GrcpEndpoint)
default:
e, err = newLogConsoleExporter()
}
if err != nil {
return nil, err
}
return
}
func newLogOTLPHttpExporter(ctx context.Context, otlpEndpoint string) (sdklogs.Exporter, error) {
insecureOpts := otlploghttp.WithInsecure()
endpoint := otlploghttp.WithEndpoint(otlpEndpoint)
return otlploghttp.New(ctx, endpoint, insecureOpts)
}
func newLogOTLPGrpcExporter(ctx context.Context, otlpEndpoint string) (sdklogs.Exporter, error) {
insecureOpts := otlploggrpc.WithInsecure()
endpoint := otlploggrpc.WithEndpoint(otlpEndpoint)
return otlploggrpc.New(ctx, endpoint, insecureOpts)
}
func newLogConsoleExporter() (sdklogs.Exporter, error) {
return stdoutlog.New(stdoutlog.WithPrettyPrint())
}
func (l *Logger) NewLoggerCore() *otelzap.Core {
core := otelzap.NewCore(l.name, otelzap.WithLoggerProvider(l.provider))
return core
}
func NewWithService(service, logLevel string, core ...zapcore.Core) (*Logger, error) {
level, err := zap.ParseAtomicLevel(logLevel)
if err != nil {
return nil, err
}
config := zap.Config{
Level: level,
Encoding: "json",
OutputPaths: []string{"stdout"},
ErrorOutputPaths: []string{"stderr"},
InitialFields: map[string]interface{}{"service": service},
EncoderConfig: zap.NewProductionEncoderConfig(),
DisableStacktrace: true,
}
if level.Level() == zap.DebugLevel {
config.EncoderConfig = zap.NewDevelopmentEncoderConfig()
}
log, err := config.Build()
if err != nil {
return nil, err
}
if len(core) > 0 {
otelCore := zap.WrapCore(func(c zapcore.Core) zapcore.Core {
core = append(core, c)
return zapcore.NewTee(core...)
})
log = log.WithOptions(otelCore)
}
return &Logger{log}, nil
} Then using the logger throughout the service Another thing also worth mentioning is that, I have built custom wrappers on top of zap to inject trace events on Logging a event. type LoggerWithCtx struct {
ctx context.Context
l *Logger
}
func (l *Logger) Ctx(ctx context.Context) *LoggerWithCtx {
span := trace.SpanContextFromContext(ctx)
traceID := zap.String("trace_id", span.TraceID().String())
spanID := zap.String("span_id", span.SpanID().String())
fields := []zap.Field{traceID, spanID}
return &LoggerWithCtx{ctx, &Logger{l.logger.With(fields...)}}
}
func (l *LoggerWithCtx) Debug(msg string, fields ...zap.Field) {
if span := trace.SpanFromContext(l.ctx); span.IsRecording() {
span.AddEvent(msg)
}
l.l.logger.Debug(msg, fields...)
}
func (l *LoggerWithCtx) Info(msg string, fields ...zap.Field) {
if span := trace.SpanFromContext(l.ctx); span.IsRecording() {
span.AddEvent(msg)
}
l.l.logger.Info(msg, fields...)
}
func (l *LoggerWithCtx) Error(msg string, fields ...zap.Field) {
if span := trace.SpanFromContext(l.ctx); span.IsRecording() {
span.SetStatus(codes.Error, msg)
}
l.l.logger.Error(msg, fields...)
}
func (l *LoggerWithCtx) Log(level zapcore.Level, msg string, fields ...zap.Field) {
l.l.logger.Log(level, msg, fields...)
}
func (l *LoggerWithCtx) With(fields ...zap.Field) *LoggerWithCtx {
log := l.l.logger.With(fields...)
return &LoggerWithCtx{l.ctx, &Logger{logger: log}}
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
Description
I'm using a otelzap bridge for logging and for testing purposes I've configures a console exporter for both traces and metrics
while logging I manually extract traceID and spanID from the context and add them as zap fields, but when otel exports the logs to console I can see that the traceIDs and spanIDs are added as attributes but the keys
TraceID
andSpanID
are both zeros everytime. I've no idea why is that so.Environment
Expected behavior
Zap Logs:
Otel Logs:
The text was updated successfully, but these errors were encountered: