Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: metrico/gigapipe
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v5.2.0
Choose a base ref
...
head repository: metrico/gigapipe
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v5.3.0
Choose a head ref
  • 2 commits
  • 19 files changed
  • 2 contributors

Commits on Aug 27, 2026

  1. refactor(writer): extract a transport-agnostic ingest core with signa…

    …l-scoped service resolvers (#940)
    
    * refactor(writer): extract a transport-agnostic ingest core with signal-scoped service resolvers
    
    Squashed final state of the ingest-core refactor:
    
    - IngestParsed(ctx, parser, svcs) carries the parse -> push pipeline that
      doParse previously inlined, so ingest paths that do not start from an
      http.Request can reuse it; doParse now just resolves its services from
      the request context and delegates.
    - InsertServices bundles the per-tenant insert services, populated by
      signal-scoped resolvers (ResolveLogServices, ResolveTraceServices,
      ResolveProfileServices, ResolveMetricServices): each signal resolves
      only its own services.
    - Node — the fingerprint-cache namespace (FPCache.DB(Node)) — comes from
      the time-series service. The cache gates exactly one thing: whether a
      series' time_series row is appended, and those rows are pushed to Ts;
      with an empty tenant DSN the static registry picks an independent
      random node per getter call, so any other choice can mark a
      fingerprint seen on a node that never received the row.
      TestResolveLogServicesNodeFollowsTimeSeries pins this.
    - The HTTP middlewares resolve through the same helpers, keeping every
      ingest path's service resolution in one place.
    
    * refactor(writer): give IngestParsed a parser type that carries its body
    
    IngestParsed took a Parser, whose signature includes an io.Reader that
    IngestParsed has no way to supply, so it passed nil and relied on callers
    to hand it a closure with the body already captured. A parser that reads
    its body satisfied the same type and would have dereferenced that nil in
    withBufferedBody.
    
    BoundParser drops the reader from the signature and Bind supplies it, so
    a parser still waiting for a body no longer type-checks at the call.
    
    ---------
    
    Co-authored-by: rita7lopes <ritamlopes@live.com.pt>
    44YHC and rita7lopes authored Aug 27, 2026
    Configuration menu
    Copy the full SHA
    fe139e8 View commit details
    Browse the repository at this point in the history
  2. feat(writer): OTLP metrics ingestion on /v1/metrics (#941)

    * feat(writer): OTLP metrics ingestion on /v1/metrics
    
    Squashed final state of the OTLP metrics feature:
    
    - /v1/metrics accepts OTLP/HTTP exports in binary protobuf and JSON,
      responding per the OTLP/HTTP spec: 200 with partial_success when data
      points were rejected, 400 google.rpc.Status for undecodable payloads,
      413 for oversize bodies, 503 for transient ingest failures.
    - The decode layer translates OTLP metrics to Prometheus-shaped series
      per the OTel<->Prometheus compatibility spec: name/unit/suffix mapping,
      job/instance from service.*, target_info (one sample per resource per
      export at the latest accepted data-point timestamp), otel_scope_*
      labels with identity-label collisions dropped, colliding sanitized
      attribute keys concatenated with ';' in original-key order, exact
      exponential-histogram bucket bounds, delta temporality rejected.
    - The payload bound is system_settings.otlp_max_message_size from
      cloki-config v0.0.96 (env QRYN_SYSTEM_SETTINGS_OTLP_MAX_MESSAGE_SIZE),
      default 64 MiB, applied to the decompressed body.
    - withPreParsedBody lets a parser run over an already-decoded proto
      object, which is how the handler feeds the shared ingest core.
    
    * fix(writer): make the OTLP histogram +Inf bucket monotonic
    
    The +Inf bucket took its value from the data point's count field rather
    than the running sum of bucket_counts. The two disagree whenever a
    producer is lossy or buggy, and count can fall below the last finite
    bucket, leaving the stored bucket series non-monotonic.
    histogram_quantile does not error on a non-monotonic bucket series; it
    silently returns a wrong number.
    
    Emit the running sum instead, so monotonicity holds by construction.
    _count still reports the producer's own total, leaving any mismatch
    visible as _bucket{le="+Inf"} != _count rather than costing the whole
    histogram. The empty-bucket path is unchanged: it has no running sum to
    report, so dp.Count remains the only meaningful value there.
    
    * test(writer): cover the non-monotonic OTLP histogram bucket case
    
    The existing +Inf test sends a count field ABOVE the sum of its buckets,
    which proves the emitted value is wrong but leaves the bucket series
    monotonic, so it never exercises the worse half of the defect.
    
    Add the mirror case, where count falls BELOW the buckets' own total. On
    the unfixed encoder that produced buckets of 4, 7, 5: the "<= infinity"
    bucket sits under "<= 1", which cumulative buckets can never do.
    histogram_quantile interpolates over such a series without complaint, so
    this asserts the ordering directly rather than only the final value.
    
    * Remove dead section
    
    * fix(writer): make the exponential histogram +Inf bucket monotonic
    
    The classic histogram path emits the running sum of bucket_counts for the
    +Inf bucket; the exponential path still sourced it from the data point's
    count field. When a producer's count falls below the total of its own
    buckets, that places the catch-all bucket below every finite one, and the
    two histogram types then disagree on the same malformed input.
    
    Emit the running sum, which already includes zero_count. Data points with
    no positive buckets keep dp.Count: no finite bucket series is emitted for
    them, so there is nothing for +Inf to stay above.
    
    ---------
    
    Co-authored-by: rita7lopes <ritamlopes@live.com.pt>
    44YHC and rita7lopes authored Aug 27, 2026
    Configuration menu
    Copy the full SHA
    60e22ea View commit details
    Browse the repository at this point in the history
Loading