Slide 1

Slide 1 text

4IPUB*XBNJ]1MBUGPSN&OHJOFFS]OFXNP *OD OpenTelemetry ͷ Log Λ࢖͍͜ͳͦ͏
 Jagu'e'r ΦϒβʔόϏϦςΟ෼Պձ Meetup #3 1

Slide 2

Slide 2 text

ؠݟজଠ*XBNJO Platform Engineer newmo, Inc. 2

Slide 3

Slide 3 text

ؠݟজଠ*XBNJO Platform Engineer Autonomous Driving Vehicle Team? newmo, Inc. 3

Slide 4

Slide 4 text

Software Design 5݄߸ 4 4 ● ͸͡Ίʹ ● OpenTelemetryͱ͸ ● OpenTelemetryͷجຊΞʔΩςΫνϟ ● αϯϓϦϯάઓུͱ࣮૷ ● ܭ૷ͷछྨͱબ୒ج४ ● खಈ/ϥΠϒϥϦ/ࣗಈܭ૷ ● TraceProvider ● MetricProvider ● LoggerProvider ● ·ͱΊ 4 “OpenTelemetryೖ໳” Λدߘ͠·ͨ͠

Slide 5

Slide 5 text

Software Design 5݄߸ 5 “OpenTelemetryೖ໳” Λدߘ͠·ͨ͠ 5 ● ͸͡Ίʹ ● OpenTelemetryͱ͸ ● OpenTelemetryͷجຊΞʔΩςΫνϟ ● αϯϓϦϯάઓུͱ࣮૷ ● ܭ૷ͷछྨͱબ୒ج४ ● खಈ/ϥΠϒϥϦ/ࣗಈܭ૷ ● TraceProvider ● MetricProvider ● LoggerProvider ● ·ͱΊ 5

Slide 6

Slide 6 text

LoggerProviderͷར༻ 6

Slide 7

Slide 7 text

Logger Provider 7 7 ● Trace, Metricsͱ͸গ͠ੑ࣭͕ҧ͏ ● طଘͷϩΪϯάϥΠϒϥϦͱ Otel Λ࿈ܞͤ͞ΔͨΊͷ Bridge ػೳΛఏڙ ● ޓ׵ੑΛอͪͳ͕Β Trace ͱඥ෇͚Δ Context ͷ௥Ճ΍ڞ௨ϑΥʔϚοτʹղੳɾม׵͢Δͨ ΊͷπʔϧΩοτΛఏڙ 7

Slide 8

Slide 8 text

Logger Provider 8 8 ● Trace, Metricsͱ͸গ͠ੑ࣭͕ҧ͏ ● طଘͷϩΪϯάϥΠϒϥϦͱ Otel Λ࿈ܞͤ͞ΔͨΊͷ Bridge ػೳΛఏڙ ● ޓ׵ੑΛอͪͳ͕Β Trace ͱඥ෇͚Δ Context ͷ௥Ճ΍ڞ௨ϑΥʔϚοτʹղੳɾม׵͢Δͨ ΊͷπʔϧΩοτΛఏڙ 8

Slide 9

Slide 9 text

Otel log bridge Λ࢖Θͳ͍৔߹ 9

Slide 10

Slide 10 text

10 func (s *slogJSONHandler) Handle( ctx context.Context, r slog.Record, ) error { newRecord := slog.NewRecord(…) ... sc := trace.SpanContextFromContext(ctx) if sc.HasTraceID() { newRecord.AddAttrs( slog.String("trace_id", sc.TraceID().String()), slog.String("trace_flags", sc.TraceFlags().String()), ) if sc.HasSpanID() { newRecord.AddAttrs(slog.String("span_id", sc.SpanID().String())) } } return s.handler.Handle(ctx, newRecord) } Bridge ౳Λ࢖Θͣʹ trace ͱඥ͚ͮΔ৔߹ ● Log Handler ʹcontext ͔Β trace id ౳Λऔಘ ● ࣗલͰ attribute ʹ௥Ճ

