GitHub Actions
Send deployment markers to Last9 from GitHub Actions workflows to correlate deployments with service performance and error rates.
The Last9 Deployment Marker action sends deployment markers to Last9’s Change Events API directly from your GitHub Actions workflows. Deployment events appear as overlays on your service dashboards, letting you correlate releases with performance changes, error spikes, and APDEX shifts.
Prerequisites
- A Last9 account with an API refresh token (write scope). See Getting Started with API to generate one.
- Your Last9 organization slug (the
{org}segment in your Last9 dashboard URL). - The
envvalue must match thedeployment_environmentlabel on your APM services for automatic dashboard correlation.
Store your refresh token as a GitHub Actions secret named LAST9_REFRESH_TOKEN.
Setup
Add the action to any job in your workflow:
- name: Mark deployment in Last9 uses: last9/deployment-marker-action@v1 with: refresh_token: ${{ secrets.LAST9_REFRESH_TOKEN }} org_slug: your-org-slug env: productionBy default, this sends a stop event with event_name: deployment. The service_name defaults to your repository name.
Configuration Reference
| Input | Required | Default | Description |
|---|---|---|---|
refresh_token | Yes | — | Last9 API refresh token with write scope |
org_slug | Yes | — | Your Last9 organization slug |
env | Yes | — | Deployment environment. Must match your APM deployment_environment label exactly for dashboard correlation |
service_name | No | Repository name | Service identifier. Must match your APM service_name label for dashboard correlation |
event_state | No | stop | start, stop, or both. Use both to fire start and stop atomically from a single step |
event_name | No | deployment | Custom label for the event. Appears as a label on the resulting last9_change_events metric |
custom_attributes | No | — | Additional metadata as a JSON string (e.g. {"team":"platform","ticket":"ENG-123"}) |
include_github_attributes | No | true | Automatically attach workflow context: commit SHA, actor, branch, run ID, and repository |
api_base_url | No | https://app.last9.io | Override the Last9 API base URL |
max_retry_attempts | No | 3 | Number of retry attempts with exponential backoff on failure |
Outputs
| Output | Description |
|---|---|
success | true if the event was delivered successfully |
start_timestamp | ISO8601 timestamp of the start event (when event_state is start or both) |
stop_timestamp | ISO8601 timestamp of the stop event (when event_state is stop or both) |
CI/CD Workflows
Mark deployment complete
The simplest pattern — a single step that fires both start and stop atomically after the deployment finishes:
jobs: deploy: runs-on: ubuntu-latest steps: - name: Deploy run: ./deploy.sh
- name: Mark deployment in Last9 if: always() uses: last9/deployment-marker-action@v1 with: refresh_token: ${{ secrets.LAST9_REFRESH_TOKEN }} org_slug: your-org-slug env: production event_state: bothTrack deployment duration
Use start and stop events to bracket the actual deploy step and capture deployment duration on your dashboards:
jobs: deploy: runs-on: ubuntu-latest steps: - name: Mark deployment start uses: last9/deployment-marker-action@v1 with: refresh_token: ${{ secrets.LAST9_REFRESH_TOKEN }} org_slug: your-org-slug env: production event_state: start
- name: Deploy run: ./deploy.sh
- name: Mark deployment complete if: always() uses: last9/deployment-marker-action@v1 with: refresh_token: ${{ secrets.LAST9_REFRESH_TOKEN }} org_slug: your-org-slug env: production event_state: stopTrack rollbacks
Use a distinct event_name to distinguish rollbacks from regular deployments:
- name: Mark rollback in Last9 if: always() uses: last9/deployment-marker-action@v1 with: refresh_token: ${{ secrets.LAST9_REFRESH_TOKEN }} org_slug: your-org-slug env: production event_state: both event_name: rollback custom_attributes: '{"rolled_back_to": "${{ env.PREVIOUS_VERSION }}"}'Multi-environment deployments
Use github.event.inputs or a matrix to pass the environment dynamically:
on: workflow_dispatch: inputs: environment: description: "Target environment" required: true default: staging
jobs: deploy: runs-on: ubuntu-latest steps: - name: Deploy run: ./deploy.sh ${{ github.event.inputs.environment }}
- name: Mark deployment in Last9 if: always() uses: last9/deployment-marker-action@v1 with: refresh_token: ${{ secrets.LAST9_REFRESH_TOKEN }} org_slug: your-org-slug env: ${{ github.event.inputs.environment }} event_state: bothCustom attributes
Attach additional context — version, team, ticket ID — as queryable labels on the last9_change_events metric:
- name: Mark deployment in Last9 if: always() uses: last9/deployment-marker-action@v1 with: refresh_token: ${{ secrets.LAST9_REFRESH_TOKEN }} org_slug: your-org-slug env: production service_name: payments-api event_state: both custom_attributes: > { "version": "${{ github.sha }}", "team": "platform", "ticket_id": "${{ github.event.head_commit.message }}" }Auto-captured GitHub Context
When include_github_attributes is true (the default), the action automatically attaches the following to every event:
| Attribute | Source |
|---|---|
github_sha | github.sha — the commit being deployed |
github_actor | github.actor — the user who triggered the workflow |
github_ref | github.ref — the branch or tag ref |
github_run_id | github.run_id — links back to the workflow run |
github_repository | github.repository — the repo name |
These labels are queryable in PromQL alongside your custom attributes:
last9_change_events{event_name="deployment", github_actor="alice"}Service Dashboard Correlation
For deployment markers to appear as overlays on your Last9 service dashboards, two values must match your APM data exactly:
envmust equal thedeployment_environmentlabel on your APM servicesservice_namemust equal theservice_namelabel on your APM services (defaults to the repository name if not set)
When both match, every deployment event appears as a vertical marker on your APDEX, response time, throughput, and error rate charts. See Change Events for details on storage, PromQL queries, and visualisation options.
Troubleshooting
Please get in touch with us on Discord or Email if you have any questions.