Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
OpenTelemetry の Log を使いこなそう
Search
Shota Iwami
July 23, 2025
Technology
2k
7
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
OpenTelemetry の Log を使いこなそう
Jagu'e'r オブザーバビリティ分科会 Meetup #3
https://jaguer-o11y-sre.connpass.com/event/359593/
Shota Iwami
July 23, 2025
More Decks by Shota Iwami
See All by Shota Iwami
モノレポにおけるエラー管理 ~Runbook自動生成とチームメンションの最適化
biwashi
2
1k
Monorepo Error Management: Automated Runbooks and Team-Targeted Alert Distribution
biwashi
2
1.1k
スタートアップ創業期を支えるオブザーバビリティ基盤のこれまでとこれから
biwashi
10
1.7k
モノレポ開発のエラー、誰が見る?Datadog で実現する適切なトリアージとエスカレーション
biwashi
7
1.8k
k6を活用した再現性・拡張性の高い負荷試験基盤の構築
biwashi
13
4.3k
Datadogマニアック機能活用術
biwashi
7
4.4k
feature flag と OpenTelemetry
biwashi
7
2.4k
OpenFeatureと自動生成を活用したフィーチャーフラグの宣言的集約管理
biwashi
20
7.4k
Unified Diff 形式の差分から Go AST を構築して feature flag を自動計装する
biwashi
11
1.6k
Other Decks in Technology
See All in Technology
Jitera Company Deck
jitera
0
270
探索・可視化・自動化を一本化 Amazon Quickでデータ活用スピードを上げる方法
koheiyoshikawa
0
170
_NIKKEI_Tech_Talk__勉強会は熱量では続かない___17回続いた輪読会の設計術.pdf
_awache
1
100
AIツールを導入しても生産性はあがらない? カオナビが直面した 3つの壁と乗り越え方。/ Overcoming 3 Barriers to AI-Driven Productivity at kaonavi
kaonavi
0
150
AI時代におけるテストの基礎の再定義 / Rethinking the Fundamentals of Testing in the AI Era
mineo_matsuya
12
3.9k
ファミコンでPHPを動かす / PHP on the Famicom
tomzoh
2
600
複数プロダクトで進めるAI機能実装 ── 実践から得たリアルな学びとロードマップ実現への挑戦 / AICon2026_yanari
rakus_dev
1
270
ここは地獄!つらい朝会を体験することで、チームとしてのより良い振る舞いに気づくワークショップ / The stand-up meeting from hell in the game industry
scrummasudar
0
210
ゴールデンパスは敷いただけでは道にならない ─ 企画部門のエンジニアが技術標準を事業価値に変えるまで
mhrtech
1
260
全社でのソフトウェアサプライチェーン攻撃対策をやってみた with Takumi Guard
z63d
0
260
AI時代のPlaywright活用(システムテストを自動化する ー 実行エンジンにPla ywrightを選んだ理由)
ynisqa1988
2
920
「顧客の声を聞かなければ何も始まらない」 ── 顧客の声から生まれた『AI返信補助機能』の開発プロセス / AICon2026_shikata_imai
rakus_dev
1
260
Featured
See All Featured
New Earth Scene 8
popppiees
3
2.4k
First, design no harm
axbom
PRO
2
1.2k
Code Review Best Practice
trishagee
74
20k
[RailsConf 2023] Rails as a piece of cake
palkan
59
6.8k
A better future with KSS
kneath
240
18k
How to train your dragon (web standard)
notwaldorf
97
6.7k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
380
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
Ethics towards AI in product and experience design
skipperchong
2
330
WENDY [Excerpt]
tessaabrams
11
38k
Google's AI Overviews - The New Search
badams
0
1.1k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
Transcript
4IPUB*XBNJ]1MBUGPSN&OHJOFFS]OFXNP *OD OpenTelemetry ͷ Log Λ͍͜ͳͦ͏ Jagu'e'r ΦϒβʔόϏϦςΟՊձ Meetup #3
1
ؠݟজଠ*XBNJO Platform Engineer newmo, Inc. 2
ؠݟজଠ*XBNJO Platform Engineer Autonomous Driving Vehicle Team? newmo, Inc. 3
Software Design 5݄߸ 4 4 • ͡Ίʹ • OpenTelemetryͱ •
OpenTelemetryͷجຊΞʔΩςΫνϟ • αϯϓϦϯάઓུͱ࣮ • ܭͷछྨͱબج४ • खಈ/ϥΠϒϥϦ/ࣗಈܭ • TraceProvider • MetricProvider • LoggerProvider • ·ͱΊ 4 “OpenTelemetryೖ” Λدߘ͠·ͨ͠
Software Design 5݄߸ 5 “OpenTelemetryೖ” Λدߘ͠·ͨ͠ 5 • ͡Ίʹ •
OpenTelemetryͱ • OpenTelemetryͷجຊΞʔΩςΫνϟ • αϯϓϦϯάઓུͱ࣮ • ܭͷछྨͱબج४ • खಈ/ϥΠϒϥϦ/ࣗಈܭ • TraceProvider • MetricProvider • LoggerProvider • ·ͱΊ 5
LoggerProviderͷར༻ 6
Logger Provider 7 7 • Trace, Metricsͱগ͠ੑ࣭͕ҧ͏ • طଘͷϩΪϯάϥΠϒϥϦͱ Otel
Λ࿈ܞͤ͞ΔͨΊͷ Bridge ػೳΛఏڙ • ޓੑΛอͪͳ͕Β Trace ͱඥ͚Δ Context ͷՃڞ௨ϑΥʔϚοτʹղੳɾม͢Δͨ ΊͷπʔϧΩοτΛఏڙ 7
Logger Provider 8 8 • Trace, Metricsͱগ͠ੑ࣭͕ҧ͏ • طଘͷϩΪϯάϥΠϒϥϦͱ Otel
Λ࿈ܞͤ͞ΔͨΊͷ Bridge ػೳΛఏڙ • ޓੑΛอͪͳ͕Β Trace ͱඥ͚Δ Context ͷՃڞ௨ϑΥʔϚοτʹղੳɾม͢Δͨ ΊͷπʔϧΩοτΛఏڙ 8
Otel log bridge ΛΘͳ͍߹ 9
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 ʹՃ
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 ʹՃ
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 ʹՃ
Otel log bridge Λ͏߹ 13
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 ͢Δ͚ͩ
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 }
Logger Provider 16 16 16
Logger Provider 17 17 17
Logger Provider 18 18 18
Logger Provider 19 19 19
Logger Provider 20 20 20
Logger Provider 21 21 21
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 ͢Δ͚ͩ ͳΜ͔͍͍ײ͡ʹͯ͘͠ΕΔ ͲͷΑ͏ͳΈʁ
Logger Provider ͷ ઃܭͱ෦࣮ 23
Logger Provider ͷઃܭͱ෦࣮ 24 24 24
Logger Provider ͷઃܭͱ෦࣮ 25 25 25
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
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
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 Λ࣮ߦ
Logger Provider ͷઃܭͱ෦࣮ 29 29 29
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
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 ࡞
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 ʹຒΊࠐΉ
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 Λ ॱ࣮࣍ߦ
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 Λ ॱ࣮࣍ߦ
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 Λ ॱ࣮࣍ߦ
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
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
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
Logger Provider ͷઃܭͱ෦࣮ 39 39 39
Logger Provider ͷઃܭͱ෦࣮ 40 40 40 local Ͱ otlp Ͱग़ྗͯ͠
o11y πʔϧͰ trace ͱඥ͚ͮͯ֬ೝ dev/stg/prod Ͱඪ४ग़ྗͰग़ͯ͠ӬଓԽͭͭ͠ϩάΛpipelineͰྲྀͯ֬͠ೝ
Logger Provider ͷઃܭͱ෦࣮ 41 41 41
Logger Provider ͷઃܭͱ෦࣮ 42 42 42 ͍ͭ௨Γ
Logger Provider ͷઃܭͱ෦࣮ 43 43 43 ͍ͭ௨Γ ͬͯΔLogͷܗࣜΛ OtelLogʹม
Logger Provider ͷઃܭͱ෦࣮ 44 44 44 ͍ͭ௨Γ ͬͯΔLogͷܗࣜΛ OtelLogʹม Trace
ใͷநग़ ҙͷ Export
Logger Provider ͷઃܭͱ෦࣮ 45 45 45 ͍ͭ௨Γ ͬͯΔLogͷܗࣜΛ OtelLogʹม Trace
ใͷநग़ ҙͷ Export ڥʹԠͨ֬͡ೝ
Logger Provider ͷઃܭͱ෦࣮ 46 46 46 ͍ͭ௨Γ ͬͯΔLogͷܗࣜΛ OtelLogʹม Trace
ใͷநग़ ҙͷ Export ڥʹԠͨ֬͡ೝ ͜Ε͚ͩͰ৭ʑͬͯ͘ΕΔ
·ͱΊ 47
• ϩάͱτϨʔεͷඥ͚Λউखʹͬͯ͘ΕΔ • Bridge ʹΑͬͯطଘͷϩάϥΠϒϥϦͷࠩΛٵऩ • Local Ͱ OTLP Ͱు͖ग़͢͜ͱͰɺීஈͷϩʔΧϧ։ൃͰϩάͱ
τϨʔεΛඥ͍ͮͯΈΕΔ • ҙͷมॲཧΛ processor ͱ࣮ͯ͠Ͱ͖Δ ·ͱΊ 48 48 ศརػೳ͕Γͩ͘͞ΜʂOpenTelemetry Logger Λ͍͜ͳͦ͏ʂ