Slide 11

Slide 11 text

11 func (s *slogJSONHandler) Handle( ctx context.Context, r slog.Record, ) error { newRecord := slog.NewRecord(…) ... sc := trace.SpanContextFromContext(ctx) if sc.HasTraceID() { newRecord.AddAttrs( slog.String("trace_id", sc.TraceID().String()), slog.String("trace_flags", sc.TraceFlags().String()), ) if sc.HasSpanID() { newRecord.AddAttrs(slog.String("span_id", sc.SpanID().String())) } } return s.handler.Handle(ctx, newRecord) } Bridge ౳Λ࢖Θͣʹ trace ͱඥ͚ͮΔ৔߹ ● Log Handler ʹcontext ͔Β trace id ౳Λऔಘ ● ࣗલͰ attribute ʹ௥Ճ

Slide 12

Slide 12 text

12 func (s *slogJSONHandler) Handle( ctx context.Context, r slog.Record, ) error { newRecord := slog.NewRecord(…) ... sc := trace.SpanContextFromContext(ctx) if sc.HasTraceID() { newRecord.AddAttrs( slog.String("trace_id", sc.TraceID().String()), slog.String("trace_flags", sc.TraceFlags().String()), ) if sc.HasSpanID() { newRecord.AddAttrs(slog.String("span_id", sc.SpanID().String())) } } return s.handler.Handle(ctx, newRecord) } Bridge ౳Λ࢖Θͣʹ trace ͱඥ͚ͮΔ৔߹ ● Log Handler ʹcontext ͔Β trace id ౳Λऔಘ ● ࣗલͰ attribute ʹ௥Ճ

Slide 13

Slide 13 text

Otel log bridge Λ࢖͏৔߹ 13

Slide 14

Slide 14 text

lp := initLoggerProvider(ctx) // slogͱOpenTelemetryͷ࿈ܞ logger := otelslog.NewLogger("my-service", otelslog.WithLoggerProvider(lp)) // τϨʔεͱͷ࿈ܞྫ tracer := otel.Tracer("my-service") ctx, span := tracer.Start(ctx, "operation-name") defer span.End() // contextΛ౉͢͜ͱͰɺtrace৘ใΛ఻ൖ͍ͯ͠Δ logger.InfoContext(ctx, "Start processing", "user_id", "12345", ) OpenTelemetry Logger Provider for Go 14 ● ීஈ࢖͍ͬͯΔ slog Λ wrap ͢Δ͚ͩ

Slide 15

Slide 15 text

lp := initLoggerProvider(ctx) // slogͱOpenTelemetryͷ࿈ܞ logger := otelslog.NewLogger("my-service", otelslog.WithLoggerProvider(lp)) // τϨʔεͱͷ࿈ܞྫ tracer := otel.Tracer("my-service") ctx, span := tracer.Start(ctx, "operation-name") defer span.End() // contextΛ౉͢͜ͱͰɺtrace৘ใΛ఻ൖ͍ͯ͠Δ logger.InfoContext(ctx, "Start processing", "user_id", "12345", ) OpenTelemetry Logger Provider for Go 15 ● ීஈ࢖͍ͬͯΔ slog Λ wrap func initLoggerProvider(ctx context.Context) (*sdklog.LoggerProvider, error) { // ΤΫεϙʔλʔͷઃఆ exporter, _ := otlploggrpc.New(ctx, otlploggrpc.WithEndpoint("localhost:4317"), otlploggrpc.WithInsecure(), ) // LoggerProviderͷઃఆ loggerProvider := sdklog.NewLoggerProvider( sdklog.WithProcessor( sdklog.NewBatchProcessor( exporter, ), ), ) return loggerProvider, nil }

Slide 16

Slide 16 text

Logger Provider 16 16 16

Slide 17

Slide 17 text

Logger Provider 17 17 17

Slide 18

