Skip to content

Port upstream coroot-node-agent v1.29.0 → v1.36.2 #369

Open

Description

@mayankpande88

Tracking issue for porting coroot/coroot-node-agent v1.29.0 → v1.36.2 into this fork.

Where we are

How to work through it

  • One PR per batch, in order.
  • git cherry-pick -x so every commit message keeps the upstream SHA.
  • After any .c change, regenerate with cd ebpftracer && make build.
  • Each PR needs a local end-to-end run, and a rollout to a test node checked for up == 0 and duplicate-series gather errors before the next batch starts.
  • Compare cumulative counters, not short windows.

Batches

B1: push path and service lifecycle (Go only)

Done when:

  • Remote-write to a store behind TLS signed by a private CA works with CA_FILE.
  • An empty or corrupt file in WAL_DIR is discarded and sending resumes.
  • systemctl restart <unit> keeps the unit's series continuous.

B2: cardinality guards

Decided: 50 FQDNs. --min-container-age ships at 0 (off), changed from upstream's 30s after review: with 30s, crash-looping pods at the maximum backoff and jobs under 30s never reported.

Done when: the series count per node is measured before and after, and containers living longer than 30s keep all their series.

B3: L7 parser correctness (eBPF)

Done when:

  • The programs load on a 5.8 kernel and on a current kernel.
  • Verified instruction counts stay within limits.
  • A ClickHouse client and a RabbitMQ client are classified correctly.
  • L7 drop and unknown counters don't regress over 24h.

