Skip to content
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c3e4e20
Initial plan for issue
Copilot Jun 3, 2025
22abf3a
Add Grafana dashboard examples for Symfony metrics visualization
Copilot Jun 3, 2025
01f0494
Add comprehensive dashboard verification and demo environment
Copilot Jun 3, 2025
ed40dc1
Add dashboard screenshots and verification tools
Copilot Jun 3, 2025
c32156f
Add GitHub Actions workflow for automated Grafana dashboard integrati…
Copilot Jun 3, 2025
3746b26
Fix Grafana workflow hanging and duplicate execution issues
Copilot Jun 3, 2025
5046792
Fix Puppeteer screenshot 'clip' and 'fullPage' mutually exclusive error
Copilot Jun 3, 2025
8243d55
Fix demo docker-compose volume mount issue and improve Symfony app co…
Copilot Jun 3, 2025
fa2c883
Fix Symfony demo app bootstrap issues: add .htaccess, update Kernel, …
Copilot Jun 3, 2025
db38549
Successfully fix Symfony demo app - metrics endpoint now working
Copilot Jun 3, 2025
7a303b2
Fix demo application issues: controller service configuration, APCu s…
Copilot Jun 3, 2025
60dce2e
Extract inline scripts from workflow to separate files
Copilot Jun 3, 2025
3ec34d1
Fix GitHub Actions workflow: add push trigger and fix missing newlines
Copilot Jun 3, 2025
b52114e
Fix missing newlines in script files
Copilot Jun 3, 2025
4bedecf
Add CustomMetricsCollector to demo app for app_version metric
Copilot Jun 3, 2025
67678b9
Add diverse exception types to demo app for "Exceptions by Class" das…
Copilot Jun 3, 2025
dc960b4
Fix missing newlines in all configuration and JSON files
Copilot Jun 3, 2025
757b4ad
Fix missing newlines in all PR files and enhance exception generation…
Copilot Jun 3, 2025
0d71bc3
Replace fake screenshots with real Grafana dashboard screenshots and …
Copilot Jun 3, 2025
d52a029
Remove DASHBOARD_VERIFICATION.md file as requested
Copilot Jun 4, 2025
3865c5e
Fix Grafana integration tests and php-cs-fixer issues
Copilot Jun 4, 2025
993c7d5
Add Playwright alternative for Grafana screenshot capture
Copilot Jun 4, 2025
0462830
Split Grafana integration workflows into separate Puppeteer and Playw…
Copilot Jun 4, 2025
caa4b26
Fix Playwright login issues with robust error handling
Copilot Jun 4, 2025
8a22657
Fix Playwright Grafana frontend loading issues with robust retry logic
Copilot Jun 4, 2025
f23dd6c
Fix duplicate 'run' key in Playwright workflow YAML
Copilot Jun 4, 2025
e2149df
Fix flawed Grafana frontend check logic in Playwright workflow
Copilot Jun 4, 2025
ce906f5
Fix Grafana frontend check logic to properly detect error state
Copilot Jun 4, 2025
83c00e0
Simplify Grafana readiness check to use only health endpoint
Copilot Jun 4, 2025
0ab44d5
Remove unnecessary debug steps from Playwright workflow
Copilot Jun 4, 2025
87d7772
Remove incorrect frontend check from Playwright script
Copilot Jun 4, 2025
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
486 changes: 486 additions & 0 deletions .github/scripts/capture-screenshots-playwright.js

Large diffs are not rendered by default.

161 changes: 161 additions & 0 deletions .github/scripts/capture-screenshots.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
const puppeteer = require('puppeteer');
const fs = require('fs');

async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

async function waitForGrafana() {
console.log('Waiting for Grafana to be ready...');
for (let i = 0; i < 60; i++) {
try {
const response = await fetch('http://localhost:3000/api/health');
if (response.ok) {
console.log('Grafana is ready!');
return true;
}
} catch (e) {
// Grafana not ready yet
}
await sleep(2000);
}
throw new Error('Grafana failed to start');
}

async function captureScreenshots() {
await waitForGrafana();

const browser = await puppeteer.launch({
headless: 'new',
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu',
'--disable-web-security',
'--disable-features=VizDisplayCompositor'
]
});

const page = await browser.newPage();
await page.setViewport({ width: 1920, height: 1080 });

// Set longer timeouts
page.setDefaultTimeout(60000);
page.setDefaultNavigationTimeout(60000);

// Login to Grafana
console.log('Logging into Grafana...');
await page.goto('http://localhost:3000/login');
await page.waitForSelector('input[name="user"]', { timeout: 30000 });
await page.type('input[name="user"]', 'admin');
await page.type('input[name="password"]', 'admin');
await page.click('button[type="submit"]');

// Skip password change if prompted
try {
await page.waitForSelector('button[aria-label="Skip"]', {
timeout: 5000
});
await page.click('button[aria-label="Skip"]');
console.log('Skipped password change');
} catch (e) {
console.log('No password change prompt found');
}

// Wait for main page to load
try {
await page.waitForSelector('[data-testid="data-testid Nav"]', { timeout: 15000 });
console.log('Grafana navigation loaded');
} catch (e) {
console.log('Alternative loading method...');
await sleep(10000);
}

// Create screenshots directory
if (!fs.existsSync('screenshots')) {
fs.mkdirSync('screenshots');
}

console.log('Waiting 5 minutes for metrics to accumulate before taking screenshots...');
await sleep(300000); // Wait 5 minutes (300,000 milliseconds)
console.log('5 minute wait completed, proceeding with screenshots...');