Slide 18 text

Logger Provider 18 18 18

Slide 19

Slide 19 text

Logger Provider 19 19 19

Slide 20

Slide 20 text

Logger Provider 20 20 20

Slide 21

Slide 21 text

Logger Provider 21 21 21

Slide 22

Slide 22 text

lp := initLoggerProvider(ctx) // slogͱOpenTelemetryͷ࿈ܞ logger := otelslog.NewLogger("my-service", otelslog.WithLoggerProvider(lp)) // τϨʔεͱͷ࿈ܞྫ tracer := otel.Tracer("my-service") ctx, span := tracer.Start(ctx, "operation-name") defer span.End() // contextΛ౉͢͜ͱͰɺtrace৘ใΛ఻ൖ͍ͯ͠Δ logger.InfoContext(ctx, "Start processing", "user_id", "12345", ) OpenTelemetry Logger Provider for Go 22 ● ීஈ࢖͍ͬͯΔ slog Λ wrap ͢Δ͚ͩ ͳΜ͔͍͍ײ͡ʹͯ͘͠ΕΔ ͲͷΑ͏ͳ࢓૊Έʁ

Slide 23

Slide 23 text

Logger Provider ͷ ઃܭͱ಺෦࣮૷ 23

Slide 24

Slide 24 text

Logger Provider ͷઃܭͱ಺෦࣮૷ 24 24 24

Slide 25

Slide 25 text

Logger Provider ͷઃܭͱ಺෦࣮૷ 25 25 25

Slide 26

Slide 26 text

26 // ΞϓϦέʔγϣϯ logger.InfoContext(ctx, "ॲཧ։࢝", "user_id", 123) // otelslog.Handler.Handle() func (h *handler) Handle(ctx context.Context, r slog.Record) error { // slog.Record Λ log.Record ʹม׵ record := convert.LogRecord(r) // ಺෦ͷOTel Loggerʹసૹ h.logger.Emit(ctx, record) return nil } otelslog Bridge

Slide 27

Slide 27 text

27 // ΞϓϦέʔγϣϯ logger.InfoContext(ctx, "ॲཧ։࢝", "user_id", 123) // otelslog.Handler.Handle() func (h *handler) Handle(ctx context.Context, r slog.Record) error { // slog.Record Λ log.Record ʹม׵ record := convert.LogRecord(r) // ಺෦ͷOTel Loggerʹసૹ h.logger.Emit(ctx, record) return nil } otelslog Bridge slog logܗ͔ࣜΒ otel logܗࣜʹ Convert

Slide 28

Slide 28 text

28 // ΞϓϦέʔγϣϯ logger.InfoContext(ctx, "ॲཧ։࢝", "user_id", 123) // otelslog.Handler.Handle() func (h *handler) Handle(ctx context.Context, r slog.Record) error { // slog.Record Λ log.Record ʹม׵ record := convert.LogRecord(r) // ಺෦ͷOTel Loggerʹసૹ h.logger.Emit(ctx, record) return nil } otelslog Bridge otel logger ͷ Emit Λ࣮ߦ

Slide 29

Slide 29 text

Logger Provider ͷઃܭͱ಺෦࣮૷ 29 29 29

Slide 30

Slide 30 text

30 func (l *logger) Emit(ctx context.Context, r log.Record) { newRecord := l.newRecord(ctx, r) for _, p := range l.provider.processors { p.OnEmit(ctx, &newRecord) } } func (l *logger) newRecord(ctx context.Context, r log.Record) Record { sc := trace.SpanContextFromContext(ctx) return Record{ body: r.Body(), severity: r.Severity(), timestamp: r.Timestamp(), traceID: sc.TraceID(), spanID: sc.SpanID(), traceFlags: sc.TraceFlags(), resource: l.provider.resource, scope: &l.instrumentationScope, } } Otel SDK

Slide 31

Slide 31 text

