Fluent forwarding rounds exact integer log fields
perfloop-oss/accesslog · NUMERIC REPRESENTATION LOSS
https://perfloop.ai/t/oss/case_ypjkptr2zb
Verdict
VERIFIED · settled 2026-10-23
What happened: The assertion is violated on the comparison and satisfied with this change.
Hypothesis
The Fluent sink can change exact integer log fields before sending them. It decodes every JSON number into float64, whose representation cannot distinguish all 64-bit integers. A local forwarding check confirmed a changed value despite a successful handler result; the frequency of affected fields in consumer traffic is unknown.
At revision b22fa9461231b8d9f94f52526a57d0752a04c25b, FluentLogWriter.Write unmarshals the event into map[string]interface{} at writer/fluent.go:59-60 and posts that map at line 64. The pinned fluent-logger-golang v1.8.0 copies the map values and encodes their existing numeric types into its MessagePack record. There is no exact-integer recovery after the JSON decode.
This sink is a supported binding for the assigned gRPC path, not the stdout binding in the gRPC example. README.md:51-57 advertises Fluent sinks and io.Writer integration. NewGRPCLogger accepts that writer at grpc.go:29-34. A handler can add an Int64 field through GetLogEntry(ctx).Add; DefaultGRPCLogEntry.Write invokes those callbacks before sending the event at grpc.go:157-161. The loss affects an emitted callback field even with the default formatter and no request or response capture options.
The local TestHuntFluentInteger check composed UnaryServerInterceptor, NewGRPCLogger, and NewFluentLogWriter. Its handler added request_id with Int64 value 9007199254740993 and a control field with value 42. A local TCP receiver decoded the actual Fluent MessagePack record: request_id arrived as float64 value 9007199254740992, while the control remained 42. The interceptor returned success. This establishes a transport conversion defect, not a production incident or a performance result.
A Case can independently repeat that wire-level check and compare received numeric values with exact references around 2^53, both int64 limits, and the uint64 upper limit, including nested records and arrays. Controls should cover ordinary integers, fractional numbers, unchanged gRPC fields and callback behavior, and malformed or trailing JSON being rejected as before. The scope is integers representable by zerolog's signed and unsigned 64-bit field APIs, not a new arbitrary-precision number contract. Confidence is medium.
Change to test: Preserve the exact values of signed and unsigned 64-bit integer log fields, including nested fields, during JSON-to-Fluent conversion. Keep fractional numbers numeric and preserve whole-input JSON validation, existing error handling, and forwarding behavior without adding public API.
Where it lives
Evidence
The assertion is violated on the comparison and satisfied with this change: `For callback-generated signed and unsigned 64-bit integer fields, FluentLogWriter preserves the exact numeric value in the Fluent MessagePack record through the default gRPC unary logging path, including nested objects and arrays, assuming a valid event and a receiver that accepts the record.`
Checks: 2 of 2 passed. Verification: no defect found.
Timeline
2026-10-22· Case opened