Repository navigation
Add gRPC payload capture (UnaryServerInterceptor) - #99
Merged
Merged
Conversation
Every integration in this SDK is an HTTP middleware, so a gRPC service gets no
request or response payloads at all — and in Go, gRPC is frequently a service's
only protocol. UnaryServerInterceptor closes that.
google.golang.org/grpc was already an indirect dependency, so promoting it to
direct costs nothing new.
Marshalling goes through protojson for anything that is a proto.Message, not
encoding/json. protojson applies the field names declared in the .proto and
renders 64-bit fields as strings; encoding/json on a generated struct leaks the
generator's internal state and produces field names that would not match a
redaction path the user wrote against their schema. This is the same class of
problem the JS SDK hit, where protobuf int64 arrived as {low, high, unsigned}.
rpc.system / rpc.method / rpc.grpc.status_code are set alongside the HTTP-shaped
fields rather than instead of them: the server lifts bodies based on the HTTP
shape, but a gRPC status says more than ok-or-not — NOT_FOUND and
PERMISSION_DENIED both flatten to 500 — so the real code is kept.
Streaming is deliberately out of scope and documented as such; there is no
single message to capture, so a stream interceptor would record nothing while
appearing to work.
Tests cover the parts that matter rather than the happy path alone: the RPC's
response and error reach the caller untouched, a sensitive field in a decoded
message is redacted, the gRPC code survives unflattened, capture off records
nothing, and an unmarshalable message degrades to no body. That last test caught
a real wart — RedactJSON turns nil into the literal 'null', which would have been
captured as a body reading "null".
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every integration in this SDK is an HTTP middleware, so a gRPC service gets no request or response payloads at all — and in Go, gRPC is frequently a service's only protocol.
google.golang.org/grpcwas already an indirect dependency, so promoting it to direct costs nothing new.protojson, not encoding/json
For anything that is a
proto.Message, marshalling goes throughprotojson: it applies the field names declared in the.protoand renders 64-bit fields as strings.encoding/jsonon a generated struct leaks the generator's internal state and produces field names that would not match a redaction path the user wrote against their schema. Same class of problem the JS SDK hit, where protobuf int64 arrived as{low, high, unsigned}.Attributes
rpc.system/rpc.method/rpc.grpc.status_codeare set alongside the HTTP-shaped fields, not instead of them. The server lifts bodies based on the HTTP shape, but a gRPC status says more than ok-or-not —NOT_FOUNDandPERMISSION_DENIEDboth flatten to 500 — so the real code is kept for the UI to filter on natively later.Scope
Unary only. Streaming has no single message to capture, so a stream interceptor would record nothing while appearing to work — better to say so than to ship a silent no-op.
Tests
Cover the parts that matter, not just the happy path: response and error reach the caller untouched, a sensitive field in a decoded message is redacted, the gRPC code survives unflattened, capture-off records nothing, and an unmarshalable message degrades to no body. That last one caught a real wart —
RedactJSONturns nil into the literalnull, which would have been captured as a body reading "null".Cross-language plan:
docs/grpc-sdk-support.mdin the monoscope repo. The Node equivalent shipped as@monoscopetech/common@1.3.1and is deployed in the demo's payment service.