31 func (l *logger) Emit(ctx context.Context, r log.Record) { newRecord := l.newRecord(ctx, r) for _, p := range l.provider.processors { p.OnEmit(ctx, &newRecord) } } func (l *logger) newRecord(ctx context.Context, r log.Record) Record { sc := trace.SpanContextFromContext(ctx) return Record{ body: r.Body(), severity: r.Severity(), timestamp: r.Timestamp(), traceID: sc.TraceID(), spanID: sc.SpanID(), traceFlags: sc.TraceFlags(), resource: l.provider.resource, scope: &l.instrumentationScope, } } Otel SDK ৽ن Record ࡞੒

Slide 32

Slide 32 text

32 func (l *logger) Emit(ctx context.Context, r log.Record) { newRecord := l.newRecord(ctx, r) for _, p := range l.provider.processors { p.OnEmit(ctx, &newRecord) } } func (l *logger) newRecord(ctx context.Context, r log.Record) Record { sc := trace.SpanContextFromContext(ctx) return Record{ body: r.Body(), severity: r.Severity(), timestamp: r.Timestamp(), traceID: sc.TraceID(), spanID: sc.SpanID(), traceFlags: sc.TraceFlags(), resource: l.provider.resource, scope: &l.instrumentationScope, } } Otel SDK Context ͔Β Trace ID / Span ID Λ औಘͯ͠ Record ʹຒΊࠐΉ

Slide 33

Slide 33 text

33 func (l *logger) Emit(ctx context.Context, r log.Record) { newRecord := l.newRecord(ctx, r) for _, p := range l.provider.processors { p.OnEmit(ctx, &newRecord) } } func (l *logger) newRecord(ctx context.Context, r log.Record) Record { sc := trace.SpanContextFromContext(ctx) return Record{ body: r.Body(), severity: r.Severity(), timestamp: r.Timestamp(), traceID: sc.TraceID(), spanID: sc.SpanID(), traceFlags: sc.TraceFlags(), resource: l.provider.resource, scope: &l.instrumentationScope, } } Otel SDK Processor Λ ॱ࣮࣍ߦ

Slide 34

Slide 34 text

34 func (l *logger) Emit(ctx context.Context, r log.Record) { newRecord := l.newRecord(ctx, r) for _, p := range l.provider.processors { p.OnEmit(ctx, &newRecord) } } func (l *logger) newRecord(ctx context.Context, r log.Record) Record { sc := trace.SpanContextFromContext(ctx) return Record{ body: r.Body(), severity: r.Severity(), timestamp: r.Timestamp(), traceID: sc.TraceID(), spanID: sc.SpanID(), traceFlags: sc.TraceFlags(), resource: l.provider.resource, scope: &l.instrumentationScope, } } Otel SDK Processor Λ ॱ࣮࣍ߦ

Slide 35

Slide 35 text

35 func (l *logger) Emit(ctx context.Context, r log.Record) { newRecord := l.newRecord(ctx, r) for _, p := range l.provider.processors { p.OnEmit(ctx, &newRecord) } } func (l *logger) newRecord(ctx context.Context, r log.Record) Record { sc := trace.SpanContextFromContext(ctx) return Record{ body: r.Body(), severity: r.Severity(), timestamp: r.Timestamp(), traceID: sc.TraceID(), spanID: sc.SpanID(), traceFlags: sc.TraceFlags(), resource: l.provider.resource, scope: &l.instrumentationScope, } } Otel SDK Processor Λ ॱ࣮࣍ߦ

Slide 36

Slide 36 text

36 // SimpleProcessor func (s *SimpleProcessor) OnEmit(ctx context.Context, r *Record) error { records := []*Record{r} return s.exporter.Export(ctx, records) } // BatchProcessor func (b *BatchProcessor) OnEmit(ctx context.Context, r *Record) error { b.queue.Enqueue(r.Clone()) return nil } Processor

Slide 37

Slide 37 text

