Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/platforms/dart/common/integrations/grpc.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: gRPC Integration
description: "Learn more about the Sentry gRPC integration for the Dart SDK."
sidebar_order: 10
redirect_from:
- /platforms/dart/guides/grpc/
---

<Include name="dart-integrations/grpc.mdx" />
9 changes: 9 additions & 0 deletions docs/platforms/dart/guides/flutter/integrations/grpc.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
title: gRPC Integration
description: "Learn more about the Sentry gRPC integration for the Flutter SDK."
sidebar_order: 40
redirect_from:
- /platforms/dart/guides/flutter/grpc/
---

<Include name="dart-integrations/grpc.mdx" />
178 changes: 178 additions & 0 deletions includes/dart-integrations/grpc.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
---
title: gRPC Integration
description: "Learn more about the Sentry gRPC integration for the Dart SDK."
platforms:
- dart
- flutter
sidebar_order: 4
---

The `sentry_grpc` package provides [gRPC](https://pub.dev/packages/grpc) support for Sentry. It instruments outgoing unary calls with spans, records breadcrumbs, injects distributed tracing headers into gRPC metadata, and can capture failed calls as Sentry errors.

## Requirements

- `grpc` 4.0.4 or higher
- `sentry_grpc` X or higher

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: The documentation for the sentry_grpc package uses a literal 'X' as a version placeholder instead of the correct version injection syntax.
Severity: LOW

Suggested Fix

Replace the literal 'X' on line 15 with the correct version injection syntax, likely {{@inject packages.version(sentry_grpc)}}, to ensure the correct package version is always displayed in the documentation.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: includes/dart-integrations/grpc.mdx#L15

Potential issue: The documentation file `includes/dart-integrations/grpc.mdx` contains a
literal character 'X' as a placeholder for the required version of the `sentry_grpc`
package. This will render as-is to the user, causing confusion about which version of
the package is needed. Other parts of the documentation correctly use the `{{@inject
packages.version(...)}}` helper to dynamically insert the correct version number.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

correct, it was intentional, the correct version will be resolved once the first gRPC integration is released


## Install

Add `sentry_grpc` to your dependencies:

```yml {filename:pubspec.yaml}
dependencies:
sentry: ^{{@inject packages.version('sentry.dart', '9.22.0') }}

@buenaflor buenaflor Jun 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

maybe we should add a short comment

sentry: xyz # or sentry_flutter

something like that, since if you use flutter you should use sentry_flutter instead of only sentry

sentry_grpc: ^{{@inject packages.version('sentry.dart.grpc', '9.22.0') }}
grpc: '>=4.0.4 <6.0.0'
```
## Configure
Add `SentryGrpcInterceptor` to your gRPC client's interceptor list. This should happen once, when the client is created.

```dart
import 'package:grpc/grpc.dart';
import 'package:sentry/sentry.dart';
import 'package:sentry_grpc/sentry_grpc.dart';
Future<void> main() async {
await Sentry.init(
(options) {
options.dsn = '___PUBLIC_DSN___';
options.tracesSampleRate = 1.0;
},
appRunner: runApp,
);
}
Future<void> runApp() async {
final channel = ClientChannel(
'api.example.com',
options: const ChannelOptions(credentials: ChannelCredentials.secure()),
);
final client = MyServiceClient(
channel,
interceptors: [SentryGrpcInterceptor()],
);
// All calls through this client are now automatically instrumented.
}
```

## Capturing Failed Requests as Errors

When a gRPC call fails, either because the server returns a non-OK status code or because a transport error occurs, the interceptor can capture it as a Sentry error.

This feature is controlled by `captureFailedRequests`. By default, the interceptor respects the global `SentryOptions.captureFailedRequests` setting. You can override this per-interceptor:

```dart
// Capture failed gRPC calls regardless of the global setting
final interceptor = SentryGrpcInterceptor(captureFailedRequests: true);
// Disable for this client only
final interceptor = SentryGrpcInterceptor(captureFailedRequests: false);
```

When a failed call is captured, Sentry attaches the gRPC method path, status code, status name, and error message as context on the event.

## Breadcrumbs

The interceptor automatically records a breadcrumb for every unary call. Successful calls are recorded at the `info` level; failed calls at the `error` level. Each breadcrumb includes the method path, gRPC status code and name, and call duration in milliseconds.

To disable breadcrumbs:

```dart
final interceptor = SentryGrpcInterceptor(enableBreadcrumbs: false);
```

## Tracing for gRPC Calls

### Instrumentation Behaviour

For each unary call, the interceptor:

- Creates a child span under the active transaction with operation `grpc.client` and a description set to the full method path (for example, `/helloworld.Greeter/SayHello`).
- Sets span data following OpenTelemetry gRPC semantic conventions:
- `rpc.system` = `grpc`
- `rpc.service` = the service portion of the method path (for example, `helloworld.Greeter`)
- `rpc.method` = the method name (for example, `SayHello`)
- `rpc.response.status_code` = the gRPC status name (for example, `OK`, `NOT_FOUND`)
- Injects `sentry-trace` and `baggage` headers into the call's gRPC metadata for distributed tracing.
- Finishes the span and sets its status when the call completes.
- Associates any thrown exception with the span.

<Alert>
Spans are only created when there is an active transaction on the scope. If no transaction is active, the interceptor still injects trace headers and records breadcrumbs.
</Alert>

<Alert>
Server-streaming and client-streaming calls receive distributed tracing header injection only. Full span lifecycle tracking for streaming RPCs will be added in a future release.
</Alert>

### Controlling Trace Header Propagation

By default, `sentry-trace` and `baggage` headers are injected for all gRPC method paths. Use `tracePropagationTargets` to restrict injection to specific services or methods. Targets are matched against the full method path (for example, `/helloworld.Greeter/SayHello`):

```dart
await Sentry.init((options) {
options.dsn = '___PUBLIC_DSN___';
options.tracePropagationTargets = [
'myservice.MyService', // Matches any method under this service
];
});
```

### Sending Request Metadata (PII)

When `sendDefaultPii` is enabled, the interceptor attaches the gRPC call's metadata headers to the span as `rpc.request.metadata.<key>` attributes. This is opt-in because metadata can contain sensitive values such as authorization tokens.

```dart
await Sentry.init((options) {
options.dsn = '___PUBLIC_DSN___';
options.sendDefaultPii = true; // Metadata headers will appear in span data
});
```

### Prerequisites

Before enabling tracing:

1. Initialize the Sentry SDK. Learn more [here](/platforms/dart/guides/flutter/#configure).
2. Set up tracing. Learn more [here](/platforms/dart/guides/flutter/tracing/).

### Verify

```dart
import 'package:grpc/grpc.dart';
import 'package:sentry/sentry.dart';
import 'package:sentry_grpc/sentry_grpc.dart';
Future<void> makeGrpcRequest() async {
final channel = ClientChannel('api.example.com');
final client = GreeterClient(
channel,
interceptors: [SentryGrpcInterceptor()],
);
// Start a transaction so the interceptor has a parent span to attach to.
final transaction = Sentry.startTransaction(
'grpc-example',
'grpc.client',
bindToScope: true,
);
try {
final response = await client.sayHello(HelloRequest(name: 'Sentry'));
transaction.status = const SpanStatus.ok();
print(response.message);
} catch (exception, stackTrace) {
transaction.throwable = exception;
transaction.status = const SpanStatus.internalError();
await Sentry.captureException(exception, stackTrace: stackTrace);
} finally {
await transaction.finish();
}
}
```

To view the recorded transaction, log into [sentry.io](https://sentry.io) and open your project. Clicking **Performance** will open a page with transactions, where you can select the transaction with the name `grpc-example` and see the `grpc.client` child span for the `/helloworld.Greeter/SayHello` call.
Loading