diff --git a/examples/quickstart/grafana/dashboards/dashboard_jobs_history.json b/examples/quickstart/grafana/dashboards/dashboard_jobs_history.json new file mode 100644 index 00000000..fdceaf56 --- /dev/null +++ b/examples/quickstart/grafana/dashboards/dashboard_jobs_history.json @@ -0,0 +1,707 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Jobs History", + "editable": true, + "gnetId": 10620, + "graphTooltip": 0, + "id": 8, + "iteration": 1652259186805, + "links": [], + "panels": [ + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "center", + "displayMode": "auto", + "filterable": false + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Job ID" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "View job #${__value.numeric}", + "url": "https://${GITLAB_HOST}/${__data.fields.project}/-/jobs/${__value.numeric}" + } + ] + }, + { + "id": "custom.displayMode", + "value": "color-background" + }, + { + "id": "color", + "value": { + "fixedColor": "dark-blue", + "mode": "fixed" + } + }, + { + "id": "custom.width", + "value": 85 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Status" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-background" + }, + { + "id": "color", + "value": { + "mode": "thresholds" + } + }, + { + "id": "mappings", + "value": [ + { + "options": { + "1": { + "color": "green", + "index": 10, + "text": "SUCCESS" + }, + "2": { + "index": 9, + "text": "RUNNING" + }, + "3": { + "index": 8, + "text": "FAILED" + }, + "4": { + "index": 7, + "text": "CANCELED" + }, + "5": { + "index": 6, + "text": "CREATED" + }, + "6": { + "index": 5, + "text": "WAITING FOR RESOURCE" + }, + "7": { + "index": 4, + "text": "PREPARING" + }, + "8": { + "index": 3, + "text": "PENDING" + }, + "9": { + "index": 2, + "text": "SKIPPED" + }, + "10": { + "index": 1, + "text": "MANUAL" + }, + "11": { + "index": 0, + "text": "SCHEDULED" + } + }, + "type": "value" + } + ] + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "light-blue", + "value": 1 + }, + { + "color": "semi-dark-red", + "value": 3 + }, + { + "color": "light-orange", + "value": 5 + }, + { + "color": "rgb(135, 135, 134)", + "value": 9 + } + ] + } + }, + { + "id": "custom.width", + "value": 110 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Project" + }, + "properties": [ + { + "id": "custom.align", + "value": "left" + }, + { + "id": "custom.width", + "value": 217 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ref Kind" + }, + "properties": [ + { + "id": "custom.width", + "value": 98 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ref Name" + }, + "properties": [ + { + "id": "custom.width", + "value": 122 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Duration" + }, + "properties": [ + { + "id": "unit", + "value": "dtdurations" + }, + { + "id": "custom.width", + "value": 150 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Date" + }, + "properties": [ + { + "id": "unit", + "value": "dtdurations" + }, + { + "id": "custom.width", + "value": 150 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Pipeline ID" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "View pipeline #${__value.numeric}", + "url": "https://${GITLAB_HOST}/${__data.fields.project}/-/pipelines/${__value.numeric}" + } + ] + }, + { + "id": "custom.displayMode", + "value": "color-background" + }, + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + }, + { + "id": "custom.width", + "value": 85 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Job Name" + }, + "properties": [ + { + "id": "custom.align", + "value": "left" + }, + { + "id": "custom.width", + "value": 285 + } + ] + } + ] + }, + "gridPos": { + "h": 18, + "w": 19, + "x": 0, + "y": 0 + }, + "id": 119, + "links": [], + "options": { + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Date" + } + ] + }, + "pluginVersion": "8.0.5", + "targets": [ + { + "exemplar": true, + "expr": "max by (project, ref, kind, pipeline_id, job_name, job_id) (max_over_time (gitlab_ci_pipeline_job_id{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", pipeline_id=~\"$PIPELINE_ID\", job_name=~\"$JOB_NAME\", status=~\"$STATUS\", job_id=~\"$JOB_ID\"}[1w]))", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "ID" + }, + { + "exemplar": true, + "expr": "-max by (project, ref, kind, job_name, job_id) (time() - max_over_time (gitlab_ci_pipeline_job_timestamp{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", pipeline_id=~\"$PIPELINE_ID\", job_name=~\"$JOB_NAME\", status=~\"$STATUS\", job_id=~\"$JOB_ID\"}[1w]))", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "Date" + }, + { + "exemplar": true, + "expr": "max by (project, ref, kind, job_name, job_id) (max_over_time (gitlab_ci_pipeline_job_duration_seconds{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", pipeline_id=~\"$PIPELINE_ID\", job_name=~\"$JOB_NAME\", status=~\"$STATUS\", job_id=~\"$JOB_ID\"}[1w]))", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "Duration" + }, + { + "exemplar": true, + "expr": "(max by (project, ref, kind, job_name, job_id) (max_over_time (gitlab_ci_pipeline_job_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", pipeline_id=~\"$PIPELINE_ID\", status=~\"success\", status=~\"$STATUS\", job_name=~\"$JOB_NAME\", job_id=~\"$JOB_ID\"}[1w])) * 1 ) > 0 or\n(max by (project, ref, kind, job_name, job_id) (max_over_time (gitlab_ci_pipeline_job_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", pipeline_id=~\"$PIPELINE_ID\", status=~\"failed\", status=~\"$STATUS\", job_name=~\"$JOB_NAME\", job_id=~\"$JOB_ID\"}[1w])) * 3 ) > 0 or \n(max by (project, ref, kind, job_name, job_id) (max_over_time (gitlab_ci_pipeline_job_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", pipeline_id=~\"$PIPELINE_ID\", status=~\"running\", status=~\"$STATUS\", job_name=~\"$JOB_NAME\", job_id=~\"$JOB_ID\"}[1w])) * 2 ) > 0 or \n(max by (project, ref, kind, job_name, job_id) (max_over_time (gitlab_ci_pipeline_job_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", pipeline_id=~\"$PIPELINE_ID\", status=~\"canceled\", status=~\"$STATUS\", job_name=~\"$JOB_NAME\", job_id=~\"$JOB_ID\"}[1w])) * 4 ) > 0 or \n(max by (project, ref, kind, job_name, job_id) (max_over_time (gitlab_ci_pipeline_job_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", pipeline_id=~\"$PIPELINE_ID\", status=~\"created\", status=~\"$STATUS\", job_name=~\"$JOB_NAME\", job_id=~\"$JOB_ID\"}[1w])) * 5 ) > 0 or \n(max by (project, ref, kind, job_name, job_id) (max_over_time (gitlab_ci_pipeline_job_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", pipeline_id=~\"$PIPELINE_ID\", status=~\"waiting_for_resource\", status=~\"$STATUS\", job_name=~\"$JOB_NAME\", job_id=~\"$JOB_ID\"}[1w])) * 6 ) > 0 or \n(max by (project, ref, kind, job_name, job_id) (max_over_time (gitlab_ci_pipeline_job_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", pipeline_id=~\"$PIPELINE_ID\", status=~\"preparing\", status=~\"$STATUS\", job_name=~\"$JOB_NAME\", job_id=~\"$JOB_ID\"}[1w])) * 7 ) > 0 or \n(max by (project, ref, kind, job_name, job_id) (max_over_time (gitlab_ci_pipeline_job_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", pipeline_id=~\"$PIPELINE_ID\", status=~\"pending\", status=~\"$STATUS\", job_name=~\"$JOB_NAME\", job_id=~\"$JOB_ID\"}[1w])) * 8 ) > 0 or \n(max by (project, ref, kind, job_name, job_id) (max_over_time (gitlab_ci_pipeline_job_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", pipeline_id=~\"$PIPELINE_ID\", status=~\"skipped\", status=~\"$STATUS\", job_name=~\"$JOB_NAME\", job_id=~\"$JOB_ID\"}[1w])) * 9 ) > 0 or \n(max by (project, ref, kind, job_name, job_id) (max_over_time (gitlab_ci_pipeline_job_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", pipeline_id=~\"$PIPELINE_ID\", status=~\"manual\", status=~\"$STATUS\", job_name=~\"$JOB_NAME\", job_id=~\"$JOB_ID\"}[1w])) * 10 ) > 0 or \n(max by (project, ref, kind, job_name, job_id) (max_over_time (gitlab_ci_pipeline_job_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", pipeline_id=~\"$PIPELINE_ID\", status=~\"scheduled\", status=~\"$STATUS\", job_name=~\"$JOB_NAME\", job_id=~\"$JOB_ID\"}[1w])) * 11 ) > 0", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "Status" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "JOBS", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value #A": false, + "Value #ID": true, + "job_id": false, + "job_name": false, + "kind": true + }, + "indexByName": { + "Time": 0, + "Value #Date": 8, + "Value #Duration": 9, + "Value #ID": 4, + "Value #Status": 10, + "job_id": 5, + "job_name": 6, + "kind": 7, + "pipeline_id": 3, + "project": 1, + "ref": 2 + }, + "renameByName": { + "Value #A": "Status", + "Value #B": "Date", + "Value #C": "Duration", + "Value #D": "ID", + "Value #Date": "Date", + "Value #Duration": "Duration", + "Value #ID": "", + "Value #Status": "Status", + "job_id": "Job ID", + "job_name": "Job Name", + "kind": "Ref Kind", + "pipeline_id": "Pipeline ID", + "project": "Project", + "ref": "Ref Name", + "status": "Status" + } + } + } + ], + "type": "table" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "description": null, + "error": null, + "hide": 2, + "label": null, + "name": "GITLAB_HOST", + "query": "gitswarm.f5net.com", + "skipUrlSync": false, + "type": "constant" + }, + { + "allValue": ".*", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "prometheus", + "definition": "label_values(gitlab_ci_pipeline_id, project)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "owner", + "multi": true, + "name": "OWNER", + "options": [], + "query": { + "query": "label_values(gitlab_ci_pipeline_id, project)", + "refId": "prometheus-OWNER-Variable-Query" + }, + "refresh": 2, + "regex": "/(.*)\\/.*$/", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "prometheus", + "definition": "label_values(gitlab_ci_pipeline_id{project=~\"($OWNER).*\"}, project)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "project", + "multi": true, + "name": "PROJECT", + "options": [], + "query": { + "query": "label_values(gitlab_ci_pipeline_id{project=~\"($OWNER).*\"}, project)", + "refId": "prometheus-PROJECT-Variable-Query" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "prometheus", + "definition": "label_values(gitlab_ci_pipeline_id{project=~\"($OWNER).*\",project=~\"$PROJECT\"}, ref)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "ref", + "multi": true, + "name": "REF", + "options": [], + "query": { + "query": "label_values(gitlab_ci_pipeline_id{project=~\"($OWNER).*\",project=~\"$PROJECT\"}, ref)", + "refId": "prometheus-REF-Variable-Query" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "prometheus", + "definition": "label_values(gitlab_ci_pipeline_job_id{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"$STATUS\", job_name=~\"$JOB_NAME\", job_id=~\"$JOB_ID\"}, pipeline_id)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Pipeline ID", + "multi": true, + "name": "PIPELINE_ID", + "options": [], + "query": { + "query": "label_values(gitlab_ci_pipeline_job_id{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"$STATUS\", job_name=~\"$JOB_NAME\", job_id=~\"$JOB_ID\"}, pipeline_id)", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "prometheus", + "definition": "label_values(gitlab_ci_pipeline_job_id{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\"}, job_name)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Job Name", + "multi": true, + "name": "JOB_NAME", + "options": [], + "query": { + "query": "label_values(gitlab_ci_pipeline_job_id{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\"}, job_name)", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": null, + "definition": "label_values(gitlab_ci_pipeline_job_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", job_name=~\"$JOB_NAME\"}, status)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Status", + "multi": true, + "name": "STATUS", + "options": [], + "query": { + "query": "label_values(gitlab_ci_pipeline_job_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", job_name=~\"$JOB_NAME\"}, status)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "prometheus", + "definition": "label_values(gitlab_ci_pipeline_job_id{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", job_name=~\"$JOB_NAME\", status=~\"$STATUS\"}, job_id)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Job ID", + "multi": true, + "name": "JOB_ID", + "options": [], + "query": { + "query": "label_values(gitlab_ci_pipeline_job_id{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", job_name=~\"$JOB_NAME\", status=~\"$STATUS\"}, job_id)", + "refId": "StandardVariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-7d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "GitLab CI Jobs History", + "uid": "gitlab_ci_jobs_history", + "version": 1 +} \ No newline at end of file diff --git a/examples/quickstart/grafana/dashboards/dashboard_pipelines_history.json b/examples/quickstart/grafana/dashboards/dashboard_pipelines_history.json new file mode 100644 index 00000000..2269a828 --- /dev/null +++ b/examples/quickstart/grafana/dashboards/dashboard_pipelines_history.json @@ -0,0 +1,606 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Pipelines History", + "editable": true, + "gnetId": 10620, + "graphTooltip": 0, + "iteration": 1652260913932, + "links": [], + "panels": [ + { + "datasource": null, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "center", + "displayMode": "auto", + "filterable": false + }, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Pipeline ID" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "View pipeline #${__value.numeric}", + "url": "https://${GITLAB_HOST}/${__data.fields.project}/pipelines/${__value.numeric}" + } + ] + }, + { + "id": "custom.displayMode", + "value": "color-background" + }, + { + "id": "color", + "value": { + "fixedColor": "dark-blue", + "mode": "fixed" + } + }, + { + "id": "custom.width", + "value": 85 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Status" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-background" + }, + { + "id": "color", + "value": { + "mode": "thresholds" + } + }, + { + "id": "mappings", + "value": [ + { + "options": { + "1": { + "color": "green", + "index": 10, + "text": "SUCCESS" + }, + "2": { + "index": 9, + "text": "RUNNING" + }, + "3": { + "index": 8, + "text": "FAILED" + }, + "4": { + "index": 7, + "text": "CANCELED" + }, + "5": { + "index": 6, + "text": "CREATED" + }, + "6": { + "index": 5, + "text": "WAITING FOR RESOURCE" + }, + "7": { + "index": 4, + "text": "PREPARING" + }, + "8": { + "index": 3, + "text": "PENDING" + }, + "9": { + "index": 2, + "text": "SKIPPED" + }, + "10": { + "index": 1, + "text": "MANUAL" + }, + "11": { + "index": 0, + "text": "SCHEDULED" + } + }, + "type": "value" + } + ] + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "light-blue", + "value": 1 + }, + { + "color": "semi-dark-red", + "value": 3 + }, + { + "color": "light-orange", + "value": 5 + }, + { + "color": "rgb(135, 135, 134)", + "value": 9 + } + ] + } + }, + { + "id": "custom.width", + "value": 208 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Job" + }, + "properties": [ + { + "id": "custom.align", + "value": "left" + }, + { + "id": "custom.width", + "value": 230 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Project" + }, + "properties": [ + { + "id": "custom.align", + "value": "left" + }, + { + "id": "custom.width", + "value": 229 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ref Kind" + }, + "properties": [ + { + "id": "custom.width", + "value": 98 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Ref Name" + }, + "properties": [ + { + "id": "custom.width", + "value": 122 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Duration" + }, + "properties": [ + { + "id": "unit", + "value": "dtdurations" + }, + { + "id": "custom.width", + "value": 172 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Date" + }, + "properties": [ + { + "id": "unit", + "value": "dtdurations" + }, + { + "id": "custom.width", + "value": 152 + } + ] + } + ] + }, + "gridPos": { + "h": 20, + "w": 22, + "x": 0, + "y": 0 + }, + "id": 120, + "links": [], + "options": { + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Date" + } + ] + }, + "pluginVersion": "8.0.5", + "targets": [ + { + "exemplar": true, + "expr": "max by (project, ref, kind, pipeline_id) (max_over_time (gitlab_ci_pipeline_id{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"$STATUS\", pipeline_id=~\"$PIPELINE_ID\"}[1w]))", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "ID" + }, + { + "exemplar": true, + "expr": "-max by (project, ref, kind, pipeline_id) (time() - max_over_time (gitlab_ci_pipeline_timestamp{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"$STATUS\", pipeline_id=~\"$PIPELINE_ID\"}[1w]))", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "Date" + }, + { + "exemplar": true, + "expr": "max by (project, ref, kind, pipeline_id) (max_over_time (gitlab_ci_pipeline_duration_seconds{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"$STATUS\", pipeline_id=~\"$PIPELINE_ID\"}[1w]))", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "Duration" + }, + { + "exemplar": true, + "expr": "(max by (project, ref, kind, pipeline_id) (max_over_time (gitlab_ci_pipeline_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"success\", status=~\"$STATUS\", pipeline_id=~\"$PIPELINE_ID\"}[1w])) * 1 ) > 0 or\n(max by (project, ref, kind, pipeline_id) (max_over_time (gitlab_ci_pipeline_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"failed\", status=~\"$STATUS\", pipeline_id=~\"$PIPELINE_ID\"}[1w])) * 3 ) > 0 or \n(max by (project, ref, kind, pipeline_id) (max_over_time (gitlab_ci_pipeline_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"running\", status=~\"$STATUS\", pipeline_id=~\"$PIPELINE_ID\"}[1w])) * 2 ) > 0 or \n(max by (project, ref, kind, pipeline_id) (max_over_time (gitlab_ci_pipeline_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"canceled\", status=~\"$STATUS\", pipeline_id=~\"$PIPELINE_ID\"}[1w])) * 4 ) > 0 or \n(max by (project, ref, kind, pipeline_id) (max_over_time (gitlab_ci_pipeline_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"created\", status=~\"$STATUS\", pipeline_id=~\"$PIPELINE_ID\"}[1w])) * 5 ) > 0 or \n(max by (project, ref, kind, pipeline_id) (max_over_time (gitlab_ci_pipeline_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"waiting_for_resource\", status=~\"$STATUS\", pipeline_id=~\"$PIPELINE_ID\"}[1w])) * 6 ) > 0 or \n(max by (project, ref, kind, pipeline_id) (max_over_time (gitlab_ci_pipeline_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"preparing\", status=~\"$STATUS\", pipeline_id=~\"$PIPELINE_ID\"}[1w])) * 7 ) > 0 or \n(max by (project, ref, kind, pipeline_id) (max_over_time (gitlab_ci_pipeline_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"pending\", status=~\"$STATUS\", pipeline_id=~\"$PIPELINE_ID\"}[1w])) * 8 ) > 0 or \n(max by (project, ref, kind, pipeline_id) (max_over_time (gitlab_ci_pipeline_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"skipped\", status=~\"$STATUS\", pipeline_id=~\"$PIPELINE_ID\"}[1w])) * 9 ) > 0 or \n(max by (project, ref, kind, pipeline_id) (max_over_time (gitlab_ci_pipeline_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"manual\", status=~\"$STATUS\", pipeline_id=~\"$PIPELINE_ID\"}[1w])) * 10 ) > 0 or \n(max by (project, ref, kind, pipeline_id) (max_over_time (gitlab_ci_pipeline_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"scheduled\", status=~\"$STATUS\", pipeline_id=~\"$PIPELINE_ID\"}[1w])) * 11 ) > 0", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "", + "refId": "Status" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "PIPELINES", + "transformations": [ + { + "id": "merge", + "options": {} + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value #A": false, + "Value #Status": false, + "job_name": false, + "kind": true, + "pipeline_id": true + }, + "indexByName": { + "Time": 0, + "Value #Date": 5, + "Value #Duration": 6, + "Value #ID": 4, + "Value #Status": 8, + "kind": 2, + "pipeline_id": 7, + "project": 1, + "ref": 3 + }, + "renameByName": { + "Time": "", + "Value #A": "A", + "Value #B": "Date", + "Value #C": "Duration", + "Value #D": "ID", + "Value #Date": "Date", + "Value #Duration": "Duration", + "Value #ID": "Pipeline ID", + "Value #Status": "Status", + "Value #Status222": "", + "job_name": "Job", + "kind": "Ref Kind", + "pipeline_id": "", + "project": "Project", + "ref": "Ref Name", + "status": "Status" + } + } + } + ], + "type": "table" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "description": null, + "error": null, + "hide": 2, + "label": null, + "name": "GITLAB_HOST", + "query": "gitswarm.f5net.com", + "skipUrlSync": false, + "type": "constant" + }, + { + "allValue": ".*", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "prometheus", + "definition": "label_values(gitlab_ci_pipeline_id, project)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "owner", + "multi": true, + "name": "OWNER", + "options": [], + "query": { + "query": "label_values(gitlab_ci_pipeline_id, project)", + "refId": "prometheus-OWNER-Variable-Query" + }, + "refresh": 1, + "regex": "/(.*)\\/.*$/", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": "", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "prometheus", + "definition": "label_values(gitlab_ci_pipeline_id{project=~\"($OWNER).*\"}, project)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "project", + "multi": true, + "name": "PROJECT", + "options": [], + "query": { + "query": "label_values(gitlab_ci_pipeline_id{project=~\"($OWNER).*\"}, project)", + "refId": "prometheus-PROJECT-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "prometheus", + "definition": "label_values(gitlab_ci_pipeline_id{project=~\"($OWNER).*\",project=~\"$PROJECT\"}, ref)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "ref", + "multi": true, + "name": "REF", + "options": [], + "query": { + "query": "label_values(gitlab_ci_pipeline_id{project=~\"($OWNER).*\",project=~\"$PROJECT\"}, ref)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": null, + "definition": "label_values(gitlab_ci_pipeline_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\"}, status)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Status", + "multi": true, + "name": "STATUS", + "options": [], + "query": { + "query": "label_values(gitlab_ci_pipeline_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\"}, status)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": null, + "definition": "label_values(gitlab_ci_pipeline_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"$STATUS\"}, pipeline_id)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Pipeline ID", + "multi": true, + "name": "PIPELINE_ID", + "options": [], + "query": { + "query": "label_values(gitlab_ci_pipeline_status{project=~\"($OWNER).*\",project=~\"$PROJECT\", ref=~\"$REF\", status=~\"$STATUS\"}, pipeline_id)", + "refId": "StandardVariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-7d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "GitLab CI Pipelines History", + "uid": "gitlab_ci_pipelines_history", + "version": 1 +} \ No newline at end of file diff --git a/pkg/controller/collectors.go b/pkg/controller/collectors.go index 126f1e16..191a605e 100644 --- a/pkg/controller/collectors.go +++ b/pkg/controller/collectors.go @@ -4,7 +4,8 @@ import "github.com/prometheus/client_golang/prometheus" var ( defaultLabels = []string{"project", "topics", "kind", "ref", "variables"} - jobLabels = []string{"stage", "job_name", "runner_description"} + jobLabels = []string{"stage", "job_name", "runner_description", "pipeline_id", "job_id", "status"} + pipelineLabels = []string{"pipeline_id", "status"} statusLabels = []string{"status"} environmentLabels = []string{"project", "environment"} environmentInformationLabels = []string{"environment_id", "external_url", "kind", "ref", "latest_commit_short_id", "current_commit_short_id", "available", "username"} @@ -117,7 +118,7 @@ func NewCollectorCoverage() prometheus.Collector { Name: "gitlab_ci_pipeline_coverage", Help: "Coverage of the most recent pipeline", }, - defaultLabels, + append(defaultLabels, pipelineLabels...), ) } @@ -128,7 +129,7 @@ func NewCollectorDurationSeconds() prometheus.Collector { Name: "gitlab_ci_pipeline_duration_seconds", Help: "Duration in seconds of the most recent pipeline", }, - defaultLabels, + append(defaultLabels, pipelineLabels...), ) } @@ -139,7 +140,7 @@ func NewCollectorQueuedDurationSeconds() prometheus.Collector { Name: "gitlab_ci_pipeline_queued_duration_seconds", Help: "Duration in seconds the most recent pipeline has been queued before starting", }, - defaultLabels, + append(defaultLabels, pipelineLabels...), ) } @@ -238,7 +239,7 @@ func NewCollectorID() prometheus.Collector { Name: "gitlab_ci_pipeline_id", Help: "ID of the most recent pipeline", }, - defaultLabels, + append(defaultLabels, pipelineLabels...), ) } @@ -304,7 +305,7 @@ func NewCollectorJobStatus() prometheus.Collector { Name: "gitlab_ci_pipeline_job_status", Help: "Status of the most recent job", }, - append(defaultLabels, append(jobLabels, statusLabels...)...), + append(defaultLabels, jobLabels...), ) } @@ -326,7 +327,7 @@ func NewCollectorStatus() prometheus.Collector { Name: "gitlab_ci_pipeline_status", Help: "Status of the most recent pipeline", }, - append(defaultLabels, "status"), + append(defaultLabels, pipelineLabels...), ) } @@ -337,7 +338,7 @@ func NewCollectorTimestamp() prometheus.Collector { Name: "gitlab_ci_pipeline_timestamp", Help: "Timestamp of the last update of the most recent pipeline", }, - defaultLabels, + append(defaultLabels, pipelineLabels...), ) } @@ -348,6 +349,6 @@ func NewCollectorRunCount() prometheus.Collector { Name: "gitlab_ci_pipeline_run_count", Help: "Number of executions of a pipeline", }, - defaultLabels, + append(defaultLabels, pipelineLabels...), ) } diff --git a/pkg/controller/jobs.go b/pkg/controller/jobs.go index 4c3ecda0..f134460d 100644 --- a/pkg/controller/jobs.go +++ b/pkg/controller/jobs.go @@ -4,6 +4,7 @@ import ( "context" "reflect" "regexp" + "strconv" "github.com/mvisonneau/gitlab-ci-pipelines-exporter/pkg/schemas" log "github.com/sirupsen/logrus" @@ -52,6 +53,9 @@ func (c *Controller) ProcessJobMetrics(ctx context.Context, ref schemas.Ref, job labels := ref.DefaultLabelsValues() labels["stage"] = job.Stage labels["job_name"] = job.Name + labels["status"] = job.Status + labels["job_id"] = strconv.Itoa(job.ID) + labels["pipeline_id"] = strconv.Itoa(job.PipelineID) if ref.Project.Pull.Pipeline.Jobs.RunnerDescription.Enabled { re, err := regexp.Compile(ref.Project.Pull.Pipeline.Jobs.RunnerDescription.AggregationRegexp) diff --git a/pkg/controller/pipelines.go b/pkg/controller/pipelines.go index 750b0ee5..485cc1a1 100644 --- a/pkg/controller/pipelines.go +++ b/pkg/controller/pipelines.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "reflect" + "strconv" "github.com/mvisonneau/gitlab-ci-pipelines-exporter/pkg/schemas" log "github.com/sirupsen/logrus" @@ -72,12 +73,16 @@ func (c *Controller) PullRefMetrics(ctx context.Context, ref schemas.Ref) error return err } + labels := ref.DefaultLabelsValues() + labels["pipeline_id"] = strconv.Itoa(pipeline.ID) + labels["status"] = pipeline.Status + // If the metric does not exist yet, start with 0 instead of 1 // this could cause some false positives in prometheus // when restarting the exporter otherwise runCount := schemas.Metric{ Kind: schemas.MetricKindRunCount, - Labels: ref.DefaultLabelsValues(), + Labels: labels, } storeGetMetric(ctx, c.Store, &runCount) @@ -90,13 +95,13 @@ func (c *Controller) PullRefMetrics(ctx context.Context, ref schemas.Ref) error storeSetMetric(ctx, c.Store, schemas.Metric{ Kind: schemas.MetricKindCoverage, - Labels: ref.DefaultLabelsValues(), + Labels: labels, Value: pipeline.Coverage, }) storeSetMetric(ctx, c.Store, schemas.Metric{ Kind: schemas.MetricKindID, - Labels: ref.DefaultLabelsValues(), + Labels: labels, Value: float64(pipeline.ID), }) @@ -104,7 +109,7 @@ func (c *Controller) PullRefMetrics(ctx context.Context, ref schemas.Ref) error ctx, c.Store, schemas.MetricKindStatus, - ref.DefaultLabelsValues(), + labels, statusesList[:], pipeline.Status, ref.Project.OutputSparseStatusMetrics, @@ -112,19 +117,19 @@ func (c *Controller) PullRefMetrics(ctx context.Context, ref schemas.Ref) error storeSetMetric(ctx, c.Store, schemas.Metric{ Kind: schemas.MetricKindDurationSeconds, - Labels: ref.DefaultLabelsValues(), + Labels: labels, Value: pipeline.DurationSeconds, }) storeSetMetric(ctx, c.Store, schemas.Metric{ Kind: schemas.MetricKindQueuedDurationSeconds, - Labels: ref.DefaultLabelsValues(), + Labels: labels, Value: pipeline.QueuedDurationSeconds, }) storeSetMetric(ctx, c.Store, schemas.Metric{ Kind: schemas.MetricKindTimestamp, - Labels: ref.DefaultLabelsValues(), + Labels: labels, Value: pipeline.Timestamp, }) diff --git a/pkg/schemas/jobs.go b/pkg/schemas/jobs.go index 9f7f2f17..068a2e1f 100644 --- a/pkg/schemas/jobs.go +++ b/pkg/schemas/jobs.go @@ -7,6 +7,7 @@ import ( // Job .. type Job struct { ID int + PipelineID int Name string Stage string Timestamp float64 @@ -42,6 +43,7 @@ func NewJob(gj goGitlab.Job) Job { return Job{ ID: gj.ID, + PipelineID: gj.Pipeline.ID, Name: gj.Name, Stage: gj.Stage, Timestamp: timestamp,