Skip to content

Commit

Permalink
stats to gcp metrics used;
Browse files Browse the repository at this point in the history
  • Loading branch information
Muneeb147 committed Oct 24, 2024
1 parent 8758d92 commit 646c223
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 2 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/dump_ci_stats.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ jobs:
node-version: '18'

- name: Install GCP Logging Client
run: npm install @google-cloud/logging
run: npm install @google-cloud/logging @google-cloud/monitoring

- name: Run Final Job and Send Logs to GCP
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GCP_CREDENTIALS: ${{ secrets.GCP_CREDENTIALS }}
run: |
node source/dump-ci-stats-to-gcp-logs.js ${{ github.event.workflow_run.id }}
node source/dump-ci-stats-to-gcp-logs.js ${{ github.event.workflow_run.id }} && node source/dump-ci-stats-to-gcp-metrics.js ${{ github.event.workflow_run.id }}
158 changes: 158 additions & 0 deletions source/dump-ci-stats-to-gcp-metrics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
const { Monitoring } = require('@google-cloud/monitoring');
// const fetch = require('node-fetch');

// Parse GCP credentials from environment variables
const gcpCredentials = JSON.parse(process.env.GCP_CREDENTIALS);

// Initialize the Google Cloud Monitoring client
const monitoring = new Monitoring.MetricServiceClient({
projectId: gcpCredentials.project_id,
credentials: {
client_email: gcpCredentials.client_email,
private_key: gcpCredentials.private_key
}
});

// Function to create and send metrics to Google Cloud Monitoring
async function sendMetricsToGCP(metricType, metricValue, labels) {
const projectId = gcpCredentials.project_id;

const request = {
name: monitoring.projectPath(projectId),
resource: {
type: 'global',
labels: {
project_id: projectId
}
},
metric: {
type: `custom.googleapis.com/${metricType}`,
labels: labels
},
points: [
{
interval: {
endTime: {
seconds: Math.floor(Date.now() / 1000)
}
},
value: {
doubleValue: metricValue
}
}
]
};

try {
await monitoring.createTimeSeries(request);
console.log(`Metric ${metricType} sent successfully.`);
} catch (error) {
console.error('Error sending metric:', error);
}
}

// Function to fetch workflow and job details via GitHub API
async function fetchWorkflowDetails() {
const runId = process.argv[2];
const repo = process.env.GITHUB_REPOSITORY;
const apiUrl = `https://api.github.com/repos/${repo}/actions/runs/${runId}`;

try {
const response = await fetch(apiUrl, {
headers: {
'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`,
'Accept': 'application/vnd.github.v3+json'
}
});

if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const data = await response.json();

return {
workflowId: data.id,
workflowName: data.name,
status: data.status, // "completed", "in_progress", etc.
conclusion: data.conclusion, // "success", "failure"
startTime: data.created_at,
endTime: data.updated_at,
trigger: data.event, // "push", "pull_request", etc.
jobs: await fetchJobDetails(repo, data.id) // Fetch individual job details
};
} catch (error) {
console.error('Error fetching workflow details:', error);
process.exit(1);
}
}

// Function to fetch details of individual jobs in a workflow run
async function fetchJobDetails(repo, runId) {
const apiUrl = `https://api.github.com/repos/${repo}/actions/runs/${runId}/jobs`;

try {
const response = await fetch(apiUrl, {
headers: {
'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`,
'Accept': 'application/vnd.github.v3+json'
}
});

if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const data = await response.json();
return data.jobs;
} catch (error) {
console.error('Error fetching job details:', error);
return [];
}
}

// Main function to send metrics
(async () => {
try {
const workflowStats = await fetchWorkflowDetails();

// Send workflow-level metrics
const workflowLabels = {
workflow_name: workflowStats.workflowName,
workflow_id: workflowStats.workflowId,
trigger: workflowStats.trigger
};

const workflowDuration = (new Date(workflowStats.endTime) - new Date(workflowStats.startTime)) / 1000;
await sendMetricsToGCP('ci_workflow_duration', workflowDuration, workflowLabels);

// Send job-level metrics for each job in the workflow
for (const job of workflowStats.jobs) {
const jobLabels = {
workflow_name: workflowStats.workflowName,
job_name: job.name,
runner_name: job.runner_name,
conclusion: job.conclusion
};

const jobExecutionTime = (new Date(job.completed_at) - new Date(job.started_at)) / 1000;
await sendMetricsToGCP('ci_job_execution_time', jobExecutionTime, jobLabels);

// Send job status (1 for success, 0 for failure)
const jobStatus = job.conclusion === 'success' ? 1 : 0;
await sendMetricsToGCP('ci_job_status', jobStatus, jobLabels);

// Capture step-level metrics if needed
for (const step of job.steps) {
const stepExecutionTime = (new Date(step.completed_at) - new Date(step.started_at)) / 1000;
const stepLabels = {
workflow_name: workflowStats.workflowName,
job_name: job.name,
step_name: step.name,
runner_name: job.runner_name
};

await sendMetricsToGCP('ci_step_execution_time', stepExecutionTime, stepLabels);
}
}
} catch (error) {
console.error('Error in main function:', error);
process.exit(1);
}

process.exit(0);
})();

0 comments on commit 646c223

Please sign in to comment.