Observability, Monitoring, Logging, and Reporting
Deployment, Release, and Monitoring
Chapter 7: Deployment, Release, and Monitoring
[Content moved from the draft: definitions (deploy/deliver/release); blue/green and canary strategies; feature flags with JSON example and modularity; release management (branching, artifacts, versioning, changelog, GitHub Releases); monitoring and observability; rollbacks with workflow example.]
Application Monitoring
Application monitoring
Deploying your application successfully doesn't always guarantee it's functioning as expected, especially in complex setups with a backend. For instance, refreshing the browser could reset the application since it doesn't maintain state server-side. Errors can also arise from other areas like backend server failures that require restarts, problematic builds that prevent the app from displaying content, or external API issues like the weather data endpoint failing.
- Identifying Potential Errors:
-
Deployment Errors: Check if the application is loading correctly. A blank page or a failure to load could indicate issues with file deployment or script errors within the application.
-
API Dependencies: If your application relies on external APIs (like a weather API), these can fail, be blocked, reach rate limits, or return unexpected responses.
-
Performance Issues: Slow load times can degrade user experience, indicating the need for performance optimization.
CI/CD Observability and Telemetry
[GUAC Docs | GUAC]{.underline} and the need to do automated dependency management (manual dependencies are harder to scan)
[krzko/run-with-telemetry: GitHub Action run
action with OpenTelemetry instrumentation]{.underline}
[inception-health/otel-export-trace-action (github.com)]{.underline}
-
[Improve your software delivery with CI/CD observability and OpenTelemetry]{.underline}
-
[DevOpsWorld 2021 - Embracing Observability in Jenkins with OpenTelemetry]{.underline}
-
[DevOpsWorld 2021 - Who Observes the Watchers? An Observability Journey]{.underline}
-
[Embracing Observability in CI/CD with OpenTelemetry]{.underline}
-
[cdCon Austin 2022 - Making your CI/CD Pipelines Speaking in Tongues with OpenTelemetry]{.underline}
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| [ftp2.osuosl.org/pub/fosdem/2024/ua2220/fosdem-2024-3445-strategic-sampling-architectural-approaches-to-efficient-telemetry.mp4]{.underline} |
| |
| |
| |
|
|
+========================================================================================================================================================================================================================================================================================+
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
Frequent Logging Data Types
Frequent logging data types in Google GitHub Actions workflows
Okay, let's break down the specific kinds of information frequently logged in the run
steps of these workflows, going beyond just the actions performed:
-
Versions:
- Tool Versions: Explicit checks like
cmake --version
,bazel version
,bazelisk --version
,clang --version
,go version
,magika --version
,clang-format --version
. Implicitly logged when tools likesetup-java
,setup-python
,setup-go
,rustup
,actions/setup-node
run or during installation (apt install
,pip install
, etc.). - Dependency Versions: Logged during installation steps (
pip install
,npm install
,apt install
,cargo build
/update
,mvn dependency:go-offline
,conan install
). Checks likecargo outdated
explicitly log version differences. Specific versions are often pinned inuses:
lines (e.g.,actions/checkout@v4
,golangci/golangci-lint-action@v6.5.2
). - OS/Platform Versions: Implicit in the
runs-on:
directive (e.g.,ubuntu-22.04
,macos-14
). Android API levels (matrix.api-level
) are logged. - Language Standard Versions: Explicitly set C++ standards (
-std=c++17
,-std=c++20
). - Build/Release Versions: Calculated from Git tags (
${GITHUB_REF#refs/tags/v}
,${REF:10}
) or commit SHAs (${GITHUB_SHA}
) and often logged viaecho
or used in artifact names/paths. Tools likegoreleaser
log the version being released.
- Tool Versions: Explicit checks like
-
Hashes:
- Commit SHAs: Frequently logged for checkout actions, determining base refs (
${{ github.event.pull_request.base.sha }}
,git merge-base
), identifying the commit being built/tested (${{ github.sha }}
,${{ github.event.pull_request.head.sha }}
), generating build versions, or reporting status (statuses/${{ github.sha }}
). Explicitly logged withgit rev-parse HEAD
orgit describe
. - File Hashes: Used in cache keys (
hashFiles(...)
). - Checksums: Logged by Gradle Wrapper validation (
wrapper-validation-action
). GoReleaser generates checksum files, which are then often logged (e.g., base64 encoded). SLSA verification steps involve checksums. - Container Image Digests: Logged by GoReleaser and used in SLSA provenance generation/verification for images.
- Commit SHAs: Frequently logged for checkout actions, determining base refs (
-
Configuration & Flags:
- Build Types:
Release
,Debug
,RelWithDebInfo
(often viamatrix.build_type
orCMAKE_BUILD_TYPE
). - Compiler/Build Flags:
CMAKE_CXX_FLAGS
,CXXFLAGS
,-march=
,-fsanitize=
,-DBUILD_SHARED_LIBS=ON/OFF
,-DDRACO_TRANSCODER_SUPPORTED=ON/OFF
,-DSNAPPY_REQUIRE_AVX=...
, CMake presets (--preset
). - Tool Arguments: Arguments passed to scripts (
./script.sh arg
), linters (golangci-lint-action
args), tests (pytest -n auto
), build tools (bazel build --config=...
),osv-scanner
args (scan-args
),cibuildwheel
env vars (CIBW_...
). - Environment Variables: Explicitly set via
echo "VAR=value" >> $GITHUB_ENV
or logged viaenv:
blocks in steps. - Targets/Architectures:
TARGET: ${{ matrix.targets[0] }}
,matrix.arch
,--config=android_arm64
,--platform=...
.
- Build Types:
-
File Paths & Names:
- Paths added to
$GITHUB_PATH
. - Paths specified in
actions/cache
oractions/upload-artifact
. - Output directories (
out/dist
,build
,wheelhouse
). - Specific config files being used (
.github/labeler.yml
,debian/control
). - Lists of changed files (
git diff --name-only
). - Artifact names (often including versions/platforms).
- Source/test directories targeted by commands (
./src
,./test
,po/*.po
).
- Paths added to
-
Test Results & Diagnostics:
- Pass/Fail status of individual tests and suites.
- Verbose test output (e.g.,
test_output=errors
,CTEST_OUTPUT_ON_FAILURE=1
). - Specific test names being run or filtered (
--gtest_filter=...
,-E IntegrationTest
). - Code coverage upload status (Codecov, Coveralls).
- JUnit XML report paths/generation (
make junit-regtest
). - Flaky test run counts (
--runs_per_test 50
). flutter doctor -v
output (detailed environment info).- Emulator configuration (API level, target, arch).
-
Linter/Formatter/Static Analysis Results:
- Specific findings (file:line:message) from tools like
clang-format
,clang-tidy
,golangci-lint
,ruff
,black
,flake8
,isort
,mypy
,pytype
,pylint
,gosec
. - Diffs generated by formatters (
clang-format.diff
,go mod tidy -diff
). - SARIF file generation/upload status (CodeQL, OSV Scanner, Gosec).
- License header check results (list of files missing headers).
- API compatibility diffs (
japicmp:cmp
). - Security scan results (OSV Scanner, CodeQL, Gosec, Coverity).
- Scorecard results.
- Specific findings (file:line:message) from tools like
-
Dependency Information:
- Packages being installed/updated (
apt install <pkg>
,pip install <pkg>
). - Cache hit/miss status and keys (
actions/cache
). - Outdated dependency lists (
cargo outdated
). go mod tidy -diff
output.
- Packages being installed/updated (
-
Deployment & Release Information:
- Target tags/branches (
${{ github.ref_name }}
). - Asset upload status and names (
actions/upload-release-asset
, GoReleaser logs). - Publishing status to registries (PyPI, NPM, GHCR, Sonatype, CocoaPods).
- SLSA provenance generation/verification logs.
- Sigstore signing logs.
- Release note paths (
docs/release-notes/...
).
- Target tags/branches (
-
System & Environment Information:
- Cache statistics (
ccache --show-stats
). - Docker system info (
docker info
,docker buildx ls
). - Basic system info like processor count (
getconf _NPROCESSORS_CONF
).
- Cache statistics (
-
Git Operations Details:
- Changed file lists (
git diff --name-only
). - Merge base commit hashes.
- Commit counts (
git rev-list --count
). - Cherry-pick status and target commits.
- Changed file lists (
In essence, while high-level actions are performed, the logs are rich with specific details about versions, hashes, configurations, file paths, test outcomes, static analysis findings, and deployment statuses.
Reporting, Code Coverage and SonarCloud
Reporting, code coverage, etc.
- How do I process code coverage reports? Should I bother with them? How do I compile and aggregate test reports?
- Coverage is the measure of how much the code is covered by tests, usually unit tests. You have to make sure that you understand the limitations and benefits of coverage; otherwise, it stops being a useful metric. For more information, see the Test Coverage Paradox.
These are popular integrations based on actual workflow data (aggregated):
- https://docs.coveralls.io/api-introduction
- https://docs.codeclimate.com/docs/finding-your-test-coverage-token
- https://docs.sonarcloud.io/advanced-setup/ci-based-analysis/github-actions-for-sonarcloud/
- https://docs.codecov.com/docs
So, you should consider how to integrate these tools into your pipeline—understanding what they do and how the results work, etc.
Setting up SonarCloud with GitHub Actions: A Step-by-Step Guide
This guide walks you through integrating SonarCloud code analysis into your GitHub Actions workflow, enabling automated code quality checks with every push or pull request.
Step 1: Generate a SonarCloud Token
- Log in to your SonarCloud account.
- Navigate to “My Account” > “Security”.
- Generate a new token.
- Copy the token value; you’ll need it for the next step.
Step 2: Store the Token as a GitHub Secret
- Go to your GitHub repository.
- Click “Settings” > “Secrets” > “Actions”.
- Click “New repository secret”.
- Name the secret SONAR_TOKEN.
- Paste the SonarCloud token you copied in Step 1 into the “Value” field.
- Save the secret.
Step 3: Define SonarCloud Properties (Project-Specific)
You’ll need to specify these properties for SonarCloud to identify your project. The location of these properties varies depending on your project type.
- Java (Maven): pom.xml
- Java (Gradle): build.gradle
- .NET: Within the SonarScanner command line arguments
- Other: Create a sonar-project.properties file in your repository’s root
Inside these files, set the following:
sonar.projectKey=your-project-key
sonar.organization=your-organization-key
sonar.host.url=https://sonarcloud.io
Replace your-project-key
and your-organization-key
with your actual values from SonarCloud.
Step 4: Create the GitHub Actions Workflow File
- Create a file named
.github/workflows/build.yml
in your repository’s root.
Choose the Workflow Configuration based on your project type:
a) Single Project Workflow
name: SonarCloud Analysis
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened]
jobs:
sonarcloud:
name: SonarCloud Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
b) Monorepo Workflow (Multiple Projects)
name: SonarCloud Monorepo Analysis
on:
push:
branches:
- main
# Add path filters if needed (e.g., - 'project1/**')
pull_request:
types: [opened, synchronize, reopened]
jobs:
sonarcloudScan1:
name: Project 1 Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
projectBaseDir: project1/ # Path to project 1
sonarcloudScan2:
name: Project 2 Scan
runs-on: ubuntu-latest
steps:
# ... (Similar to sonarcloudScan1, but with projectBaseDir: project2/)
c) C/C++ Project Workflow
This workflow simplifies the process by automatically installing necessary tools:
name: SonarCloud C/C++ Analysis
on:
# ... (Trigger events same as above)
jobs:
sonarcloud:
name: SonarCloud Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
Step 5: Commit and Push Your Changes
Commit your updated project configuration files and the .github/workflows/build.yml
file to your repository. This will trigger your first SonarCloud analysis.
Step 6: View the Analysis Report
- Go to your SonarCloud project dashboard.
- You’ll see the results of your code analysis, including code smells, bugs, security vulnerabilities, and code coverage.
Important Notes
- Reusable Workflows: For reusable workflows, use the
secret: inherit
feature to pass the SONAR_TOKEN securely. - Detailed Configuration: For advanced configuration options, refer to the official SonarCloud documentation and the
sonar-project.properties
file. - Language-Specific Setup: For languages not explicitly mentioned, check the SonarCloud documentation for specific setup instructions.