diff --git a/README.md b/README.md index 7ef95ba..5a6cbda 100644 --- a/README.md +++ b/README.md @@ -226,3 +226,37 @@ func (s *svc) GetDevice(ctx context.Context, id int) (*Device, error) { return device } ``` + +With context you can also expose more relevant span names: + +```go + // Define a function to build meaningful span name from context + formatSpanName := func(ctx context.Context, baseName string) string { + ctxName := ctx.Value("txName") + if txName, ok := ctxName.(string); ok { + return fmt.Sprintf("%s:%s", txName, baseName) + } + return baseName + } + + // Register our ocsql wrapper for the provided Postgres driver. + driverName, err := ocsql.Register("postgres", ocsql.WithAllTraceOptions(), + ocsql.WithFormatSpanNameFunc(formatSpanName), + ) + if err != nil { + ... + } + + // Connect to a Postgres database using the ocsql driver wrapper. + db, err := sql.Open(driverName, "postgres://localhost:5432/my_database") + if err != nil { + ... + } + + + // Add relevant information to context + ctx := context.WithValue(context.Background(), "txName", "orderCreation") + + // Use context with database + db.ExecContext(ctx, "INSERT INTO order ...") +``` diff --git a/driver.go b/driver.go index 49e51a2..08e8bf5 100644 --- a/driver.go +++ b/driver.go @@ -127,7 +127,8 @@ func (c ocConn) Ping(ctx context.Context) (err error) { if c.options.Ping && (c.options.AllowRoot || trace.FromContext(ctx) != nil) { var span *trace.Span - ctx, span = trace.StartSpan(ctx, "sql:ping", trace.WithSpanKind(trace.SpanKindClient)) + ctx, span = trace.StartSpan(ctx, c.options.formatSpanName(ctx, "sql:ping"), + trace.WithSpanKind(trace.SpanKindClient)) if len(c.options.DefaultAttributes) > 0 { span.AddAttributes(c.options.DefaultAttributes...) } @@ -158,7 +159,8 @@ func (c ocConn) Exec(query string, args []driver.Value) (res driver.Result, err return exec.Exec(query, args) } - ctx, span := trace.StartSpan(context.Background(), "sql:exec", trace.WithSpanKind(trace.SpanKindClient)) + ctx, span := trace.StartSpan(context.Background(), c.options.formatSpanName(context.Background(), "sql:exec"), + trace.WithSpanKind(trace.SpanKindClient)) attrs := make([]trace.Attribute, 0, len(c.options.DefaultAttributes)+2) attrs = append(attrs, c.options.DefaultAttributes...) attrs = append( @@ -200,11 +202,12 @@ func (c ocConn) ExecContext(ctx context.Context, query string, args []driver.Nam return execCtx.ExecContext(ctx, query, args) } + spanName := c.options.formatSpanName(ctx, "sql:exec") var span *trace.Span if parentSpan == nil { - ctx, span = trace.StartSpan(ctx, "sql:exec", trace.WithSpanKind(trace.SpanKindClient)) + ctx, span = trace.StartSpan(ctx, spanName, trace.WithSpanKind(trace.SpanKindClient)) } else { - _, span = trace.StartSpan(ctx, "sql:exec", trace.WithSpanKind(trace.SpanKindClient)) + _, span = trace.StartSpan(ctx, spanName, trace.WithSpanKind(trace.SpanKindClient)) } attrs := append([]trace.Attribute(nil), c.options.DefaultAttributes...) if c.options.Query { @@ -238,7 +241,8 @@ func (c ocConn) Query(query string, args []driver.Value) (rows driver.Rows, err return queryer.Query(query, args) } - ctx, span := trace.StartSpan(context.Background(), "sql:query", trace.WithSpanKind(trace.SpanKindClient)) + ctx, span := trace.StartSpan(context.Background(), c.options.formatSpanName(context.Background(), "sql:query"), + trace.WithSpanKind(trace.SpanKindClient)) attrs := make([]trace.Attribute, 0, len(c.options.DefaultAttributes)+2) attrs = append(attrs, c.options.DefaultAttributes...) attrs = append( @@ -283,9 +287,11 @@ func (c ocConn) QueryContext(ctx context.Context, query string, args []driver.Na var span *trace.Span if parentSpan == nil { - ctx, span = trace.StartSpan(ctx, "sql:query", trace.WithSpanKind(trace.SpanKindClient)) + ctx, span = trace.StartSpan(ctx, c.options.formatSpanName(ctx, "sql:query"), + trace.WithSpanKind(trace.SpanKindClient)) } else { - _, span = trace.StartSpan(ctx, "sql:query", trace.WithSpanKind(trace.SpanKindClient)) + _, span = trace.StartSpan(ctx, c.options.formatSpanName(ctx, "sql:query"), + trace.WithSpanKind(trace.SpanKindClient)) } attrs := append([]trace.Attribute(nil), c.options.DefaultAttributes...) if c.options.Query { @@ -316,7 +322,8 @@ func (c ocConn) Prepare(query string) (stmt driver.Stmt, err error) { defer recordCallStats(context.Background(), "go.sql.prepare")(err) if c.options.AllowRoot { - _, span := trace.StartSpan(context.Background(), "sql:prepare", trace.WithSpanKind(trace.SpanKindClient)) + _, span := trace.StartSpan(context.Background(), c.options.formatSpanName(context.Background(), "sql:prepare"), + trace.WithSpanKind(trace.SpanKindClient)) attrs := make([]trace.Attribute, 0, len(c.options.DefaultAttributes)+1) attrs = append(attrs, c.options.DefaultAttributes...) attrs = append(attrs, attrMissingContext) @@ -354,7 +361,8 @@ func (c *ocConn) PrepareContext(ctx context.Context, query string) (stmt driver. var span *trace.Span attrs := append([]trace.Attribute(nil), c.options.DefaultAttributes...) if c.options.AllowRoot || trace.FromContext(ctx) != nil { - ctx, span = trace.StartSpan(ctx, "sql:prepare", trace.WithSpanKind(trace.SpanKindClient)) + ctx, span = trace.StartSpan(ctx, c.options.formatSpanName(ctx, "sql:prepare"), + trace.WithSpanKind(trace.SpanKindClient)) if c.options.Query { attrs = append(attrs, trace.StringAttribute("sql.query", query)) } @@ -396,11 +404,10 @@ func (c *ocConn) BeginTx(ctx context.Context, opts driver.TxOptions) (tx driver. if ctx == nil || ctx == context.TODO() { ctx = context.Background() - _, span = trace.StartSpan(ctx, "sql:begin_transaction", trace.WithSpanKind(trace.SpanKindClient)) attrs = append(attrs, attrMissingContext) - } else { - _, span = trace.StartSpan(ctx, "sql:begin_transaction", trace.WithSpanKind(trace.SpanKindClient)) } + _, span = trace.StartSpan(ctx, c.options.formatSpanName(ctx, "sql:begin_transaction"), + trace.WithSpanKind(trace.SpanKindClient)) defer func() { if len(attrs) > 0 { span.AddAttributes(attrs...) @@ -441,7 +448,8 @@ type ocResult struct { func (r ocResult) LastInsertId() (id int64, err error) { if r.options.LastInsertID { - _, span := trace.StartSpan(r.ctx, "sql:last_insert_id", trace.WithSpanKind(trace.SpanKindClient)) + _, span := trace.StartSpan(r.ctx, r.options.formatSpanName(r.ctx, "sql:last_insert_id"), + trace.WithSpanKind(trace.SpanKindClient)) if len(r.options.DefaultAttributes) > 0 { span.AddAttributes(r.options.DefaultAttributes...) } @@ -457,7 +465,8 @@ func (r ocResult) LastInsertId() (id int64, err error) { func (r ocResult) RowsAffected() (cnt int64, err error) { if r.options.RowsAffected { - _, span := trace.StartSpan(r.ctx, "sql:rows_affected", trace.WithSpanKind(trace.SpanKindClient)) + _, span := trace.StartSpan(r.ctx, r.options.formatSpanName(r.ctx, "sql:rows_affected"), + trace.WithSpanKind(trace.SpanKindClient)) if len(r.options.DefaultAttributes) > 0 { span.AddAttributes(r.options.DefaultAttributes...) } @@ -485,7 +494,8 @@ func (s ocStmt) Exec(args []driver.Value) (res driver.Result, err error) { return s.parent.Exec(args) } - ctx, span := trace.StartSpan(context.Background(), "sql:exec", trace.WithSpanKind(trace.SpanKindClient)) + ctx, span := trace.StartSpan(context.Background(), s.options.formatSpanName(context.Background(), "sql:exec"), + trace.WithSpanKind(trace.SpanKindClient)) attrs := make([]trace.Attribute, 0, len(s.options.DefaultAttributes)+2) attrs = append(attrs, s.options.DefaultAttributes...) attrs = append( @@ -532,7 +542,8 @@ func (s ocStmt) Query(args []driver.Value) (rows driver.Rows, err error) { return s.parent.Query(args) } - ctx, span := trace.StartSpan(context.Background(), "sql:query", trace.WithSpanKind(trace.SpanKindClient)) + ctx, span := trace.StartSpan(context.Background(), s.options.formatSpanName(context.Background(), "sql:query"), + trace.WithSpanKind(trace.SpanKindClient)) attrs := make([]trace.Attribute, 0, len(s.options.DefaultAttributes)+2) attrs = append(attrs, s.options.DefaultAttributes...) attrs = append( @@ -572,11 +583,12 @@ func (s ocStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (res return s.parent.(driver.StmtExecContext).ExecContext(ctx, args) } + spanName := s.options.formatSpanName(ctx, "sql:exec") var span *trace.Span if parentSpan == nil { - ctx, span = trace.StartSpan(ctx, "sql:exec", trace.WithSpanKind(trace.SpanKindClient)) + ctx, span = trace.StartSpan(ctx, spanName, trace.WithSpanKind(trace.SpanKindClient)) } else { - _, span = trace.StartSpan(ctx, "sql:exec", trace.WithSpanKind(trace.SpanKindClient)) + _, span = trace.StartSpan(ctx, spanName, trace.WithSpanKind(trace.SpanKindClient)) } attrs := append([]trace.Attribute(nil), s.options.DefaultAttributes...) if s.options.Query { @@ -613,9 +625,11 @@ func (s ocStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (row var span *trace.Span if parentSpan == nil { - ctx, span = trace.StartSpan(ctx, "sql:query", trace.WithSpanKind(trace.SpanKindClient)) + ctx, span = trace.StartSpan(ctx, s.options.formatSpanName(ctx, "sql:query"), + trace.WithSpanKind(trace.SpanKindClient)) } else { - _, span = trace.StartSpan(ctx, "sql:query", trace.WithSpanKind(trace.SpanKindClient)) + _, span = trace.StartSpan(ctx, s.options.formatSpanName(ctx, "sql:query"), + trace.WithSpanKind(trace.SpanKindClient)) } attrs := append([]trace.Attribute(nil), s.options.DefaultAttributes...) if s.options.Query { @@ -730,7 +744,8 @@ func (r ocRows) Columns() []string { func (r ocRows) Close() (err error) { if r.options.RowsClose { - _, span := trace.StartSpan(r.ctx, "sql:rows_close", trace.WithSpanKind(trace.SpanKindClient)) + _, span := trace.StartSpan(r.ctx, r.options.formatSpanName(r.ctx, "sql:rows_close"), + trace.WithSpanKind(trace.SpanKindClient)) if len(r.options.DefaultAttributes) > 0 { span.AddAttributes(r.options.DefaultAttributes...) } @@ -746,7 +761,8 @@ func (r ocRows) Close() (err error) { func (r ocRows) Next(dest []driver.Value) (err error) { if r.options.RowsNext { - _, span := trace.StartSpan(r.ctx, "sql:rows_next", trace.WithSpanKind(trace.SpanKindClient)) + _, span := trace.StartSpan(r.ctx, r.options.formatSpanName(r.ctx, "sql:rows_next"), + trace.WithSpanKind(trace.SpanKindClient)) if len(r.options.DefaultAttributes) > 0 { span.AddAttributes(r.options.DefaultAttributes...) } @@ -802,7 +818,8 @@ type ocTx struct { func (t ocTx) Commit() (err error) { defer recordCallStats(context.Background(), "go.sql.commit")(err) - _, span := trace.StartSpan(t.ctx, "sql:commit", trace.WithSpanKind(trace.SpanKindClient)) + _, span := trace.StartSpan(t.ctx, t.options.formatSpanName(t.ctx, "sql:commit"), + trace.WithSpanKind(trace.SpanKindClient)) if len(t.options.DefaultAttributes) > 0 { span.AddAttributes(t.options.DefaultAttributes...) } @@ -818,7 +835,8 @@ func (t ocTx) Commit() (err error) { func (t ocTx) Rollback() (err error) { defer recordCallStats(context.Background(), "go.sql.rollback")(err) - _, span := trace.StartSpan(t.ctx, "sql:rollback", trace.WithSpanKind(trace.SpanKindClient)) + _, span := trace.StartSpan(t.ctx, t.options.formatSpanName(t.ctx, "sql:rollback"), + trace.WithSpanKind(trace.SpanKindClient)) if len(t.options.DefaultAttributes) > 0 { span.AddAttributes(t.options.DefaultAttributes...) } diff --git a/options.go b/options.go index e82cac7..0238eee 100644 --- a/options.go +++ b/options.go @@ -1,6 +1,8 @@ package ocsql import ( + "context" + "go.opencensus.io/trace" ) @@ -53,12 +55,26 @@ type TraceOptions struct { // DisableErrSkip, if set to true, will suppress driver.ErrSkip errors in spans. DisableErrSkip bool + + // FormatSpanName holds the function to use for generating the span name + // from the information found in the context. + FormatSpanName func(ctx context.Context, baseName string) string +} + +// formatSpanName decorates span name +func (o *TraceOptions) formatSpanName(ctx context.Context, baseName string) string { + if o.FormatSpanName != nil { + return o.FormatSpanName(ctx, baseName) + } + return baseName } // WithAllTraceOptions enables all available trace options. func WithAllTraceOptions() TraceOption { return func(o *TraceOptions) { + f := o.FormatSpanName *o = AllTraceOptions + o.FormatSpanName = f } } @@ -166,3 +182,11 @@ func WithDisableErrSkip(b bool) TraceOption { o.DisableErrSkip = b } } + +// WithFormatSpanNameFunc enables custom span names, built with information from the context. +// When context is not available context.Background() is used. +func WithFormatSpanNameFunc(f func(ctx context.Context, baseName string) string) TraceOption { + return func(o *TraceOptions) { + o.FormatSpanName = f + } +}