Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/workflows/example-workflow-01.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ name: Example Workflow 01

on:
push:
branches:
- main
- getting-started

jobs:
example-app:
Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/example-workflow-02.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ name: Example Workflow 02

on:
push:
branches:
- main
- getting-started

jobs:
example-app:
Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/example-workflow-03.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ name: Example Workflow 03

on:
push:
branches:
- main
- getting-started

jobs:
example-app:
Expand Down
214 changes: 214 additions & 0 deletions .github/workflows/validate-action-output.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
name: Validate Action Output
# Reusable workflow for testing the GitHub Action with OpenTelemetry collector validation
# This workflow can be used to test different trigger events (push, workflow_run, etc.)
#
# To update test data for any workflow using this reusable workflow:
# 1. Run the calling workflow (by pushing changes, creating PR, or triggering workflow_run)
# 2. After workflow completion, download the artifact from the GitHub Actions run page
# 3. Extract the artifact and copy traces.json and metrics.json to the appropriate .github/test-data/ directory
# 4. Commit and push the updated test data files

on:
workflow_call:
inputs:
test-data-directory:
description:
'Directory name under .github/test-data/ for expected test data'
required: true
type: string
artifact-name:
description: 'Name for the collector logs artifact'
required: false
type: string
default: 'collector-logs'
retention-days:
description: 'Number of days to retain the artifact'
required: false
type: number
default: 5

jobs:
test-action:
name: GitHub Actions Test
runs-on: ubuntu-latest

steps:
- name: Checkout
id: checkout
uses: actions/checkout@v4

# Create directory with proper permissions
- name: Create log directory with proper permissions
run: |
mkdir -p collector-logs
chmod 777 collector-logs

# Start OpenTelemetry Collector manually after checkout
- name: Start OpenTelemetry Collector
# port 13133 is used for health checks, 4318 for OTLP HTTP endpoint
run: |
echo "Starting OpenTelemetry Collector with custom configuration..."
docker run -d \
--name otel-collector \
-p 13133:13133 \
-p 4318:4318 \
-v ${{ github.workspace }}/.github/configs/otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml:ro \
-v ${{ github.workspace }}/collector-logs:/collector-logs \
--health-cmd "wget --no-verbose --tries=1 --spider http://localhost:13133/ || exit 1" \
--health-interval 10s \
--health-timeout 5s \
--health-retries 3 \
otel/opentelemetry-collector-contrib:0.115.1

# Wait for collector to be healthy and ready
- name: Wait for collector to be ready
run: |
echo "Waiting for OpenTelemetry Collector to be ready..."
timeout 60s bash -c 'until docker ps | grep -q "healthy.*otel-collector"; do sleep 2; echo "Waiting for collector health check..."; done'
echo "Collector is ready"

# Define JQ filters for normalization (setting dynamic fields to fixed values)
- name: Set JQ filters for normalization
id: set-jq-filters
run: |
# JQ filter for trace normalization
cat > /tmp/normalize-traces.jq << 'EOF'
.resourceSpans[]?.scopeSpans[]?.spans[]? |= (
.traceId = "00000000000000000000000000000000" |
.spanId = "0000000000000000" |
.parentSpanId = "0000000000000000" |
.startTimeUnixNano = "0000000000000000000" |
.endTimeUnixNano = "0000000000000000000"
) |
.resourceSpans[]?.scopeSpans[]?.spans[]?.attributes[]? |= (
if .key == "run_id" then .value = {"intValue": "0"}
elif .key == "job.id" then .value = {"intValue": "0"}
elif .key == "url" then .value = {"stringValue": "https://example.com/actions/runs/0"}
elif .key == "runner.name" then .value = {"stringValue": "GitHub Actions 0"}
else .
end
)
EOF

# JQ filter for metrics normalization
cat > /tmp/normalize-metrics.jq << 'EOF'
.resourceMetrics[]?.scopeMetrics[]?.metrics[]?.gauge?.dataPoints[]? |= (
.startTimeUnixNano = "0000000000000000000" |
.timeUnixNano = "0000000000000000000" |
.asDouble = 0
)
EOF

