contrib/aerospike/aerospike-client-go.v7

contrib/aerospike/aerospike-client-go.v7

Those integration are enabled by having the following import in the project’s orchestrion.tool.go file:

import (
	_ "github.com/DataDog/orchestrion"

	_ "github.com/DataDog/dd-trace-go/contrib/aerospike/aerospike-client-go.v7/v2" // integration
	//...
)

Aerospike client for Go.

Client

Join Point
Definition of aerospike.Client
Advice
Introduce new declarations:
// Using the following synthetic imports:
import (
	context "context"
	goid "github.com/petermattis/goid"
	sync "sync"
	tracing "github.com/DataDog/dd-trace-go/contrib/aerospike/aerospike-client-go.v7/v2/internal/tracing"
)
// __dd_aerospike_ctxs maps goroutine ID → context.Context.
// Keys are short-lived: WithContext stores a context and the very next
// instrumented method call on that goroutine retrieves and deletes it via
// LoadAndDelete in __dd_aerospike_get_ctx.
//
// Goroutine-exit hazard: if the goroutine exits after WithContext but
// before any instrumented method fires, the entry is never consumed and
// persists until the Go runtime recycles that goroutine ID.  The next
// Aerospike call on the new goroutine with the same ID will then pick up
// a stale context.  There is no Go API to hook goroutine exit, so this
// is an inherent limitation of the goroutine-ID approach.  Mitigation:
// always chain WithContext with the very next instrumented call in the
// same goroutine — do not store the returned *Client and use it later.
var __dd_aerospike_ctxs sync.Map // map[int64]context.Context

// __dd_aerospike_active_key is an unexported context key injected by
// Orchestrion into the aerospike-client-go package.  It is embedded in
// the goroutine's context to signal that an instrumented Aerospike call
// is already in progress on this goroutine, preventing double-spans when
// a public method delegates internally to another public method that is
// also in the advice list (e.g. Query → QueryPartitions).
// Because the type is unexported and lives in the aerospike-client-go
// package, no external code can produce a context with this key set.
type __dd_aerospike_active_key struct{}

// WithContext stores ctx so that the immediately following method call
// on this client creates its span as a child of the span in ctx.
// It MUST be chained directly with the method call in the same goroutine:
//
//   go func() { client.WithContext(ctx).Put(nil, key, bins) }()
//
// Storing the returned *Client and calling the method from a different
// goroutine will not propagate the context; call WithContext inside the
// goroutine that executes the method.
func (c *Client) WithContext(ctx context.Context) *Client {
	__dd_aerospike_ctxs.Store(goid.Get(), ctx)
	return c
}

// __dd_aerospike_get_ctx retrieves and removes the context stored by
// the most recent WithContext call on this goroutine.  Returns
// context.Background() when none was stored, which lets the tracer's
// GLS provide same-goroutine parenting automatically.
func __dd_aerospike_get_ctx() context.Context {
	if v, ok := __dd_aerospike_ctxs.LoadAndDelete(goid.Get()); ok {
		return v.(context.Context)
	}
	return context.Background()
}

func __dd_finishAerospikeSpan(span *tracing.Span, err error) {
	tracing.FinishSpan(span, err)
}

Client.Operation.Error

Join Point
Function body
Advice
Prepend statements produced by the following template:
// Using the following synthetic imports:
import (
	context "context"
	goid "github.com/petermattis/goid"
	tracing "github.com/DataDog/dd-trace-go/contrib/aerospike/aerospike-client-go.v7/v2/internal/tracing"
)
{{- $name := .Function.Name -}}
{{- $err := .Function.Result 0 -}}
__dd_ctx := __dd_aerospike_get_ctx()
var __dd_span *tracing.Span
if __dd_ctx.Value(__dd_aerospike_active_key{}) == nil {
	__dd_aerospike_ctxs.Store(goid.Get(), context.WithValue(__dd_ctx, __dd_aerospike_active_key{}, struct{}{}))
	__dd_span = tracing.StartDefaultSpan(__dd_ctx, {{ printf "%q" $name }})
	defer func() {
		__dd_aerospike_ctxs.Delete(goid.Get())
		__dd_finishAerospikeSpan(__dd_span, {{ $err }})
	}()
} else {
	__dd_aerospike_ctxs.Store(goid.Get(), __dd_ctx)
}

Client.Operation.ValueError

Join Point
Function body
Advice
Prepend statements produced by the following template:
// Using the following synthetic imports:
import (
	context "context"
	goid "github.com/petermattis/goid"
	tracing "github.com/DataDog/dd-trace-go/contrib/aerospike/aerospike-client-go.v7/v2/internal/tracing"
)
{{- $name := .Function.Name -}}
{{- $err := .Function.Result 1 -}}
__dd_ctx := __dd_aerospike_get_ctx()
var __dd_span *tracing.Span
if __dd_ctx.Value(__dd_aerospike_active_key{}) == nil {
	__dd_aerospike_ctxs.Store(goid.Get(), context.WithValue(__dd_ctx, __dd_aerospike_active_key{}, struct{}{}))
	__dd_span = tracing.StartDefaultSpan(__dd_ctx, {{ printf "%q" $name }})
	defer func() {
		__dd_aerospike_ctxs.Delete(goid.Get())
		__dd_finishAerospikeSpan(__dd_span, {{ $err }})
	}()
} else {
	__dd_aerospike_ctxs.Store(goid.Get(), __dd_ctx)
}