// Function to capture dashboard with retry logic
async function captureDashboard(dashboardId, name, filename) {
console.log(`Capturing ${name} dashboard...`);
// Set time range to last 5 minutes and refresh every 5 seconds
const dashboardUrl = `http://localhost:3000/d/${dashboardId}?orgId=1&refresh=5s&from=now-5m&to=now&kiosk=tv`;

try {
await page.goto(dashboardUrl, { waitUntil: 'networkidle0', timeout: 45000 });

// Wait for dashboard content - try multiple selectors
let dashboardLoaded = false;
const selectors = [
'.react-grid-layout',
'.dashboard-container',
'[data-testid="dashboard-grid"]',
'.panel-container',
'.grafana-panel'
];

for (const selector of selectors) {
try {
await page.waitForSelector(selector, { timeout: 10000 });
console.log(`Dashboard loaded with selector: ${selector}`);
dashboardLoaded = true;
break;
} catch (e) {
console.log(`Selector ${selector} not found, trying next...`);
}
}

if (!dashboardLoaded) {
console.log('Waiting for any dashboard content...');
await sleep(15000); // Give it more time
}

// Wait additional time for data to load
await sleep(10000);

// Take screenshot
await page.screenshot({
path: `screenshots/${filename}`,
fullPage: true
});

console.log(`Screenshot saved: ${filename}`);

} catch (error) {
console.error(`Error capturing ${name}: ${error.message}`);
// Try to take a screenshot anyway for debugging
try {
await page.screenshot({
path: `screenshots/${filename.replace('.png', '-error.png')}`,
fullPage: true
});
} catch (e) {
console.error('Failed to take error screenshot');
}
}
}

// Capture both dashboards
await captureDashboard(
'symfony-app-overview',
'Symfony Application Overview',
'symfony-app-overview-dashboard-live.png'
);

await captureDashboard(
'symfony-app-monitoring',
'Symfony Application Monitoring',
'symfony-app-monitoring-dashboard-live.png'
);

await browser.close();
console.log('Screenshot capture completed!');
}

captureScreenshots().catch(console.error);
85 changes: 85 additions & 0 deletions .github/scripts/generate-traffic.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/bin/bash

echo "Waiting for Symfony app to be ready..."
for i in {1..30}; do
if curl -s http://localhost:8080/ > /dev/null; then
echo "Symfony app is ready!"
break
fi
sleep 2
echo "Attempt $i/30..."
done

# Check if we should run continuously (for background execution)
if [ "$1" = "--continuous" ]; then
echo "Starting continuous traffic generation..."

# Run for approximately 5 minutes (300 seconds)
START_TIME=$(date +%s)
DURATION=300

while [ $(($(date +%s) - START_TIME)) -lt $DURATION ]; do
# Generate variety of requests every few seconds
curl -s http://localhost:8080/ > /dev/null &
curl -s http://localhost:8080/api/users > /dev/null &
curl -s http://localhost:8080/health > /dev/null &

# Some error requests for exception metrics
curl -s http://localhost:8080/api/error > /dev/null &
curl -s http://localhost:8080/api/database-error > /dev/null &
curl -s http://localhost:8080/api/validation-error > /dev/null &

# Occasional 404s and slow requests
if [ $((RANDOM % 10)) -eq 0 ]; then
curl -s http://localhost:8080/nonexistent > /dev/null &
fi

if [ $((RANDOM % 15)) -eq 0 ]; then
curl -s http://localhost:8080/api/slow > /dev/null &
fi

sleep 2
done

echo "Continuous traffic generation completed after 5 minutes"
exit 0
fi

echo "Generating test traffic to populate metrics..."

# Generate successful requests
for i in {1..50}; do
curl -s http://localhost:8080/ > /dev/null &
curl -s http://localhost:8080/api/users > /dev/null &
curl -s http://localhost:8080/health > /dev/null &
sleep 0.2
done

# Generate error requests to populate exception metrics with more variety
for i in {1..50}; do
curl -s http://localhost:8080/api/error > /dev/null &
curl -s http://localhost:8080/api/database-error > /dev/null &
curl -s http://localhost:8080/api/validation-error > /dev/null &
sleep 0.2
done

# Additional error generation for better exception metrics
for i in {1..25}; do
curl -s http://localhost:8080/api/error > /dev/null &
sleep 0.1
done

# Generate some 404s
for i in {1..10}; do
curl -s http://localhost:8080/nonexistent > /dev/null &
sleep 0.1
done

# Generate some slower requests
for i in {1..20}; do
curl -s http://localhost:8080/api/slow > /dev/null &
sleep 0.5
done

wait
echo "Traffic generation completed!"
11 changes: 11 additions & 0 deletions .github/scripts/grafana/provisioning/dashboards/symfony.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: 1
providers:
- name: 'Symfony Dashboards'
orgId: 1
folder: ''
type: file
disableDeletion: false
updateIntervalSeconds: 10
allowUiUpdates: true
options:
path: /etc/grafana/provisioning/dashboards
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: true
15 changes: 15 additions & 0 deletions .github/scripts/setup-grafana-provisioning.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash

# Create Grafana provisioning directories
mkdir -p demo/grafana/provisioning/dashboards
mkdir -p demo/grafana/provisioning/datasources

# Copy provisioning configuration files
cp .github/scripts/grafana/provisioning/datasources/prometheus.yml demo/grafana/provisioning/datasources/
cp .github/scripts/grafana/provisioning/dashboards/symfony.yml demo/grafana/provisioning/dashboards/

# Copy the dashboard JSON files to the provisioning directory
cp grafana/symfony-app-overview.json demo/grafana/provisioning/dashboards/
cp grafana/symfony-app-monitoring.json demo/grafana/provisioning/dashboards/

echo "Grafana provisioning setup completed!"
Loading
Loading