# Execute the GitHub Action which sends telemetry data to the collector
- name: Test Local Action
id: test-action
uses: ./
env:
OTEL_SERVICE_NAME: github-actions-opentelemetry
# Point to local collector service (not external endpoint)
OTEL_EXPORTER_OTLP_ENDPOINT: http://localhost:4318
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

# Upload collector logs as GitHub artifact for debugging
- name: Upload collector logs as artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.artifact-name }}
path: collector-logs/
retention-days: ${{ inputs.retention-days }}

# Validate that collector generated the expected JSON log files with correct content
- name: Validate collector logs (Traces)
run: |
echo "=== Validating traces data ==="
if [ -f "collector-logs/traces.json" ]; then
echo "✓ Traces file found"
echo "Traces content preview (first 5 lines):"
head -5 collector-logs/traces.json

# Check if traces file has content
if [ -s "collector-logs/traces.json" ]; then
echo "✓ Traces data received"

# Validate traces structure matches expected format by comparing with test data
echo "=== Validating trace structure ==="
if [ -f ".github/test-data/${{ inputs.test-data-directory }}/traces.json" ]; then
# Apply jq transformation to remove dynamic fields from collected traces
jq -f /tmp/normalize-traces.jq collector-logs/traces.json > collector-logs/traces-normalized.json

# Apply same transformation to expected test data
jq -f /tmp/normalize-traces.jq .github/test-data/${{ inputs.test-data-directory }}/traces.json > collector-logs/traces-expected.json

# Compare normalized traces
if diff collector-logs/traces-normalized.json collector-logs/traces-expected.json > /dev/null; then
echo "✓ Trace structure matches expected format"
else
echo "✗ Trace structure differs from expected format"
echo "=== Differences ==="
diff collector-logs/traces-normalized.json collector-logs/traces-expected.json || true
exit 1
fi
else
echo "⚠ Test data file not found, skipping structure validation"
fi
else
echo "⚠ Traces file is empty"
fi
else
echo "⚠ Traces file not found (no trace data received)"
fi

- name: Validate collector logs (Metrics)
run: |
echo "=== Validating metrics data ==="
if [ -f "collector-logs/metrics.json" ]; then
echo "✓ Metrics file found"
echo "Metrics content preview (first 5 lines):"
head -5 collector-logs/metrics.json

# Check if metrics file has content
if [ -s "collector-logs/metrics.json" ]; then
echo "✓ Metrics data received"

# Validate metrics structure matches expected format by comparing with test data
echo "=== Validating metrics structure ==="
if [ -f ".github/test-data/${{ inputs.test-data-directory }}/metrics.json" ]; then
# Apply jq transformation to remove dynamic fields from collected metrics
jq -f /tmp/normalize-metrics.jq collector-logs/metrics.json > collector-logs/metrics-normalized.json

# Apply same transformation to expected test data
jq -f /tmp/normalize-metrics.jq .github/test-data/${{ inputs.test-data-directory }}/metrics.json > collector-logs/metrics-expected.json

# Compare normalized metrics
if diff collector-logs/metrics-normalized.json collector-logs/metrics-expected.json > /dev/null; then
echo "✓ Metrics structure matches expected format"
else
echo "✗ Metrics structure differs from expected format"
echo "=== Differences ==="
diff collector-logs/metrics-normalized.json collector-logs/metrics-expected.json || true
exit 1
fi
else
echo "⚠ Test data file not found, skipping structure validation"
fi
else
echo "⚠ Metrics file is empty"
fi
else
echo "⚠ Metrics file not found (no metrics data received)"
fi

# Show final collector status and logs for debugging
- name: Show collector debug info
if: always()
run: |
echo "=== Final collector status ==="
docker ps -a | grep otel-collector || echo "Collector container not found"

echo "=== Complete collector logs ==="
docker logs otel-collector || echo "Could not retrieve collector logs"

echo "=== All generated files ==="
find collector-logs -type f -exec echo "File: {}" \; -exec head -10 {} \; -exec echo "---" \; 2>/dev/null || echo "No files found"
5 changes: 4 additions & 1 deletion .github/workflows/workflow-run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ name: Workflow Run Tests

on:
workflow_run:
workflows: ['Push Tests']
workflows:
- Example Workflow 01
- Example Workflow 02
- Example Workflow 03
types:
- completed

Expand Down
Loading