@@ -8,6 +8,10 @@ import (
88 "github.com/shortlink-org/go-sdk/cqrs/bus"
99 "github.com/shortlink-org/go-sdk/logger"
1010 "github.com/shortlink-org/go-sdk/saga"
11+ "go.opentelemetry.io/otel"
12+ "go.opentelemetry.io/otel/attribute"
13+ otelcodes "go.opentelemetry.io/otel/codes"
14+ "go.opentelemetry.io/otel/trace"
1115 "google.golang.org/protobuf/types/known/timestamppb"
1216
1317 "github.com/shortlink-org/shortlink/boundaries/metadata/internal/domain"
@@ -88,12 +92,29 @@ func (uc *UC) Add(ctx context.Context, linkURL string) (*v1.Meta, error) { //nol
8892
8993 _ , errs = sagaSetMetadata .AddStep (SAGA_STEP_ADD_META ).
9094 Then (func (ctx context.Context ) error {
95+ ctx , span := otel .Tracer ("metadata.uc.parser" ).Start (ctx , "saga: SAGA_STEP_ADD_META" ,
96+ trace .WithSpanKind (trace .SpanKindInternal ),
97+ )
98+ defer span .End ()
99+
100+ span .SetAttributes (
101+ attribute .String ("step" , SAGA_STEP_ADD_META ),
102+ attribute .String ("status" , "run" ),
103+ attribute .String ("link.url" , linkURL ),
104+ )
105+
91106 m , stepErr := uc .parserUC .Set (ctx , linkURL )
92107 if stepErr != nil {
108+ span .RecordError (stepErr )
109+ span .SetStatus (otelcodes .Error , stepErr .Error ())
93110 return domainerrors .Normalize (OpParserSet , stepErr )
94111 }
95112
96113 meta = m
114+ span .SetAttributes (
115+ attribute .String ("meta.id" , m .GetId ()),
116+ )
117+ span .SetStatus (otelcodes .Ok , "Metadata parsed successfully" )
97118
98119 return nil
99120 }).Build ()
@@ -104,11 +125,25 @@ func (uc *UC) Add(ctx context.Context, linkURL string) (*v1.Meta, error) { //nol
104125
105126 _ , errs = sagaSetMetadata .AddStep (SAGA_STEP_ADD_SCREENSHOT ).
106127 Then (func (ctx context.Context ) error {
128+ ctx , span := otel .Tracer ("metadata.uc.screenshot" ).Start (ctx , "saga: SAGA_STEP_ADD_SCREENSHOT" ,
129+ trace .WithSpanKind (trace .SpanKindInternal ),
130+ )
131+ defer span .End ()
132+
133+ span .SetAttributes (
134+ attribute .String ("step" , SAGA_STEP_ADD_SCREENSHOT ),
135+ attribute .String ("status" , "run" ),
136+ attribute .String ("link.url" , linkURL ),
137+ )
138+
107139 stepErr := uc .screenshotUC .Set (ctx , linkURL )
108140 if stepErr != nil {
141+ span .RecordError (stepErr )
142+ span .SetStatus (otelcodes .Error , stepErr .Error ())
109143 return domainerrors .Normalize (OpScreenshotSet , stepErr )
110144 }
111145
146+ span .SetStatus (otelcodes .Ok , "Screenshot processing started successfully" )
112147 return nil
113148 }).Build ()
114149
@@ -119,19 +154,38 @@ func (uc *UC) Add(ctx context.Context, linkURL string) (*v1.Meta, error) { //nol
119154 _ , errs = sagaSetMetadata .AddStep (SAGA_STEP_GET_SCREENSHOT_URL ).
120155 Needs (SAGA_STEP_ADD_SCREENSHOT , SAGA_STEP_ADD_META ).
121156 Then (func (ctx context.Context ) error {
157+ ctx , span := otel .Tracer ("metadata.uc.screenshot" ).Start (ctx , "saga: SAGA_STEP_GET_SCREENSHOT_URL" ,
158+ trace .WithSpanKind (trace .SpanKindInternal ),
159+ )
160+ defer span .End ()
161+
162+ span .SetAttributes (
163+ attribute .String ("step" , SAGA_STEP_GET_SCREENSHOT_URL ),
164+ attribute .String ("status" , "run" ),
165+ attribute .String ("link.url" , linkURL ),
166+ )
167+
122168 // Try to get screenshot URL, but don't fail if screenshot is not available yet
123169 url , stepErr := uc .screenshotUC .Get (ctx , linkURL )
124170 if stepErr != nil {
125171 // Log warning but continue without screenshot URL
172+ span .AddEvent ("Screenshot URL not available yet, continuing without it" )
173+ span .SetAttributes (attribute .Bool ("screenshot.available" , false ))
126174 uc .log .WarnWithContext (ctx , "Failed to get screenshot URL, continuing without it" ,
127175 slog .String ("error" , stepErr .Error ()),
128176 slog .String ("url" , linkURL ),
129177 )
130178
179+ span .SetStatus (otelcodes .Ok , "Continuing without screenshot URL" )
131180 return nil // Continue saga execution even if screenshot URL is not available
132181 }
133182
134183 meta .ImageUrl = url .String ()
184+ span .SetAttributes (
185+ attribute .String ("screenshot.url" , url .String ()),
186+ attribute .Bool ("screenshot.available" , true ),
187+ )
188+ span .SetStatus (otelcodes .Ok , "Screenshot URL retrieved successfully" )
135189
136190 return nil
137191 }).Build ()
@@ -143,10 +197,24 @@ func (uc *UC) Add(ctx context.Context, linkURL string) (*v1.Meta, error) { //nol
143197 _ , errs = sagaSetMetadata .AddStep (SAGA_STEP_UPDATE_META ).
144198 Needs (SAGA_STEP_GET_SCREENSHOT_URL ).
145199 Then (func (ctx context.Context ) error {
200+ ctx , span := otel .Tracer ("metadata.uc.store" ).Start (ctx , "saga: SAGA_STEP_UPDATE_META" ,
201+ trace .WithSpanKind (trace .SpanKindInternal ),
202+ )
203+ defer span .End ()
204+
205+ span .SetAttributes (
206+ attribute .String ("step" , SAGA_STEP_UPDATE_META ),
207+ attribute .String ("status" , "run" ),
208+ attribute .String ("link.url" , linkURL ),
209+ attribute .String ("meta.id" , meta .GetId ()),
210+ )
211+
146212 // Update meta in store with ImageUrl after screenshot URL is retrieved (or without it if screenshot failed)
147213 // This ensures meta is always persisted with the latest state
148214 storeErr := uc .parserUC .MetaStore .Store .Add (ctx , meta )
149215 if storeErr != nil {
216+ span .RecordError (storeErr )
217+ span .SetStatus (otelcodes .Error , storeErr .Error ())
150218 uc .log .ErrorWithContext (ctx , "Failed to update meta in store" ,
151219 slog .String ("error" , storeErr .Error ()),
152220 slog .String ("url" , linkURL ),
@@ -155,6 +223,10 @@ func (uc *UC) Add(ctx context.Context, linkURL string) (*v1.Meta, error) { //nol
155223 return domainerrors .Normalize (OpStoreUpdate , storeErr )
156224 }
157225
226+ span .SetAttributes (
227+ attribute .String ("meta.image_url" , meta .GetImageUrl ()),
228+ )
229+ span .SetStatus (otelcodes .Ok , "Meta updated in store successfully" )
158230 uc .log .InfoWithContext (ctx , "Meta updated in store" ,
159231 slog .String ("url" , linkURL ),
160232 slog .String ("image_url" , meta .GetImageUrl ()),
@@ -174,6 +246,21 @@ func (uc *UC) Add(ctx context.Context, linkURL string) (*v1.Meta, error) { //nol
174246
175247 // Publish MetadataExtracted event using EventBus (canonical name: metadata.metadata.extracted.v1)
176248 // Published after saga completion to ensure all enrichment (including screenshot) is complete
249+ ctx , span := otel .Tracer ("metadata.uc.event" ).Start (ctx , "metadata.uc.publish_metadata_extracted" ,
250+ trace .WithSpanKind (trace .SpanKindProducer ),
251+ )
252+ defer span .End ()
253+
254+ span .SetAttributes (
255+ attribute .String ("messaging.system" , "kafka" ),
256+ attribute .String ("messaging.destination" , domain .MetadataExtractedTopic ),
257+ attribute .String ("messaging.destination_kind" , "topic" ),
258+ attribute .String ("messaging.operation" , "publish" ),
259+ attribute .String ("event.type" , domain .MetadataExtractedTopic ),
260+ attribute .String ("link.url" , linkURL ),
261+ attribute .String ("meta.id" , meta .GetId ()),
262+ )
263+
177264 event := & v1.MetadataExtracted {
178265 Id : meta .GetId (),
179266 ImageUrl : meta .GetImageUrl (),
@@ -183,13 +270,19 @@ func (uc *UC) Add(ctx context.Context, linkURL string) (*v1.Meta, error) { //nol
183270 }
184271
185272 if err := uc .eventBus .Publish (ctx , event ); err != nil {
273+ span .RecordError (err )
274+ span .SetStatus (otelcodes .Error , err .Error ())
186275 uc .log .ErrorWithContext (ctx , "Failed to publish metadata extracted event" ,
187276 slog .String ("error" , err .Error ()),
188277 slog .String ("event_type" , domain .MetadataExtractedTopic ),
189278 slog .String ("url" , linkURL ),
190279 )
191280 // Don't fail the operation if event publishing fails
192281 } else {
282+ span .SetAttributes (
283+ attribute .String ("event_type" , domain .MetadataExtractedTopic ),
284+ )
285+ span .SetStatus (otelcodes .Ok , "Metadata extracted event published successfully" )
193286 uc .log .InfoWithContext (ctx , "Metadata extracted event published successfully" ,
194287 slog .String ("event_type" , domain .MetadataExtractedTopic ),
195288 slog .String ("url" , linkURL ),
0 commit comments