Detect the revision, hostname and platform in the package - #277
Conversation
|
✔️ All good! |
| type: change | ||
| --- | ||
|
|
||
| On Heroku, report the name of the dyno as the hostname. Before, the hostname of the container that the dyno runs in was reported, so applications running on Heroku will see their data reported under a new host name. |
There was a problem hiding this comment.
| On Heroku, report the name of the dyno as the hostname. Before, the hostname of the container that the dyno runs in was reported, so applications running on Heroku will see their data reported under a new host name. | |
| When running in collector mode on Heroku, report the name of the dyno as the hostname. Before, the hostname of the container that the dyno runs in was reported, so applications running on Heroku in collector mode will see their data reported under a new host name. |
(The agent mode logic already did this, right?)
There was a problem hiding this comment.
I left this one as it was, because agent mode did not already do this.
The package always sets a hostname, from HOSTNAME or socket.gethostname(), and passes it to the agent as _APPSIGNAL_HOSTNAME. The agent reads that variable as the first step of determine_hostname, before its own DYNO fallback. So on Heroku the agent received the container hostname from the package, and never reached the step that would have reported the dyno name.
That is why the changeset is not scoped to collector mode. Applications on Heroku will see a new host name in both modes.
b5dda91 to
754e0d3
Compare
8a91b77 to
0ee996d
Compare
754e0d3 to
bb004b7
Compare
0ee996d to
93e3e75
Compare
There was a problem hiding this comment.
Pull request overview
This pull request ports parts of the agent’s environment-based autodetection into the Python package so collector mode can report revision/hostname/platform correctly (and avoids None options wiping detected values).
Changes:
- Add revision autodetection fallback chain (Heroku/Render/Kamal/Scalingo) and platform autodetection (Dokku/Heroku) to
Config.load_from_system. - Prefer the Heroku dyno name (
DYNO) over container hostname for hostname detection. - Prevent
Nonepassed via initializer options from overriding system-detected values; propagate platform via private env and OpenTelemetry resource attributes; expand tests and changesets accordingly.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/appsignal/config.py |
Adds platform + revision detection and filters initializer None overrides against system-detected values; exports _APPSIGNAL_PLATFORM. |
src/appsignal/opentelemetry.py |
Adds appsignal.config.platform attribute to the OpenTelemetry Resource. |
tests/test_config.py |
Adds coverage for hostname/dyno preference, revision/platform detection, and None override behavior; updates existing expectations. |
.changesets/report-host-name-when-set-to-none.md |
Removes now-obsoleted changeset due to updated None handling behavior. |
.changesets/prefer-the-dyno-name-for-the-hostname.md |
Documents the hostname behavior change for Heroku. |
.changesets/keep-detected-values-when-an-option-is-none.md |
Documents the new None-override behavior. |
.changesets/detect-the-revision-from-the-platform.md |
Documents revision autodetection via platform-provided environment variables. |
Suppressed comments (1)
tests/test_config.py:141
- The revision tests (e.g.
test_system_source_revision_reads_variables_in_order) assume no higher-priority revision env vars are already present (likeHEROKU_SLUG_COMMITorAPP_REVISION). To avoid environment-dependent failures, explicitlypopallPLATFORM_REVISION_ENVIRONMENT_VARIABLESandAPP_REVISIONbefore setting the variables under test.
def test_system_source_revision_reads_variables_in_order():
os.environ["RENDER_GIT_COMMIT"] = "from-render"
os.environ["KAMAL_VERSION"] = "from-kamal"
config = Config()
assert config.option("revision") == "from-render"
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Replies from @unflxw, added with copilot-loop. Copilot's review above is unchanged.
tests/test_config.py:141 — Addressed. tests/test_config.py now has an autouse fixture that clears every environment variable the system source reads, including APP_REVISION and the four platform revision variables, so these tests no longer depend on what happens to be set where they run.
bb004b7 to
723fc30
Compare
The agent reads these same variables, but only for the data it reports itself. In collector mode the package puts the revision in a resource attribute instead, and the collector cannot read it from the environment, because it runs as its own process and usually on another host.
The agent falls back to the dyno name when it detects the hostname, but the package's value reaches it first as _APPSIGNAL_HOSTNAME, so that step never ran. In collector mode there is nothing to fall back on at all, because the collector runs as its own process and usually on another host.
The agent detects the platform the same way, but only for the data it reports itself. In collector mode the package has to put it in a resource attribute, and the collector cannot detect it, because DOKKU_ROOT and DYNO are set in the application's environment while the collector runs as its own process, usually on another host. There is no config option for the platform. The detected value reaches the agent through the private environment variable that its own detection already reads first.
The options passed to the client merge last, so a None among them replaces what the system source detected: the app path, the hostname, the revision and the platform. A None carries no value, so it now leaves those alone. It still overrides a default, which is how `request_headers=None` turns off request header collection. The unreleased changeset for reporting `unknown` when the host name is set to `None` goes with it, because that case now reports the detected host name instead.
93e3e75 to
a5d153f
Compare
* Send the app path to the collector The processor strips the app path from each backtrace line, and decides whether a frame belongs to the application by checking that its path is relative. Without the app path, every frame keeps its absolute path, so no line is recognized as the application's own. * Add the ignore_logs option Collector mode sends log records, and the collector filters out the ones matching this option when the resource carries it. The package had no option for it because agent mode sends no logs at all, which is also why it is not passed on to the agent. * Detect the revision, hostname and platform in the package (#277) * Detect the revision from the platform The agent reads these same variables, but only for the data it reports itself. In collector mode the package puts the revision in a resource attribute instead, and the collector cannot read it from the environment, because it runs as its own process and usually on another host. * Prefer the dyno name for the hostname The agent falls back to the dyno name when it detects the hostname, but the package's value reaches it first as _APPSIGNAL_HOSTNAME, so that step never ran. In collector mode there is nothing to fall back on at all, because the collector runs as its own process and usually on another host. * Detect the platform and send it The agent detects the platform the same way, but only for the data it reports itself. In collector mode the package has to put it in a resource attribute, and the collector cannot detect it, because DOKKU_ROOT and DYNO are set in the application's environment while the collector runs as its own process, usually on another host. There is no config option for the platform. The detected value reaches the agent through the private environment variable that its own detection already reads first. * Keep detected values when an option is None The options passed to the client merge last, so a None among them replaces what the system source detected: the app path, the hostname, the revision and the platform. A None carries no value, so it now leaves those alone. It still overrides a default, which is how `request_headers=None` turns off request header collection. The unreleased changeset for reporting `unknown` when the host name is set to `None` goes with it, because that case now reports the detected host name instead.
Fixes #271.
Fixes #272.
Fixes #274.
Stacked on #276.
Detect the revision from the platform
The agent reads these same variables, but only for the data it reports
itself. In collector mode the package puts the revision in a resource
attribute instead, and the collector cannot read it from the
environment, because it runs as its own process and usually on another
host.
Prefer the dyno name for the hostname
The agent falls back to the dyno name when it detects the hostname, but
the package's value reaches it first as
_APPSIGNAL_HOSTNAME, so thatstep never ran. In collector mode there is nothing to fall back on at
all, because the collector runs as its own process and usually on
another host.
Detect the platform and send it
The agent detects the platform the same way, but only for the data it
reports itself. In collector mode the package has to put it in a
resource attribute, and the collector cannot detect it, because
DOKKU_ROOTandDYNOare set in the application's environment whilethe collector runs as its own process, usually on another host.
There is no config option for the platform. The detected value reaches
the agent through the private environment variable that its own
detection already reads first.
Keep detected values when an option is None
The options passed to the client merge last, so a None among them
replaces what the system source detected: the app path, the hostname,
the revision and the platform. A None carries no value, so it now leaves
those alone. It still overrides a default, which is how
request_headers=Noneturns off request header collection.The unreleased changeset for reporting
unknownwhen the host name isset to
Nonegoes with it, because that case now reports the detectedhost name instead.