Skip to content

feat: [#726] Add gRPC telemetry instrumentation [4]#1305

Merged
krishankumar01 merged 26 commits intomasterfrom
kkumar-gcc/#726-auto-instrumentation
Dec 23, 2025
Merged

feat: [#726] Add gRPC telemetry instrumentation [4]#1305
krishankumar01 merged 26 commits intomasterfrom
kkumar-gcc/#726-auto-instrumentation

Conversation

@krishankumar01
Copy link
Member

@krishankumar01 krishankumar01 commented Dec 17, 2025

📑 Description

RelatedTo goravel/goravel#726

This PR introduces stats.Handler support to enable metrics emission and trace propagation for both gRPC servers and clients. Specifically, it exposes new NewServerStatsHandler and NewClientStatsHandler utilities via the github.com/framework/telemetry/instrumentation/grpc package.

Registration

You can register these stats handlers using the new ClientStatsHandlerGroups and ServerStatsHandlers methods on the gRPC facade, typically within your custom Service Providers.

Note

These handlers usually depend on the Telemetry facade. If the Telemetry service is not available or registered, the system will log a warning to prevent issues with nil service providers.

Example: Registering in a Service Provider

func (s *GrpcServiceProvider) Boot() {
    // Register a client handler for a specific group (e.g., "user")
    facades.Grpc().ClientStatsHandlerGroups(map[string][]stats.Handler{
        "user": { 
            telemetrygrpc.NewClientStatsHandler(),
        },
    })

    // Register a global server handler
    facades.Grpc().ServerStatsHandlers([]stats.Handler{
        telemetrygrpc.NewServerStatsHandler(),
    })
}

Warning

Important Configuration Note
When registering client handlers, the key you use (e.g., "user") acts as a "group name." For the handler to actually take effect, this same group name must be listed in your config/grpc.go file under the client's stats_handlers array. The framework automatically loads the Stats Handlers assigned to that group key.

Example: config/grpc.go

// In your configuration, you link the "user" group to this client
"clients": map[string]any{
    "user_service": map[string]any{
       "host":         config.Env("GRPC_USER_HOST", "localhost"),
       "port":         config.Env("GRPC_USER_PORT", "50051"),
       "stats_handlers": []string{"user"}, // <--- This key ("user") links to the registration above
    },
},

Bootstrap Configuration

For applications using the new slim skeleton, you can also configure these handlers directly in bootstrap/app.go using the fluent WithGrpcClientStatsHandlers and WithGrpcServerStatsHandlers methods.

Options

The instrumentation/grpc package exposes several options to further customize the handlers, such as WithFilter (to skip instrumentation based on specific criteria), WithSpanAttributes, and WithMetricAttributes.

Example: Using Filters and Attributes

telemetrygrpc.NewClientStatsHandler(
    // Option: Skip tracing for health check endpoints
    telemetrygrpc.WithFilter(func(info *stats.RPCTagInfo) bool {
        return info.FullMethodName != "/grpc.health.v1.Health/Check"
    }),
    
    // Option: Add custom attributes to metrics (these are extra other than resources defined in config/telemetry.go)
    telemetrygrpc.WithMetricAttributes(telemetry.String("client", "user")),
)

Configuration

General tracing and metrics settings (exporters, sampling, etc.) can continue to be customized in config/telemetry.go.

Screenshots

Screenshot 2025-12-23 at 3 04 17 AM Screenshot 2025-12-23 at 3 05 09 AM Screenshot 2025-12-23 at 3 06 53 AM

✅ Checks

  • Added test cases for my code

@krishankumar01 krishankumar01 requested a review from a team as a code owner December 17, 2025 11:53
Copilot AI review requested due to automatic review settings December 17, 2025 11:53
@codecov
Copy link

codecov bot commented Dec 17, 2025

Codecov Report

❌ Patch coverage is 94.78261% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.41%. Comparing base (eec12ad) to head (82a9a58).
⚠️ Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
grpc/application.go 93.65% 2 Missing and 2 partials ⚠️
foundation/application_builder.go 90.47% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1305      +/-   ##
==========================================
+ Coverage   69.20%   69.41%   +0.20%     
==========================================
  Files         280      282       +2     
  Lines       16517    16630     +113     
==========================================
+ Hits        11431    11543     +112     
+ Misses       4599     4596       -3     
- Partials      487      491       +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds automatic HTTP instrumentation for OpenTelemetry tracing and metrics to the Goravel framework. It introduces a configurable middleware that creates spans, records metrics (request duration, body sizes), and propagates trace context for incoming HTTP requests.

  • Adds a new HTTP telemetry middleware with configurable span naming, path/method exclusion, and custom filters
  • Introduces global telemetry and config facades in the service provider for convenient access
  • Provides configuration options for enabling/disabling instrumentation and customizing behavior

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
telemetry/service_provider.go Adds global facades for Config and Telemetry, and updates Boot method to initialize them
telemetry/instrumentation/http/middleware.go Implements HTTP server instrumentation middleware with tracing and metrics collection
telemetry/instrumentation/http/config.go Defines configuration structure and options for HTTP instrumentation
telemetry/alias.go Adds KeyValue type alias for OpenTelemetry attributes

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@krishankumar01 krishankumar01 marked this pull request as draft December 17, 2025 16:44
@krishankumar01 krishankumar01 changed the title Kkumar gcc/#726 auto instrumentation feat: [#726] Add HTTP and gRPC telemetry instrumentation [4] Dec 18, 2025
@krishankumar01 krishankumar01 marked this pull request as ready for review December 21, 2025 06:57
@krishankumar01 krishankumar01 marked this pull request as draft December 21, 2025 06:57
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.

Benchmark suite Current: 3c4d11a Previous: 91bf06d Ratio
Benchmark_Fatal 5e-7 ns/op 0 B/op 0 allocs/op 2e-7 ns/op 0 B/op 0 allocs/op 2.50
Benchmark_Fatal - ns/op 5e-7 ns/op 2e-7 ns/op 2.50

This comment was automatically generated by workflow using github-action-benchmark.

@krishankumar01 krishankumar01 changed the title feat: [#726] Add HTTP and gRPC telemetry instrumentation [4] feat: [#726] Add gRPC telemetry instrumentation [4] Dec 22, 2025
@krishankumar01 krishankumar01 marked this pull request as ready for review December 22, 2025 07:21
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 16 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@hwbrzzl hwbrzzl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great PR, LGTM 👍 Could you fill the PR description and add some screenshots for the testing and show how to use the handler?

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 22 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 22 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 22 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +161 to +166
for _, h := range app.serverStatsHandlers {
if h == nil {
continue
}
opts = append(opts, grpc.StatsHandler(h))
}
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gRPC only supports registering one stats handler per server. When multiple grpc.StatsHandler() calls are made, only the last one takes effect (they overwrite each other). This loop will result in only the last non-nil handler being registered, making all previous handlers ineffective.

If multiple handlers are needed, consider creating a composite stats handler that internally delegates to multiple handlers, or document that only one handler should be registered.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot No, this behavior has already changed. gRPC now supports multiple StatsHandlers, and all of them are used.

@krishankumar01
Copy link
Member Author

Great PR, LGTM 👍 Could you fill the PR description and add some screenshots for the testing and show how to use the handler?

I have added the steps to enable auto telemetry for the gRPC server and client, along with screenshots I used to test the feature locally. I have also optimized the gRPC facade to support the new requirements and provided clearer warnings on how to use it.

Copy link
Contributor

@hwbrzzl hwbrzzl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

func (s *GrpcServiceProvider) Boot() {
    // Register a client handler for a specific group (e.g., "user")
    facades.Grpc().ClientStatsHandlerGroups(map[string][]stats.Handler{
        "user": { 
            telemetrygrpc.NewClientStatsHandler(),
        },
    })

    // Register a global server handler
    facades.Grpc().ServerStatsHandlers([]stats.Handler{
        telemetrygrpc.NewServerStatsHandler(),
    })
}

We can use the With* functions instead of the above, correct?

"interceptors": []string{"user"} is for interceptor, should a new configuration for StatsHandler be added in the config file?

@krishankumar01
Copy link
Member Author

krishankumar01 commented Dec 23, 2025

We can use the With* functions instead of the above, correct?

Yes, you can use With* methods inside bootstrap/app.go.

"interceptors": []string{"user"} is for interceptor, should a new configuration for StatsHandler be added in the config file?

I thought it would be more convenient for users to use the same key for both and register it in one place. Since interceptors and stats handlers are different, I added a new stats_handlers key to the client config.

Copy link
Contributor

@hwbrzzl hwbrzzl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

@krishankumar01 krishankumar01 merged commit 07de65f into master Dec 23, 2025
14 checks passed
@krishankumar01 krishankumar01 deleted the kkumar-gcc/#726-auto-instrumentation branch December 23, 2025 07:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants