Repository navigation
Conversation
Events get an optional root `environment` property, separate from the `@environment` machine data. The client configuration holds a default (`environment(String)`, `exceptionless.environment`, `EXCEPTIONLESS_ENVIRONMENT`), `EventBuilder.setEnvironment` overrides it per event, and the Spring Boot starter falls back to the only active profile. Names are normalized like the server does: trimmed, and unspecified when empty, over 64 characters or containing control characters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
EventBuilder.setEnvironment(null) now clears any earlier override on the builder so the configured default applies, matching the .NET and JavaScript clients. Only a non-null value that is not valid (empty or white space, over 64 characters, control characters) is an explicit override that sends the event without an environment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Events can now carry a deployment environment such as production or staging. It is sent as the optional root
environmentproperty of the event, next totype,sourceandmessage, and it is separate fromdata.@environment, which still holds machine information and is untouched. This matches the .NET client (Exceptionless.Net #371) and the JavaScript client (Exceptionless.JavaScript #193), and the server support in Exceptionless #2570.Self-hosted installs should upgrade their server first. Older servers drop the root
environmentproperty, so events sent by this client to an older server simply arrive without an environment.What changed
ExceptionlessConfiguration.environment(String)sets the default environment, withgetEnvironment()andisEnvironmentConfigured()to read it.EventBuilder.setEnvironment(String)overrides the default for one event. A non-null name that is not valid (empty or whitespace, over 64 characters, or containing control characters) is still an override, so that event is sent unspecified and does not fall back to the default.setEnvironment(null)means no override: it clears any earlier call on that builder and the configured default applies, as in the .NET and JavaScript clients.ConfigurationDefaultsPluginapplies the default to every event that does not already have one, including errors, logs, feature usage, 404s and session events. Events set by hand withEvent.setEnvironmentkeep their value.Eventhas a newenvironmentproperty, andtoJsonwrites it at the event root only when it is set.String.strip()would keep), casing preserved, and treated as unspecified when empty, longer than 64 characters or containing control characters.Event.setEnvironmentand the configuration setters enforce this, so every path to the queue, including plugins, submitting handlers and the duplicate checker's merged events, produces a valid payload.exceptionless.environmentand, as a last resort, uses the active Spring profile when exactly one profile is active.How precedence works
From highest to lowest:
EventBuilder.setEnvironment(...)with a non-null value. A valid name is used; an invalid one leaves that event unspecified. Null is not an override and falls through to the lower levels.ExceptionlessConfiguration.environment(...).exceptionless.properties, thenEXCEPTIONLESS_ENVIRONMENT, then theexceptionless.environmentsystem property (the existing order for external sources), and the Springexceptionless.environmentproperty in the starter. This holds whichever is applied first, so reading external configuration after setting a value in code does not replace it.ExceptionlessConfiguration.environmentFallback(...), used only when no environment is configured at all and exactly one profile is active. Several profiles such asprod,metricsdo not name an environment, so none is guessed.As in .NET, a configured value that is empty or invalid counts as configured: it leaves events unspecified and blocks lower-priority sources, rather than silently falling through to them. Passing null to
environment(...)forgets the value set in code.How I tested it
I ran
./mvnw verifyfor the whole reactor in Docker (maven:3.9-eclipse-temurin) on JDK 17, 21 and 25, matching the CI matrix. After the last change (null means no override) I re-ran it on JDK 17 and 21; CI covers the rest of the matrix. That includes Spotless, Error Prone and NullAway on JDK 21 and up, and all 432 core tests plus the logging, servlet and Spring Boot starter modules (also with-Pspring-boot-4before that change). All pass. The end-to-end tests against a real server (-De2e=true) were not run locally.New tests cover:
data.@environmentleft alone;I also mutation-checked the key behavior by breaking each of these in turn and confirming tests fail: the default application, the per-event override flag (null counted as an override, and invalid names not counted as one), setter normalization, serialization, code-over-external precedence, the 64 character limit, the control character check, the Unicode trim, the duplicate hash, the fallback and both Spring paths. Every mutant was caught.
🤖 Generated with Claude Code