Documentation
¶
Overview ¶
Package contractkit provides runtime helpers used by the per-package mock_gen.go file forge generates from contract.go.
Scope ¶
As of the observe.* migration, contractkit's surface is the mock-side helpers (Recorder + MockNotSet) only. The middleware/tracing/metrics helpers (LogCall, TraceStart, Metrics, Record) historically lived here to support the per-method middleware_gen.go / tracing_gen.go / metrics_gen.go wrappers; those wrappers were removed in favour of Connect interceptors + opt-in helpers in forge/pkg/observe. The helpers themselves remain in this package for backward compatibility with any user code that imported them directly.
The mock side ¶
- Recorder is embedded by every Mock<Iface> struct. Tests assert against captured calls via m.CallCount(...) / m.Calls(...).
- MockNotSet returns the canonical "<MockName>.<Method>Func not set" error string that fallthrough mock methods emit when the user hasn't set the corresponding XxxFunc field. The format is locked by TestMockNotSet_FingerprintLocked because dogfood projects assert on the substring.
Where the other helpers went ¶
The non-mock helpers — LogCallErr / LogCall / TraceStart / RecordSpanError / NewMetrics / RecordCall / RecordDuration / RecordError — are still present here for compile-time stability. New code should prefer the equivalent in forge/pkg/observe:
- observe.LogCall replaces contractkit.LogCallErr / LogCall.
- observe.TraceCall replaces contractkit.TraceStart + RecordSpanError.
- observe.NewCallMetrics + (*CallMetrics).RecordCall replaces contractkit.NewMetrics + the trio of Record* methods.
observe.* is also where the Connect interceptors live, which is usually the right level of granularity for new projects.
Index ¶
- func LogCall(logger *slog.Logger, method string, start time.Time)
- func LogCallErr(logger *slog.Logger, method string, start time.Time, err error)
- func MockNotSet(mockName, method string) error
- func RecordSpanError(span trace.Span, err error)
- func TraceStart(ctx context.Context, tracer trace.Tracer, name string) (context.Context, trace.Span)
- type Call
- type Metrics
- type Recorder
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func LogCall ¶
LogCall emits a single slog.Info record summarising a wrapped method call that does NOT return an error. start should be captured immediately before the inner call.
The record is identical in shape to the previous generated per-method log line for void methods:
logger.Info("<method>", "duration", time.Since(start))
func LogCallErr ¶
LogCallErr emits a single slog.Info record summarising a wrapped method call that returns an error. start should be captured immediately before the inner call; err is the method's terminal error result (which may be nil — the attribute is always emitted to match the previous generated behaviour).
The record is identical in shape to the previous generated per-method log line:
logger.Info("<method>", "duration", time.Since(start), "error", err)
Always-emit-error semantics are part of the locked behavioural fingerprint (see TestLogCallErr_FingerprintLocked).
func MockNotSet ¶
MockNotSet returns the canonical "func field not set" error used by every Forge-generated mock when a method is invoked but the corresponding XxxFunc field has not been assigned by the test.
The exact format string — "<MockName>.<Method>Func not set" — is part of the public surface. Tests in dogfood projects assert on this substring; the format is locked by TestMockNotSet_FingerprintLocked.
Example (generated):
func (m *MockService) Send(ctx context.Context, args SendArgs) (SendResult, error) {
m.Record("Send", ctx, args)
if m.SendFunc != nil {
return m.SendFunc(ctx, args)
}
return SendResult{}, contractkit.MockNotSet("MockService", "Send")
}
func RecordSpanError ¶
RecordSpanError records err on span if err is non-nil and sets the span status to codes.Error with err.Error() as the description.
This is identical in behaviour to the previous generated code's per-method block:
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
}
nil-safe on err. Does nothing for a nil span.
func TraceStart ¶
func TraceStart(ctx context.Context, tracer trace.Tracer, name string) (context.Context, trace.Span)
TraceStart starts a span on tracer with the given operation name. If ctx is nil, context.Background() is used (matching the previous generated code's fallback for context-less methods).
The returned context carries the span and should be propagated to the inner method call (or held as the call's stand-in context for methods without a context parameter).
Callers are responsible for calling span.End(); the canonical pattern is:
ctx, span := contractkit.TraceStart(ctx, tracer, "Service.Send") defer span.End() err := inner.Send(ctx, ...) contractkit.RecordSpanError(span, err) return err
Types ¶
type Call ¶
Call captures a single recorded invocation of a mock method.
Args is a snapshot of the positional arguments passed to the mock at the moment Record was called. Time is the wall-clock time of the call (UTC monotonic via time.Now), useful for ordering assertions across methods.
type Metrics ¶
type Metrics struct {
// contains filtered or unexported fields
}
Metrics groups the three OpenTelemetry instruments used by every metric_gen.go wrapper: a call-count counter, an error-count counter, and a duration histogram (in seconds).
The instruments are named according to the canonical "<package>.calls", "<package>.errors", "<package>.duration" pattern that the previous generated wrapper emitted. Callers construct a Metrics via NewMetrics and embed it in the per-interface generated wrapper.
func NewMetrics ¶
NewMetrics constructs a Metrics by creating three instruments on meter using the canonical "<packageName>.{calls,errors,duration}" names and the same descriptions/units that the previous generated code used.
Errors from meter.Int64Counter / Float64Histogram are silently dropped (mirroring the previous generated code, which discarded them via _, _ assignments). This preserves the existing behavioural fingerprint.
func (*Metrics) RecordCall ¶
RecordCall registers a method invocation on the call-count counter with a "method" attribute. Should be called immediately before invoking the inner method (matching the previous generated code's ordering: increment count, then call inner, then record duration).
nil-safe on the receiver.
func (*Metrics) RecordDuration ¶
RecordDuration registers the elapsed duration since start on the duration histogram with a "method" attribute. Should be called immediately after the inner method returns.
nil-safe on the receiver.
type Recorder ¶
type Recorder struct {
// contains filtered or unexported fields
}
Recorder is a thread-safe per-method call log embedded in every mock produced by forge's mock_gen.go. Tests use it to assert that a mock method was invoked the expected number of times with the expected arguments.
The zero value is ready to use.
func (*Recorder) CallCount ¶
CallCount returns the number of recorded calls for method. Returns 0 if the method was never called. Cheap (no allocation).
func (*Recorder) Calls ¶
Calls returns the ordered list of recorded calls for method. Returns nil if Record has never been called for that method. The returned slice (and each Call's Args) is a deep copy — callers may mutate it freely without affecting the recorder's state.