37 // SimpleProcessor func (s *SimpleProcessor) OnEmit(ctx context.Context, r *Record) error { records := []*Record{r} return s.exporter.Export(ctx, records) } // BatchProcessor func (b *BatchProcessor) OnEmit(ctx context.Context, r *Record) error { b.queue.Enqueue(r.Clone()) return nil } Processor SimpleProcessor ଈ࠲ʹ Export

Slide 38

Slide 38 text

38 // SimpleProcessor func (s *SimpleProcessor) OnEmit(ctx context.Context, r *Record) error { records := []*Record{r} return s.exporter.Export(ctx, records) } // BatchProcessor func (b *BatchProcessor) OnEmit(ctx context.Context, r *Record) error { b.queue.Enqueue(r.Clone()) return nil } Processor BatchProcessor όοναΠζʹୡͨ͠Β ผͷ Goroutine Ͱ Export

Slide 39

Slide 39 text

Logger Provider ͷઃܭͱ಺෦࣮૷ 39 39 39

Slide 40

Slide 40 text

Logger Provider ͷઃܭͱ಺෦࣮૷ 40 40 40 local Ͱ͸ otlp Ͱग़ྗͯ͠ o11y πʔϧͰ trace ͱඥ͚ͮͯ֬ೝ dev/stg/prod Ͱ͸ඪ४ग़ྗͰग़ͯ͠ӬଓԽͭͭ͠ϩάΛpipelineͰྲྀͯ֬͠ೝ

Slide 41

Slide 41 text

Logger Provider ͷઃܭͱ಺෦࣮૷ 41 41 41

Slide 42

Slide 42 text

Logger Provider ͷઃܭͱ಺෦࣮૷ 42 42 42 ͍ͭ΋௨Γ

Slide 43

Slide 43 text

Logger Provider ͷઃܭͱ಺෦࣮૷ 43 43 43 ͍ͭ΋௨Γ ࢖ͬͯΔLogͷܗࣜΛ OtelLogʹม׵

Slide 44

Slide 44 text

Logger Provider ͷઃܭͱ಺෦࣮૷ 44 44 44 ͍ͭ΋௨Γ ࢖ͬͯΔLogͷܗࣜΛ OtelLogʹม׵ Trace ৘ใͷநग़ ೚ҙͷ Export

Slide 45

Slide 45 text

Logger Provider ͷઃܭͱ಺෦࣮૷ 45 45 45 ͍ͭ΋௨Γ ࢖ͬͯΔLogͷܗࣜΛ OtelLogʹม׵ Trace ৘ใͷநग़ ೚ҙͷ Export ؀ڥʹԠͨ֬͡ೝ

Slide 46

Slide 46 text

Logger Provider ͷઃܭͱ಺෦࣮૷ 46 46 46 ͍ͭ΋௨Γ ࢖ͬͯΔLogͷܗࣜΛ OtelLogʹม׵ Trace ৘ใͷநग़ ೚ҙͷ Export ؀ڥʹԠͨ֬͡ೝ ͜Ε͚ͩͰ৭ʑ΍ͬͯ͘ΕΔ

Slide 47

Slide 47 text

·ͱΊ 47

Slide 48

Slide 48 text

● ϩάͱτϨʔεͷඥ෇͚Λউखʹ΍ͬͯ͘ΕΔ ● Bridge ʹΑͬͯطଘͷϩάϥΠϒϥϦͷࠩ෼Λٵऩ ● Local Ͱ OTLP Ͱు͖ग़͢͜ͱͰɺීஈͷϩʔΧϧ։ൃͰ΋ϩάͱ τϨʔεΛඥ͍ͮͯΈΕΔ ● ೚ҙͷม׵ॲཧΛ processor ͱ࣮ͯ͠૷Ͱ͖Δ ·ͱΊ 48 48 ศརػೳ͕੝Γͩ͘͞ΜʂOpenTelemetry Logger Λ࢖͍͜ͳͦ͏ʂ