Skip to content

Commit acad65f

Browse files
committed
add spans for tracer in onstarthook context
1 parent d41f125 commit acad65f

File tree

2 files changed

+61
-4
lines changed

2 files changed

+61
-4
lines changed

pkg/gofr/gofr.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"strings"
1313

1414
"github.com/gorilla/mux"
15+
"go.opentelemetry.io/otel"
1516
"golang.org/x/sync/errgroup"
1617

1718
"gofr.dev/pkg/gofr/config"
@@ -21,12 +22,15 @@ import (
2122
"gofr.dev/pkg/gofr/metrics"
2223
"gofr.dev/pkg/gofr/migration"
2324
"gofr.dev/pkg/gofr/service"
25+
"gofr.dev/pkg/gofr/version"
2426
)
2527

2628
const (
2729
configLocation = "./configs"
2830
)
2931

32+
var errStartupHookPanic = errors.New("startup hook panicked")
33+
3034
// App is the main application in the GoFr framework.
3135
type App struct {
3236
// Config can be used by applications to fetch custom configurations from environment or file.
@@ -50,16 +54,36 @@ type App struct {
5054
}
5155

5256
func (a *App) runOnStartHooks(ctx context.Context) error {
57+
// Create a span for the startup hooks execution,
58+
tr := otel.GetTracerProvider().Tracer("gofr-" + version.Framework)
59+
60+
ctx, span := tr.Start(ctx, "startup-hooks")
61+
defer span.End()
62+
5363
// Use the existing newContext function with noopRequest
5464
gofrCtx := newContext(nil, noopRequest{}, a.container)
5565

5666
// Set the context for cancellation support
5767
gofrCtx.Context = ctx
5868

59-
for _, hook := range a.onStartHooks {
60-
if err := hook(gofrCtx); err != nil {
61-
a.Logger().Errorf("OnStart hook failed: %v", err)
62-
return err
69+
for i, hook := range a.onStartHooks {
70+
// Add panic recovery to prevent entire application crash
71+
var hookErr error
72+
73+
func() {
74+
defer func() {
75+
if r := recover(); r != nil {
76+
a.Logger().Errorf("OnStart hook %d panicked: %v", i, r)
77+
hookErr = fmt.Errorf("hook %d: %w: %v", i, errStartupHookPanic, r)
78+
}
79+
}()
80+
81+
hookErr = hook(gofrCtx)
82+
}()
83+
84+
if hookErr != nil {
85+
a.Logger().Errorf("OnStart hook failed: %v", hookErr)
86+
return hookErr
6387
}
6488

6589
// Check if context was canceled

pkg/gofr/gofr_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,4 +1203,37 @@ func TestApp_OnStart(t *testing.T) {
12031203

12041204
require.ErrorIs(t, err, errHookFailed, "Expected an error from runOnStartHooks")
12051205
})
1206+
1207+
// Test case 3: Verify trace context is properly set
1208+
t.Run("trace context", func(t *testing.T) {
1209+
app := New()
1210+
1211+
var traceID string
1212+
1213+
app.OnStart(func(ctx *Context) error {
1214+
// Verify that trace context is not empty
1215+
traceID = ctx.GetCorrelationID()
1216+
return nil
1217+
})
1218+
1219+
err := app.runOnStartHooks(t.Context())
1220+
1221+
require.NoError(t, err, "Expected no error from runOnStartHooks")
1222+
assert.NotEmpty(t, traceID, "Expected traceID to be set in OnStart hook context")
1223+
assert.NotEqual(t, "00000000000000000000000000000000", traceID, "Expected valid traceID, not zero value")
1224+
})
1225+
1226+
// Test case 4: Verify panic recovery
1227+
t.Run("panic recovery", func(t *testing.T) {
1228+
app := New()
1229+
1230+
app.OnStart(func(_ *Context) error {
1231+
panic("test panic")
1232+
})
1233+
1234+
err := app.runOnStartHooks(t.Context())
1235+
1236+
require.Error(t, err, "Expected error from panicked hook")
1237+
assert.Contains(t, err.Error(), "panicked", "Expected error message to mention panic")
1238+
})
12061239
}

0 commit comments

Comments
 (0)