B4: uprobe lifecycle (port; overlaps #349, #352, #354)

Decided: the TLS attach delay ships at 0. Upstream's 30s would drop the first 30s of every process's TLS traffic, and all of it for processes that live less than 30s. Measure attach CPU with #352 in place before changing that. Upstream uses a single flag for both delays, so keeping Python/Node at 30s with TLS at 0 needs a separate flag; settle that in the PR.

Done when:

  • The uprobe count on a test node stays flat over 24h.
  • TLS-attach CPU is no worse than before.
  • Plaintext captured for long-lived processes doesn't drop.

B5: TLS runtimes (port onto the #346 hooks)

The Java agent is injected into running JVMs. It stays opt-in, off by default.

Done when:

  • A rustls client and a Java HttpClient calling HTTPS produce HTTP metrics with the right status, and spans with paths.
  • With the Java agent enabled, the JVM stays stable under load.

B6: inbound L7 (port; depends on B3–B5)

It adds container_*_inbound_* metrics labelled status (plus method for RabbitMQ/NATS). It has to be re-checked against our variable-length ring records (#356) and the HTTP/2 resync and stream-cap changes (#364, #365).

Done when:

  • A request from an uninstrumented client produces container_http_inbound_requests_total.
  • With both sides instrumented, server-side MySQL, Redis and Postgres counts match client-side counts within 1%.
  • Ring-buffer drops don't regress.
  • The programs still load on 5.8.

B7: logs (logparser fork synced first)

Done when:

  • A log storm into one container doesn't push the agent's CPU past the cap.
  • JSON log lines become OTLP records with attributes and trace context.

B8: process start and boot time

Done when: process start times are unchanged and the taskstats calls are gone from the CPU profile.

After the port

  • Once every commit above is ported or skipped, open a PR with git merge -s ours <upstream tag>. It changes no files; it gives git the right merge base, so the next sync starts from v1.36 instead of 2025-06-03.

Not porting (for now)

Commits Reason
34de3a0, 481feb0, and the windows/* parts of later commits Windows support is out of scope
e5818fc, e73d36c, b9fc7fd, 675758e, 835ae85, 0c934cd, 8992a5b JVM async-profiler and Go heap profiling: revisit with the profiling work. The async-profiler is also injected into JVMs
f6813ff docker → moby client: do it when the docker client deprecation requires it
de67715, ae3e2e6 group AWS/GCP endpoints by FQDN: overlaps the FQDN resolution in #313–#315; compare naming first
f97a3f8 ping timestamping: the pinger is off by default here
80d4530 RHEL 7 / kernel 3.10: our L7 path needs BPF ring buffers (5.8+, #363), so this needs a perf-buffer fallback design. First test whether RHEL 8's backported ring buffer loads our programs
2de271a removes the Vagrant test setup, which we don't have
7efe671, 91bb874 already covered (#346, Dockerfile)

Activity

  1. mayankpande88 commented on Oct 7, 2026

    @mayankpande88
    ContributorAuthor

    B1 is in #370. Two changes to the plan:

    75d6656 also turned out to be mostly covered here already: #353 registers processes on exec, listen and connect events. B1 takes the rest of it: registration for every event type, and a locked lookup.

  2. mayankpande88 commented on Oct 7, 2026

    @mayankpande88
    ContributorAuthor

    B2 is in #371, stacked on #370.

    Also found during the e2e (not part of B2): on every build, a burst of new systemd units started within about a minute of the agent starting can go undetected, 1–2 of 10 per burst.

  3. mayankpande88 commented on Oct 8, 2026

    @mayankpande88
    ContributorAuthor

    B2 change after review: --min-container-age ships with a default of 0 (off), not upstream's 30s. A pod in CrashLoopBackOff at the 5-minute maximum backoff is removed between restarts and comes back as a new container each time, so with 30s it never reported. Short jobs were hidden too. The flag stays available for installs that want it.

  4. mayankpande88 commented on Oct 8, 2026

    @mayankpande88
    ContributorAuthor

    B3 is in #377: coroot/coroot-node-agent@a8a084f (new ClickHouse parser), b53b38d and 556154b (stricter eBPF detection), plus regenerated ebpf.go.

    Two B3 commits aren't needed here:

    • 2d8fb1b, eBPF half: this fork already classifies every AMQP frame on 5672 as RabbitMQ before the port-gated ClickHouse check.
    • 6d5addb: L7Stats already ignores protocols that have no metrics.

    In the e2e, main lost the text of every query that carried settings (empty db.statement); #377 keeps it. The programs load on 5.10 and 6.1.

  5. mayankpande88 commented on Oct 8, 2026

    @mayankpande88
    ContributorAuthor

    B4 is split.

    B4a is #378.

    • 2c72586 is ported: uprobe programs are registered before anything is attached.
    • 44e3e8e is in with --instrumentation-delay defaulting to 0. The measured saving was about 2.6 millicores at 300 short-lived Python processes a minute, because Node.js tracing is already opt-in here.
    • 2fdd10d isn't needed: fix(tls): count TLS capture losses and fix the gaps they exposed #353 already closes links that arrive after Close.

    B4b, still to do: f8d437a (uprobe deduplication) and 0ae7f5a (delay for TLS uprobes). This reworks TLS attach here, so it needs a spec first.

    • Design:
    • Measure first: TLS-attach CPU and capture rate, using the short-lived-client scenario (about 390 clients, baseline 388–390 captured) and an attach-share CPU profile on a busy node.
    • Done when:
      • the short-lived capture rate is at or above baseline;
      • the number of uprobe links scales with distinct binaries, not processes;
      • TLS-attach CPU is lower;
      • the link count returns to baseline after process churn (no leaks);
      • long-lived TLS capture is unchanged;
      • the programs load on 5.10 and 6.1.
    • 0ae7f5a ships with a TLS delay of 0 unless the measurement justifies more.
  6. mayankpande88 commented on Oct 8, 2026

    @mayankpande88
    ContributorAuthor

    B8 is in #379: 27bc75d, 8c14700 and a9fd101, plus a test for GetStartTime. Process registration no longer depends on taskstats. At about 100 process starts per second, the agent used 3667 ms of CPU over 60s, against 4251 ms on main.

  7. mayankpande88 commented on Oct 8, 2026

    @mayankpande88
    ContributorAuthor

    B7 is in #380, on top of nudgebee/logparser#34, which merges coroot/logparser v1.4.2 into our fork. Merge #34 first, with a merge commit.

    • All five log commits are in.
    • JSON logs: exported with the message as the body, the other fields as attributes, and the trace context set.
    • --log-pattern-extraction-limit defaults to 0. In a 59k-line storm, 100/s saved about 4.6 millicores but hid 93% of the storm under the sampled pattern.
    • Over-limit messages are still exported, not dropped as upstream does.
  8. mayankpande88 commented on Oct 8, 2026

    @mayankpande88
    ContributorAuthor

    Specs for the remaining large batches

    Each of these is a re-port onto this fork's eBPF code, not a cherry-pick, so each needs its own design pass.

    B5: rustls and Java TLS (913e9d4, 579eef8)

    Design

    • How upstream attaches: both feed plaintext through upstream's own maps (ssl_pending, rustls_last_read_fd, java_tls_last_read_fd), consumed in its syscall read/write path.
    • What has to change here: this fork's OpenSSL capture (fix(ebpf): capture OpenSSL traffic regardless of BIO type and OpenSSL version #346) uses ssl_write_pending, ssl_read_pending and ssl_fds, correlating the plaintext call with the next socket write or read on the same thread. Both runtimes have to be re-hooked onto those.
    • rustls: it's sans-IO. Plaintext goes into rustls's buffer, and TLS records are written to the socket later, possibly on another thread under an async runtime such as tokio. Thread correlation has to be checked there, not just assumed.
    • Java: a Java agent (jar plus native lib) is loaded into running JVMs with jattach. That makes it opt-in (--enable-java-tls, default off), and it needs a security review before the default changes.

    Done when

    • reqwest with rustls, both blocking and tokio, has its HTTPS requests counted with the right status, and its spans carry paths.
    • A Java HttpClient over HTTPS is captured with the flag on and not loaded with it off.
    • The JVM stays stable under load with the agent attached.
    • OpenSSL and Go capture rates don't regress.

    B6: inbound (server-side) L7 (fa6f500)

    Design

    Done when

    • For local servers (HTTP/1, HTTP/2, gRPC, Postgres, MySQL, Redis), inbound counts match the client-side counts within 1%.
    • Outbound counts are unchanged.
    • Ring-buffer drops are no worse (compared on cumulative counters).
    • The programs load on 5.8+ and on a RHEL 8 4.18 kernel.
    • The agent's CPU overhead is measured.
    • Reference: in a side-by-side run, OBI captured server-side requests that this agent doesn't see today; that run is the baseline to compare against.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions