feat: add manual telemetry usage example#121
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a runnable example of manual telemetry instrumentation to the example app, demonstrating direct usage of facades.Telemetry() for spans, metrics, propagation, and context-aware logging, and extends the telemetry feature test to assert the new telemetry output.
Changes:
- Add
app/services/telemetry.goimplementing manual spans (users.process,users.consume), metrics, propagation (Inject/Extract), and trace-context logging. - Invoke the new manual telemetry example from the existing
GET /telemetryroute. - Extend the telemetry feature test to assert the new spans and the
users_processed_totalmetric.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| tests/feature/telemetry_test.go | Asserts the additional spans and counter metric produced by the new manual telemetry example. |
| routes/api.go | Executes the manual telemetry example during the /telemetry request so it’s exercised end-to-end. |
| app/services/telemetry.go | New manual telemetry example implementation (custom spans, metrics, propagation, and context-based logging). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
goravel-coder
left a comment
There was a problem hiding this comment.
Review Summary
Clean, well-structured PR — compiles cleanly, follows existing patterns, and adds meaningful end-to-end test coverage. A few suggestions below for consideration.
Suggestions
1. users.validate span should also record error on failure (app/services/telemetry.go:129–134)
When userID == "", the child users.validate span ends without RecordError or SetStatus. In a trace UI, only the parent users.process span will appear red. Recording the error on the child span too would make the example more complete:
if userID == "" {
span.RecordError(errUserIDRequired)
span.SetStatus(telemetry.CodeError, errUserIDRequired.Error())
return errUserIDRequired
}2. The error path of Process is never exercised in tests
The route always passes "1" as user ID, so validate() always succeeds. The counter("result","error") branch at telemetry.go:93 has no test coverage. A separate sub-test or an additional route call with an empty ID would close that gap.
3. Log assertions could be expanded in TestLogs()
Only the pre-existing "test telemetry log" is asserted. The new "user processed" and "user event consumed" messages could be added for completeness.
4. Scope name overlap
scopeName = "goravel" could overlap with the framework's own instrumentation scope in trace backends. Consider "goravel-example" to make the distinction clearer.
Verdict
Approve — the suggestions are non-blocking polish. The PR meets its goal of demonstrating the manual telemetry API in a runnable, tested, commented way.
How about this? |
📑 Description
The example app demonstrates automatic HTTP and gRPC instrumentation, but not the telemetry module's manual API. This adds a runnable, commented example of using
facades.Telemetry()directly.What is changing:
app/services/telemetry.goshowing manual telemetry over the user domain: a custom span with an attribute and an event, a nested child span, error recording (RecordError+SetStatus), span kinds, enriching the active server span viaSpanFromContext, a counter, a histogram, an up-down counter, context propagation across a simulated transport (Propagator().Inject/Extract), and a context-propagated log./telemetryroute invokes it, so the example runs as part of a request.Example:
Processproduces ausers.processspan nested under the request span, andPublish/Consumecarry the trace into ausers.consumespan, showing how to continue a trace across a custom boundary.The telemetry suite asserts the
users.processandusers.consumespans and theusers_processed_totalmetric end to end.✅ Checks