Conversation
unflxw
force-pushed
the
derive-collector-params-options
branch
10 times, most recently
from
September 16, 2026 18:12
c7d97f7 to
9169860
Compare
unflxw
marked this pull request as ready for review
September 16, 2026 18:31
Collector mode keeps the request payload, the function parameters and the query parameters in an attribute each, with an option per kind to filter it and to suppress it. The package ignores `filter_parameters` and `send_params` there, so an application that filtered a password in agent mode stops filtering it under a collector, and one that turned parameter reporting off reports parameters again. Derive the six options from the two whenever the application set one of the two and left the replacement alone. Derived values go in a configuration source of their own, ranked below every other source, so an option the application names wins over one derived for it.
Collector mode reads `filter_parameters` and `send_params` to derive the six options that replace them, and those six name which kind of parameters they mean. Warn at startup that the option is deprecated in collector mode, and name the value to set for each option that replaces it, which AppSignal has already derived in order to fall back to it. The warning that the two are ignored goes with it, along with the one pointing `filter_attributes` at `filter_parameters`, which nothing derives a value for.
Collector mode keeps the request payload, the function parameters and the query parameters in an attribute each, and the package writes to the request payload. An application reporting a job's arguments has `filter_request_payload` and `send_request_payload` applied to them, rather than the two options that name function parameters. Add a helper per kind, so a caller says which kind it is reporting. Agent mode has one slot for all three, and every helper writes there.
The Django and Flask instrumentation hands parameters to a helper that names no kind, so a request's query string is reported as a request payload and filtered by the options that name the payload. Call the helper that names the kind instead. Django reports two kinds at once, and agent mode has one place for them, so it hands both over under the keys that say which is which. Flask reports one kind, so it hands that over on its own, without the `args` key.
`_Once` calls a function the first time it is called and never again, which is how the package emits a deprecation warning without repeating it. It lives in the heartbeat module, which pulls in `check_in`, so anything else that warns once imports the whole of that. Move it and the warning function beside it into a module of their own.
The `set_params` helper reports parameters without naming their kind, so collector mode reports whatever it is given as the request payload, with the options that name a request payload applied to it. Warn the first time it is called in collector mode, naming the three helpers that say which kind they report. Agent mode keeps every kind in one place, so the warning is limited to collector mode.
The diagnose report prints every configuration option with the value it holds. Reading it means guessing whether a value is a default or came from the environment, which is the first thing somebody checks when an option is not what they set. Print the source beside the value, and, for an option more than one source holds, list each source with what it holds in the order they are merged. The order comes from the constant the merge walks.
The HTTP instrumentation reports a header only when the header is named in the environment variable for its kind. The package sets the request variable from `request_headers` and leaves the response one unset, so no `http.response.header.*` attribute is produced and `response_headers` has nothing to apply to. Set both variables from the option that names them.
The collector keeps a header whose arriving name is in the allowlist the package sends, compared by exact match. That name follows the OpenTelemetry semantic convention: the header's own name, lowercased, with its dashes kept. The `request_headers` and `response_headers` options hold whatever the application wrote, and someone naming the `Content-Type` header is as likely to write it that way as `content-type`. Normalize a header's name to the convention's spelling before sending it, for the two options and for the name `set_header` is given in collector mode.
A list option read from the environment is split on commas, and splitting an empty string gives a list holding one empty string. An empty variable is how a list is emptied from the environment, so `APPSIGNAL_RESPONSE_HEADERS=` names one header that cannot exist. Read an empty variable as an empty list, so that the diagnose report shows the value the application set, and an option left at its default reads as unchanged.
Twelve list options have no default and hold `None` until they are configured, while the Ruby gem and the documentation for these options give them an empty list. Default them to an empty list. The agent is told about them as an empty string rather than an unset variable, and the collector receives an empty list rather than no attribute, which is what stops it reporting every response header it receives.
The diagnose integration tests live in a repository shared with the other language integrations, and assert the full list of sources a report carries. The package merges a `derived` source, so the expectations there carry it too.
unflxw
force-pushed
the
derive-collector-params-options
branch
from
September 17, 2026 14:23
9169860 to
6f89bc0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Derive the collector-mode parameter options
Collector mode keeps the request payload, the function parameters and
the query parameters in an attribute each, with an option per kind to
filter it and to suppress it. The package ignores
filter_parametersand
send_paramsthere, so an application that filtered a password inagent mode stops filtering it under a collector, and one that turned
parameter reporting off reports parameters again. Derive the six options
from the two whenever the application set one of the two and left the
replacement alone. Derived values go in a configuration source of their
own, ranked below every other source, so an option the application names
wins over one derived for it.
Deprecate the params options in collector mode
Collector mode reads
filter_parametersandsend_paramsto derive thesix options that replace them, and those six name which kind of
parameters they mean. Warn at startup that the option is deprecated in
collector mode, and name the value to set for each option that replaces
it, which AppSignal has already derived in order to fall back to it. The
warning that the two are ignored goes with it, along with the one
pointing
filter_attributesatfilter_parameters, which nothingderives a value for.
Add a helper for each kind of parameters
Collector mode keeps the request payload, the function parameters and
the query parameters in an attribute each, and the package writes to the
request payload. An application reporting a job's arguments has
filter_request_payloadandsend_request_payloadapplied to them,rather than the two options that name function parameters. Add a helper
per kind, so a caller says which kind it is reporting. Agent mode has
one slot for all three, and every helper writes there.
Say which parameters our instrumentation reports
The Django and Flask instrumentation hands parameters to a helper that
names no kind, so a request's query string is reported as a request
payload and filtered by the options that name the payload. Call the
helper that names the kind instead. Django reports two kinds at once,
and agent mode has one place for them, so it hands both over under the
keys that say which is which. Flask reports one kind, so it hands that
over on its own, without the
argskey.Move the warn-once helper to a module of its own
_Oncecalls a function the first time it is called and never again,which is how the package emits a deprecation warning without repeating
it. It lives in the heartbeat module, which pulls in
check_in, soanything else that warns once imports the whole of that. Move it and the
warning function beside it into a module of their own.
Deprecate set_params when a collector is used
The
set_paramshelper reports parameters without naming their kind, socollector mode reports whatever it is given as the request payload, with
the options that name a request payload applied to it. Warn the first
time it is called in collector mode, naming the three helpers that say
which kind they report. Agent mode keeps every kind in one place, so the
warning is limited to collector mode.
Name the source of each config option in diagnose
The diagnose report prints every configuration option with the value it
holds. Reading it means guessing whether a value is a default or came
from the environment, which is the first thing somebody checks when an
option is not what they set. Print the source beside the value, and, for
an option more than one source holds, list each source with what it
holds in the order they are merged. The order comes from the constant
the merge walks.
Report the configured response headers
The HTTP instrumentation reports a header only when the header is named
in the environment variable for its kind. The package sets the request
variable from
request_headersand leaves the response one unset, so nohttp.response.header.*attribute is produced andresponse_headershas nothing to apply to. Set both variables from the option that names
them.
Name a header the way the convention does
The collector keeps a header whose arriving name is in the allowlist the
package sends, compared by exact match. That name follows the
OpenTelemetry semantic convention: the header's own name, lowercased,
with its dashes kept. The
request_headersandresponse_headersoptions hold whatever the application wrote, and someone naming the
Content-Typeheader is as likely to write it that way ascontent-type.Normalize a header's name to the convention's spelling before sending
it, for the two options and for the name
set_headeris given incollector mode.
Read an empty list option from the environment
A list option read from the environment is split on commas, and
splitting an empty string gives a list holding one empty string. An
empty variable is how a list is emptied from the environment, so
APPSIGNAL_RESPONSE_HEADERS=names one header that cannot exist. Readan empty variable as an empty list, so that the diagnose report shows
the value the application set, and an option left at its default reads
as unchanged.
Default the list options to empty lists
Twelve list options have no default and hold
Noneuntil they areconfigured, while the Ruby gem and the documentation for these options
give them an empty list. Default them to an empty list. The agent is
told about them as an empty string rather than an unset variable, and
the collector receives an empty list rather than no attribute, which is
what stops it reporting every response header it receives.
Point the diagnose tests at the derived source
The diagnose integration tests live in a repository shared with the
other language integrations, and assert the full list of sources a
report carries. The package merges a
derivedsource, so theexpectations there carry it too.