-
-
Notifications
You must be signed in to change notification settings - Fork 27.4k
feat: add log deployments and changes pattern (#2696) #3606
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
arnabnandy7
wants to merge
2
commits into
iluwatar:master
Choose a base branch
from
arnabnandy7:feature/logDeploymentsAndChanges
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| name: Log deployments and changes example | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| demonstrate: | ||
| runs-on: ubuntu-22.04 | ||
| steps: | ||
| - name: Checkout Code | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up JDK 21 | ||
| uses: actions/setup-java@v4 | ||
| with: | ||
| java-version: '21' | ||
| distribution: 'temurin' | ||
| cache: 'maven' | ||
|
|
||
| - name: Build example | ||
| run: ./mvnw -B -pl microservices-log-deployments-and-changes -am package | ||
|
|
||
| - name: Run simulated deployment and change pipeline | ||
| shell: bash | ||
| run: | | ||
| set -o pipefail | ||
| java -jar microservices-log-deployments-and-changes/target/microservices-log-deployments-and-changes-1.26.0-SNAPSHOT.jar 2>&1 | tee deployment-events.log | ||
|
|
||
| - name: Preserve timeline and alerts | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: deployment-events | ||
| path: deployment-events.log | ||
| if-no-files-found: warn |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,172 @@ | ||
| --- | ||
| title: "Microservices Log Deployments and Changes Pattern in Java" | ||
| shortTitle: Microservices Log Deployments and Changes | ||
| description: "Record operational changes in a shared timeline to correlate service failures with deployments and configuration updates." | ||
| category: Integration | ||
| language: en | ||
| tag: | ||
| - Microservices | ||
| - Enterprise patterns | ||
| - Fault tolerance | ||
| --- | ||
|
|
||
| ## Intent of Microservices Log Deployments and Changes Design Pattern | ||
|
|
||
| Record deployments and operational changes with their service, version, environment, initiator, | ||
| timestamp, and outcome. Use this history to correlate changes with unexpected application behavior. | ||
|
|
||
| ## Detailed Explanation of Microservices Log Deployments and Changes Pattern with Real-World Examples | ||
|
|
||
| Real-world example | ||
|
|
||
| > An online shop releases a new orders service and changes the payments timeout. Payments then | ||
| > start failing. A shared timeline helps operators identify which changes preceded the failures, | ||
| > even though different teams performed the operations. | ||
|
|
||
| In plain words | ||
|
|
||
| > Keep a shared record of what changed, when, who changed it, and whether it succeeded. | ||
|
|
||
| [Microservices.io](https://microservices.io/patterns/observability/log-deployments-and-changes.html) | ||
| describes recording deployments and environment changes to correlate them with application issues. | ||
|
|
||
| This example follows the producer-to-central-store structure of | ||
| [Microservices Log Aggregation](../microservices-log-aggregation/README.md). Its events describe | ||
| operational changes rather than general application messages. Each `DeploymentPipeline` wraps a | ||
| service operation and appends its outcome to the shared `CentralLogStore`. `LogMonitor` presents | ||
| the history and selects alerts using a supplied rule. | ||
|
|
||
| ## Class diagram | ||
|
|
||
| ```mermaid | ||
| classDiagram | ||
| DeploymentPipeline --> CentralLogStore : appends outcomes | ||
| CentralLogStore o-- ChangeEvent : retains history | ||
| ChangeEvent --> ChangeType | ||
| LogMonitor --> CentralLogStore : reads history | ||
| class ChangeEvent { | ||
| Instant timestamp | ||
| String service | ||
| String version | ||
| String environment | ||
| String actor | ||
| ChangeType type | ||
| String description | ||
| boolean successful | ||
| } | ||
| class ChangeType { | ||
| <<enumeration>> | ||
| DEPLOYMENT | ||
| CONFIGURATION | ||
| ENDPOINT | ||
| PROTOCOL | ||
| } | ||
| ``` | ||
|
|
||
| ## Programmatic Example of Microservices Log Deployments and Changes Pattern in Java | ||
|
|
||
| Create a shared store and inject a clock. Tests use a fixed clock for deterministic UTC timestamps. | ||
|
|
||
| ```java | ||
| var store = new CentralLogStore(); | ||
| var pipeline = new DeploymentPipeline(store, Clock.systemUTC()); | ||
| var monitor = new LogMonitor(store); | ||
| pipeline.execute( | ||
| "orders", "2.0", "production", "release-engineer", ChangeType.DEPLOYMENT, | ||
| "Deploy orders release", () -> LOGGER.info("Deploying orders 2.0")); | ||
| ``` | ||
|
|
||
| The operation represents deployment tooling or a configuration update. `execute` invokes it once | ||
| and records an immutable `ChangeEvent` in a `finally` block. A successful return records success; | ||
| an exception records failure and propagates to the caller. The timestamp is the completion time. | ||
| Configuration, endpoint, and communication protocol updates use the corresponding `ChangeType`. | ||
| Callers do not need a separate logging step. | ||
|
|
||
| Display the timeline and alert on failed production operations: | ||
|
|
||
| ```java | ||
| LOGGER.info("Deployment and change timeline:\n{}", monitor.timeline()); | ||
| monitor.alerts(event -> !event.successful() && "production".equals(event.environment())) | ||
| .forEach(event -> LOGGER.warn("ALERT: {} {} failed", event.service(), event.type())); | ||
| ``` | ||
|
|
||
| `App` simulates changes for orders and payments. Its protocol update deliberately fails; the demo | ||
| catches that failure to display the complete history. Output includes these lines (times and actor vary): | ||
|
|
||
| ```text | ||
| 2026-01-01T12:00:00Z | orders | 2.0 | production | release-engineer | DEPLOYMENT | SUCCESS | Deploy orders release | ||
| 2026-01-01T12:00:00Z | payments | 1.1 | production | release-engineer | PROTOCOL | FAILURE | Switch inter-service protocol to gRPC | ||
| ALERT: payments PROTOCOL failed | ||
| ``` | ||
|
|
||
| ### Running and verifying the example | ||
|
|
||
| From the repository root, with Java 21: | ||
|
|
||
| ```shell | ||
| ./mvnw -pl microservices-log-deployments-and-changes -am test | ||
| ./mvnw -pl microservices-log-deployments-and-changes spotless:check | ||
| ./mvnw -pl microservices-log-deployments-and-changes -am package -DskipTests | ||
| java -jar microservices-log-deployments-and-changes/target/microservices-log-deployments-and-changes-1.26.0-SNAPSHOT.jar | ||
| ``` | ||
|
|
||
| On Windows, use `./mvnw.cmd` instead of `./mvnw`. Tests cover all event types, complete metadata, | ||
| exception propagation, and immutable snapshots. `LogMonitorTest` also integrates two producers | ||
| with the shared store and verifies the rendered timeline and selective alerts. | ||
|
|
||
| ### CI/CD integration | ||
|
|
||
| The repository's `.github/workflows/log-deployments-and-changes.yml` defines the manually triggered | ||
| **Log deployments and changes example** workflow. It follows the existing Java 21/Maven setup, | ||
| builds this module, and runs the demonstration. `App` reads `GITHUB_ACTOR` for the initiator. The | ||
| workflow saves the console timeline and alerts as a downloadable artifact. Once the workflow is | ||
| on the default branch, run it from the repository's Actions tab. | ||
|
|
||
| This is a simulated pipeline; it does not deploy the repository's other examples. For a real service, | ||
| wrap its deployment or change command with `DeploymentPipeline.execute`, supplying the actual | ||
| version, environment, and initiator. The operation must throw on failure, including when an external | ||
| command returns a nonzero exit code. Share the event destination across services. Production callers | ||
| should let failures fail the pipeline; only the demo catches its deliberately simulated failure. | ||
|
|
||
| The store is single-threaded and in-memory, and visualization is a console timeline. It does not | ||
| retain history between processes, detect out-of-band changes, or send external notifications. | ||
| Production use needs durable shared collection, delivery handling, and monitoring that overlays | ||
| change timestamps on service metrics. Abrupt process termination can prevent a completion event | ||
| from being written. Descriptions should not contain credentials or raw configuration secrets. | ||
|
|
||
| ## When to Use the Microservices Log Deployments and Changes Pattern in Java | ||
|
|
||
| * Multiple services or teams deploy independently. | ||
| * Operators need to correlate incidents with releases and environment changes. | ||
| * Configuration, endpoint, or protocol changes affect behavior without a new release. | ||
|
|
||
| ## Real-World Applications of Microservices Log Deployments and Changes Pattern in Java | ||
|
|
||
| * Deployment tools can publish release markers alongside application metrics, as described by | ||
| [Microservices.io](https://microservices.io/patterns/observability/log-deployments-and-changes.html). | ||
| * Service delivery pipelines can record releases and configuration updates in one operational history. | ||
|
|
||
| ## Benefits and Trade-offs of Microservices Log Deployments and Changes Pattern | ||
|
|
||
| Benefits: | ||
|
|
||
| * Makes recent changes visible across service and team boundaries. | ||
| * Automates recording at the operation boundary, including failed attempts. | ||
| * Supports filtering by environment, service, type, or outcome. | ||
|
|
||
| Trade-offs: | ||
|
|
||
| * Every deployment and change path must participate for complete history. | ||
| * Durable collection and reliable delivery add operational work. | ||
| * Temporal correlation aids investigation but does not prove causation. | ||
|
|
||
| ## Related Java Design Patterns | ||
|
|
||
| * [Microservices Log Aggregation](../microservices-log-aggregation/README.md): centralizes application logs. | ||
| * [Event Sourcing](../event-sourcing/README.md): reconstructs state from events; this example records operational outcomes. | ||
| * [Observer](../observer/README.md): can notify subscribers when change events arrive. | ||
|
|
||
| ## References and Credits | ||
|
|
||
| * [Pattern: Log deployments and changes](https://microservices.io/patterns/observability/log-deployments-and-changes.html) | ||
| * [Issue #2696](https://github.com/iluwatar/java-design-patterns/issues/2696) |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <!-- | ||
|
|
||
| This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). | ||
|
|
||
| The MIT License | ||
| Copyright © 2014-2022 Ilkka Seppälä | ||
|
|
||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
|
|
||
| The above copyright notice and this permission notice shall be included in | ||
| all copies or substantial portions of the Software. | ||
|
|
||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| THE SOFTWARE. | ||
|
|
||
| --> | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
| <parent> | ||
| <groupId>com.iluwatar</groupId> | ||
| <artifactId>java-design-patterns</artifactId> | ||
| <version>1.26.0-SNAPSHOT</version> | ||
| </parent> | ||
|
|
||
| <artifactId>microservices-log-deployments-and-changes</artifactId> | ||
|
|
||
| <dependencies> | ||
| <dependency> | ||
| <groupId>org.slf4j</groupId> | ||
| <artifactId>slf4j-api</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>ch.qos.logback</groupId> | ||
| <artifactId>logback-classic</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.junit.jupiter</groupId> | ||
| <artifactId>junit-jupiter-engine</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| </dependencies> | ||
| <build> | ||
| <plugins> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-assembly-plugin</artifactId> | ||
| <executions> | ||
| <execution> | ||
| <configuration> | ||
| <archive> | ||
| <manifest> | ||
| <mainClass>com.iluwatar.logdeploymentsandchanges.App</mainClass> | ||
| </manifest> | ||
| </archive> | ||
| </configuration> | ||
| </execution> | ||
| </executions> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
| </project> | ||
86 changes: 86 additions & 0 deletions
86
...-log-deployments-and-changes/src/main/java/com/iluwatar/logdeploymentsandchanges/App.java
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| /* | ||
| * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). | ||
| * | ||
| * The MIT License | ||
| * Copyright © 2014-2022 Ilkka Seppälä | ||
| * | ||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| * of this software and associated documentation files (the "Software"), to deal | ||
| * in the Software without restriction, including without limitation the rights | ||
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| * copies of the Software, and to permit persons to whom the Software is | ||
| * furnished to do so, subject to the following conditions: | ||
| * | ||
| * The above copyright notice and this permission notice shall be included in | ||
| * all copies or substantial portions of the Software. | ||
| * | ||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| * THE SOFTWARE. | ||
| */ | ||
| package com.iluwatar.logdeploymentsandchanges; | ||
|
|
||
| import java.time.Clock; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| /** Demonstrates automatic deployment and change logging for two services. */ | ||
| public class App { | ||
| private static final Logger LOGGER = LoggerFactory.getLogger(App.class); | ||
|
|
||
| /** Run simulated pipeline steps, then display their timeline and failure alerts. */ | ||
| public static void main(String[] args) { | ||
| var store = new CentralLogStore(); | ||
| var pipeline = new DeploymentPipeline(store, Clock.systemUTC()); | ||
| var monitor = new LogMonitor(store); | ||
| var actor = System.getenv().getOrDefault("GITHUB_ACTOR", "release-engineer"); | ||
|
|
||
| pipeline.execute( | ||
| "orders", | ||
| "2.0", | ||
| "production", | ||
| actor, | ||
| ChangeType.DEPLOYMENT, | ||
| "Deploy orders release", | ||
| () -> LOGGER.info("Deploying orders 2.0")); | ||
| pipeline.execute( | ||
| "payments", | ||
| "1.1", | ||
| "production", | ||
| actor, | ||
| ChangeType.CONFIGURATION, | ||
| "Increase request timeout", | ||
| () -> LOGGER.info("Updating payments timeout")); | ||
| pipeline.execute( | ||
| "orders", | ||
| "2.0", | ||
| "production", | ||
| actor, | ||
| ChangeType.ENDPOINT, | ||
| "Route payments to /v2/payments", | ||
| () -> LOGGER.info("Updating payments endpoint")); | ||
| try { | ||
| pipeline.execute( | ||
| "payments", | ||
| "1.1", | ||
| "production", | ||
| actor, | ||
| ChangeType.PROTOCOL, | ||
| "Switch inter-service protocol to gRPC", | ||
| () -> { | ||
| throw new IllegalStateException("Protocol health check failed"); | ||
| }); | ||
| } catch (IllegalStateException exception) { | ||
| LOGGER.warn("Simulated change failed: {}", exception.getMessage()); | ||
| } | ||
|
|
||
| LOGGER.info("Deployment and change timeline:\n{}", monitor.timeline()); | ||
| monitor | ||
| .alerts(event -> !event.successful() && "production".equals(event.environment())) | ||
| .forEach(event -> LOGGER.warn("ALERT: {} {} failed", event.service(), event.type())); | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.