Watch
0
0
Fork
You've already forked hyperhive
0

merge the self-scrape into each collector's settings instead of defining them twice

This commit is contained in:
atlas 2026-10-28 22:20:24 +01:00 • committed by mara
commit a00bcb8c05

View file

@ -215,100 +215,101 @@ in
# and the collector then dies at startup. Same caveat as both other
# tiers; see nix/host-modules/otel.nix for the measurement.
validateConfigFile = true;
settings = {
# `journalctl --follow --lines=0` (what this receiver runs under
# the hood) ships only what's written *after* it starts — every
# collector start has a silent gap at the front. `storage:` below
# persists the read cursor, so a restart resumes from where it
# left off instead of re-opening that gap; `start_at` stays `end`
# (its default) because a cursor already covers every run after
# the first, and `beginning` without one would re-ship the whole
# journal on every restart. The cursor lives in the unit's own
# `StateDirectory` (nixpkgs' module already sets one, `%S`, below
# as `WorkingDirectory` too) — container-lifetime, not the
# host-persisted state bind mount: it indexes /var/log/journal,
# itself fresh on every container start, so the two must share
# a lifetime or the cursor outlives the journal it points into.
# `create_directory` matters here for a build-time-vs-runtime
# reason, not a convenience one: `validateConfigFile` above runs
# `otelcol validate` in the nix build sandbox, before systemd's
# `StateDirectory=` has ever created this path. Without it the
# validator refuses with "directory must exist" and the build fails.
extensions.file_storage = {
directory = "/var/lib/opentelemetry-collector";
create_directory = true;
};
settings = lib.mkMerge [
{
# `journalctl --follow --lines=0` (what this receiver runs under
# the hood) ships only what's written *after* it starts — every
# collector start has a silent gap at the front. `storage:` below
# persists the read cursor, so a restart resumes from where it
# left off instead of re-opening that gap; `start_at` stays `end`
# (its default) because a cursor already covers every run after
# the first, and `beginning` without one would re-ship the whole
# journal on every restart. The cursor lives in the unit's own
# `StateDirectory` (nixpkgs' module already sets one, `%S`, below
# as `WorkingDirectory` too) — container-lifetime, not the
# host-persisted state bind mount: it indexes /var/log/journal,
# itself fresh on every container start, so the two must share
# a lifetime or the cursor outlives the journal it points into.
# `create_directory` matters here for a build-time-vs-runtime
# reason, not a convenience one: `validateConfigFile` above runs
# `otelcol validate` in the nix build sandbox, before systemd's
# `StateDirectory=` has ever created this path. Without it the
# validator refuses with "directory must exist" and the build fails.
extensions.file_storage = {
directory = "/var/lib/opentelemetry-collector";
create_directory = true;
};
receivers.journald = {
# ⚠️ STATED, and it must stay stated: the receiver's own default
# is the RUNTIME journal (`/run/log/journal`), which in an agent
# container is empty — journald stores persistently here, so
# every entry is under /var/log/journal. Dropping this line
# leaves a collector that validates, starts, reports healthy and
# forwards nothing.
directory = "/var/log/journal";
storage = "file_storage";
# No `units` allowlist, and no user-session filter like the swarm
# tier's: a container's journal is the harness and what the
# harness spawns, so there is no foreign traffic to filter out and
# an allowlist would only be a list to forget to update.
receivers.journald = {
# ⚠️ STATED, and it must stay stated: the receiver's own default
# is the RUNTIME journal (`/run/log/journal`), which in an agent
# container is empty — journald stores persistently here, so
# every entry is under /var/log/journal. Dropping this line
# leaves a collector that validates, starts, reports healthy and
# forwards nothing.
directory = "/var/log/journal";
storage = "file_storage";
# No `units` allowlist, and no user-session filter like the swarm
# tier's: a container's journal is the harness and what the
# harness spawns, so there is no foreign traffic to filter out and
# an allowlist would only be a list to forget to update.
# journald's PRIORITY carries the level every line already has;
# without this the record reaches VictoriaLogs with
# `severity_text: Unspecified` and the store cannot tell an error
# from a debug line. The table — and the inverted direction that
# makes it worth a file of its own — lives in
# ../journald-severity.nix, shared with the swarm tier's receiver.
operators = import ../journald-severity.nix;
};
# journald's PRIORITY carries the level every line already has;
# without this the record reaches VictoriaLogs with
# `severity_text: Unspecified` and the store cannot tell an error
# from a debug line. The table — and the inverted direction that
# makes it worth a file of its own — lives in
# ../journald-severity.nix, shared with the swarm tier's receiver.
operators = import ../journald-severity.nix;
};
# Identity the hop above cannot supply. A host-side reader can say
# which machine a line came from; only a collector running as the
# agent can say which agent. `hive` and `swarm` are deliberately
# NOT stamped here: the swarm tier upserts both from the receiver
# that accepted the sample, precisely so the labels come from
# something the sender cannot write.
processors.resource.attributes = [
{
key = "service.name";
value = "hyperhive-agent";
action = "upsert";
# Identity the hop above cannot supply. A host-side reader can say
# which machine a line came from; only a collector running as the
# agent can say which agent. `hive` and `swarm` are deliberately
# NOT stamped here: the swarm tier upserts both from the receiver
# that accepted the sample, precisely so the labels come from
# something the sender cannot write.
processors.resource.attributes = [
{
key = "service.name";
value = "hyperhive-agent";
action = "upsert";
}
{
key = "agent";
value = userName;
action = "upsert";
}
];
# The hive's collector, at the same base address every in-process
# producer already exports to. `endpoint` is a BASE the exporter
# appends `/v1/logs` to — the path an OTLP/HTTP receiver serves.
exporters.${logExporter} = {
endpoint = cfg.endpoint;
}
{
key = "agent";
value = userName;
action = "upsert";
}
];
// lib.optionalAttrs (cfg.protocol == "http/json") { encoding = "json"; };
# The hive's collector, at the same base address every in-process
# producer already exports to. `endpoint` is a BASE the exporter
# appends `/v1/logs` to — the path an OTLP/HTTP receiver serves.
exporters.${logExporter} = {
endpoint = cfg.endpoint;
service.pipelines.logs = {
receivers = [ "journald" ];
processors = [ "resource" ];
exporters = [ logExporter ];
};
# An extension configured but not listed here is INERT — the
# journald receiver's `storage: file_storage` above would name a
# component the collector never starts.
service.extensions = [ "file_storage" ];
}
// lib.optionalAttrs (cfg.protocol == "http/json") { encoding = "json"; };
service.pipelines.logs = {
receivers = [ "journald" ];
processors = [ "resource" ];
exporters = [ logExporter ];
};
# An extension configured but not listed here is INERT — the
# journald receiver's `storage: file_storage` above would name a
# component the collector never starts.
service.extensions = [ "file_storage" ];
};
};
# Every agent container has a network namespace of its own, so they can all
# use the same port.
services.opentelemetry-collector.settings = import ../collector-self-scrape.nix {
inherit lib;
port = selfTelemetryPort;
exporter = logExporter;
attributes.agent = userName;
# Every agent container has a network namespace of its own, so they can all
# use the same port.
(import ../collector-self-scrape.nix {
inherit lib;
port = selfTelemetryPort;
exporter = logExporter;
attributes.agent = userName;
})
];
};
};
}