GitHub Actions
Send CI/CD pipeline logs from GitHub Actions to Parseable
Collect and analyze GitHub Actions workflow logs in Parseable for CI/CD observability.
Overview
Integrate GitHub Actions with Parseable to:
- Centralize CI/CD Logs - Collect all workflow logs in one place
- Debug Failures - Quickly find and analyze failed jobs
- Track Performance - Monitor build times and trends
- Audit Pipelines - Maintain compliance with log retention
Prerequisites
- GitHub repository with Actions enabled
- Parseable instance accessible from GitHub Actions runners
- GitHub Personal Access Token (for API access)
Method 1: Direct Log Shipping
Send logs directly from your workflow to Parseable.
Workflow Configuration
Add a step to send logs to Parseable:
name: CI Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
id: build
run: |
echo "Starting build..."
# Your build commands here
npm ci
npm run build
echo "Build completed successfully"
- name: Send logs to Parseable
if: always()
run: |
curl -X POST "${{ secrets.PARSEABLE_URL }}/api/v1/ingest" \
-H "Authorization: Basic ${{ secrets.PARSEABLE_AUTH }}" \
-H "X-P-Stream: github-actions" \
-H "Content-Type: application/json" \
-d '[{
"timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'",
"repository": "${{ github.repository }}",
"workflow": "${{ github.workflow }}",
"job": "${{ github.job }}",
"run_id": "${{ github.run_id }}",
"run_number": "${{ github.run_number }}",
"actor": "${{ github.actor }}",
"event": "${{ github.event_name }}",
"ref": "${{ github.ref }}",
"sha": "${{ github.sha }}",
"status": "${{ job.status }}",
"conclusion": "${{ steps.build.conclusion }}"
}]'Reusable Action
Create a reusable action for consistent logging:
# .github/actions/log-to-parseable/action.yml
name: Log to Parseable
description: Send workflow logs to Parseable
inputs:
parseable_url:
description: Parseable instance URL
required: true
parseable_auth:
description: Base64 encoded credentials
required: true
dataset:
description: Parseable dataset name
default: github-actions
status:
description: Job status
required: true
message:
description: Log message
default: ''
runs:
using: composite
steps:
- name: Send to Parseable
shell: bash
run: |
curl -X POST "${{ inputs.parseable_url }}/api/v1/ingest" \
-H "Authorization: Basic ${{ inputs.parseable_auth }}" \
-H "X-P-Stream: ${{ inputs.dataset }}" \
-H "Content-Type: application/json" \
-d '[{
"timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'",
"repository": "${{ github.repository }}",
"workflow": "${{ github.workflow }}",
"job": "${{ github.job }}",
"run_id": "${{ github.run_id }}",
"run_number": "${{ github.run_number }}",
"actor": "${{ github.actor }}",
"event": "${{ github.event_name }}",
"ref": "${{ github.ref }}",
"sha": "${{ github.sha }}",
"status": "${{ inputs.status }}",
"message": "${{ inputs.message }}"
}]'Use the action in your workflow:
- name: Log success
if: success()
uses: ./.github/actions/log-to-parseable
with:
parseable_url: ${{ secrets.PARSEABLE_URL }}
parseable_auth: ${{ secrets.PARSEABLE_AUTH }}
status: success
message: Build completed successfully
- name: Log failure
if: failure()
uses: ./.github/actions/log-to-parseable
with:
parseable_url: ${{ secrets.PARSEABLE_URL }}
parseable_auth: ${{ secrets.PARSEABLE_AUTH }}
status: failure
message: Build failedMethod 2: OpenTelemetry Tracing
Use OpenTelemetry to trace your CI/CD pipelines.
Workflow with OTEL
name: CI Pipeline with Tracing
on:
push:
branches: [main]
env:
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.PARSEABLE_OTEL_ENDPOINT }}
OTEL_EXPORTER_OTLP_HEADERS: "Authorization=Basic ${{ secrets.PARSEABLE_AUTH }},X-P-Stream=github-actions-traces"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup OTEL CLI
run: |
curl -L https://github.com/equinix-labs/otel-cli/releases/latest/download/otel-cli-linux-amd64 -o otel-cli
chmod +x otel-cli
sudo mv otel-cli /usr/local/bin/
- name: Build with tracing
run: |
otel-cli exec \
--name "build" \
--service "github-actions" \
--attrs "repository=${{ github.repository }},workflow=${{ github.workflow }}" \
-- npm run buildMethod 3: Webhook Integration
Use GitHub webhooks to capture workflow events.
Webhook Receiver
Create a webhook receiver that forwards events to Parseable:
// github-webhook-to-parseable.js
const express = require('express');
const crypto = require('crypto');
const axios = require('axios');
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = process.env.GITHUB_WEBHOOK_SECRET;
const PARSEABLE_URL = process.env.PARSEABLE_URL;
const PARSEABLE_AUTH = process.env.PARSEABLE_AUTH;
function verifySignature(payload, signature) {
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
const digest = 'sha256=' + hmac.update(JSON.stringify(payload)).digest('hex');
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest));
}
app.post('/webhook', async (req, res) => {
const signature = req.headers['x-hub-signature-256'];
if (!verifySignature(req.body, signature)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = req.headers['x-github-event'];
const payload = req.body;
// Only process workflow events
if (event === 'workflow_run' || event === 'workflow_job') {
const logEntry = {
timestamp: new Date().toISOString(),
event_type: event,
action: payload.action,
repository: payload.repository?.full_name,
workflow: payload.workflow?.name || payload.workflow_run?.name,
run_id: payload.workflow_run?.id || payload.workflow_job?.run_id,
conclusion: payload.workflow_run?.conclusion || payload.workflow_job?.conclusion,
actor: payload.sender?.login,
url: payload.workflow_run?.html_url || payload.workflow_job?.html_url
};
try {
await axios.post(`${PARSEABLE_URL}/api/v1/ingest`, [logEntry], {
headers: {
'Authorization': `Basic ${PARSEABLE_AUTH}`,
'X-P-Stream': 'github-webhooks',
'Content-Type': 'application/json'
}
});
} catch (error) {
console.error('Error sending to Parseable:', error);
}
}
res.status(200).json({ status: 'received' });
});
app.listen(3000, () => {
console.log('GitHub webhook receiver listening on port 3000');
});Configure GitHub Webhook
- Go to your repository Settings → Webhooks
- Click Add webhook
- Set Payload URL to your webhook receiver
- Set Content type to
application/json - Set Secret to your webhook secret
- Select events: Workflow runs and Workflow jobs
Querying GitHub Actions Logs
Query your CI/CD logs in Parseable:
-- Get recent workflow runs
SELECT timestamp, repository, workflow, status, actor
FROM "github-actions"
ORDER BY timestamp DESC
LIMIT 100
-- Find failed builds
SELECT timestamp, repository, workflow, run_id, message
FROM "github-actions"
WHERE status = 'failure'
ORDER BY timestamp DESC
-- Build success rate by repository
SELECT
repository,
COUNT(*) as total_runs,
SUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END) as successful,
ROUND(SUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END)::float / COUNT(*) * 100, 2) as success_rate
FROM "github-actions"
WHERE timestamp > NOW() - INTERVAL '7 days'
GROUP BY repository
ORDER BY success_rate ASCGitHub Secrets Configuration
Add these secrets to your repository:
| Secret | Description |
|---|---|
PARSEABLE_URL | Your Parseable instance URL |
PARSEABLE_AUTH | Base64 encoded username:password |
PARSEABLE_OTEL_ENDPOINT | OTEL endpoint (for tracing) |
Best Practices
- Use Secrets - Never hardcode credentials in workflows
- Log on Failure - Always capture failure information
- Include Context - Add repository, workflow, and run details
- Use Consistent Streams - Organize logs by dataset
- Set Retention - Configure appropriate log retention
Troubleshooting
Logs Not Appearing
- Verify Parseable URL is accessible from GitHub runners
- Check authentication credentials are correct
- Verify the dataset exists or auto-creation is enabled
- Check workflow logs for curl errors
Authentication Failures
- Verify Base64 encoding of credentials
- Check the Parseable user has ingest permissions
- Verify secrets are properly configured
Next Steps
- Set up alerts for failed builds
- Create dashboards for CI/CD metrics
- Configure Jenkins for additional pipelines
Was this page helpful?