Skip to content
27 changes: 27 additions & 0 deletions .chloggen/gh-job-spans.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: githubreceiver

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: add GitHub workflow job spans

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [38016]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: []
17 changes: 11 additions & 6 deletions receiver/githubreceiver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,19 @@ see the [Scraping README][ghsread].

## Traces - Getting Started

Workflow tracing support is actively being added to the GitHub receiver.
This is accomplished through the processing of GitHub Actions webhook
events for workflows and jobs. The [`workflow_job`][wjob] and
Workflow tracing support is accomplished through the processing of GitHub
Actions webhook events for workflows and jobs. The [`workflow_job`][wjob] and
[`workflow_run`][wrun] event payloads are then constructed into `trace`
telemetry.

Each GitHub Action workflow or job, along with its steps, are converted
into trace spans, allowing the observation of workflow execution times,
success, and failure rates.
success, and failure rates. Each Trace and Span ID is deterministic. This
enables the underlying actions to emit telemetry from any command running in any
step. This can be achieved by using tools like the [run-with-telemetry
action][run] and [otel-cli][otcli]. The key is generating IDs in the same way
that this GitHub receiver does. The [trace_event_handling.go][tr] file contains
the `new*ID` functions that generate deterministic IDs.

### Receiver Configuration

Expand Down Expand Up @@ -179,8 +183,6 @@ To configure a GitHub App, you will need to create a new GitHub App within your
organization. Refer to the general [GitHub App documentation][ghapp] for how to
create a GitHub App. During the subscription phase, subscribe to `workflow_run` and `workflow_job` events.

> NOTE: Only `workflow_run` events are supported in created traces at this time.

[wjob]: https://docs.github.com/en/webhooks/webhook-events-and-payloads#workflow_job
[wrun]: https://docs.github.com/en/webhooks/webhook-events-and-payloads#workflow_run
[valid]: https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries
Expand All @@ -190,3 +192,6 @@ create a GitHub App. During the subscription phase, subscribe to `workflow_run`
[doracap]: https://dora.dev/capabilities/
[dorafour]: https://dora.dev/guides/dora-metrics-four-keys/
[ghapp]: https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/registering-a-github-app
[run]: https://github.com/krzko/run-with-telemetry
[otcli]: https://github.com/equinix-labs/otel-cli
[tr]: ./trace_event_handling.go
71 changes: 69 additions & 2 deletions receiver/githubreceiver/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ const (
AttributeCICDPipelineTaskRunSenderLogin = "cicd.pipeline.task.run.sender.login" // GitHub's Task Sender Login
AttributeCICDPipelineFilePath = "cicd.pipeline.file.path" // GitHub's Path in workflow_run
AttributeCICDPipelinePreviousAttemptURLFull = "cicd.pipeline.run.previous_attempt.url.full"
AttributeCICDPipelineWorkerID = "cicd.pipeline.worker.id" // GitHub's Runner ID
AttributeCICDPipelineWorkerGroupID = "cicd.pipeline.worker.group.id" // GitHub's Runner Group ID
AttributeCICDPipelineWorkerName = "cicd.pipeline.worker.name" // GitHub's Runner Name
AttributeCICDPipelineWorkerGroupName = "cicd.pipeline.worker.group.name" // GitHub's Runner Group Name
AttributeCICDPipelineWorkerNodeID = "cicd.pipeline.worker.node.id" // GitHub's Runner Node ID
AttributeCICDPipelineWorkerLabels = "cicd.pipeline.worker.labels" // GitHub's Runner Labels

// The following attributes are exclusive to GitHub but not listed under
// Vendor Extensions within Semantic Conventions yet.
Expand Down Expand Up @@ -127,10 +133,10 @@ const (
AttributeVCSVendorName = "vcs.vendor.name" // GitHub
)

// getWorkflowAttrs returns a pcommon.Map of attributes for the Workflow Run
// getWorkflowRunAttrs returns a pcommon.Map of attributes for the Workflow Run
// GitHub event type and an error if one occurs. The attributes are associated
// with the originally provided resource.
func (gtr *githubTracesReceiver) getWorkflowAttrs(resource pcommon.Resource, e *github.WorkflowRunEvent) error {
func (gtr *githubTracesReceiver) getWorkflowRunAttrs(resource pcommon.Resource, e *github.WorkflowRunEvent) error {
attrs := resource.Attributes()
var err error

Expand Down Expand Up @@ -200,6 +206,67 @@ func (gtr *githubTracesReceiver) getWorkflowAttrs(resource pcommon.Resource, e *
return err
}

// getWorkflowJobAttrs returns a pcommon.Map of attributes for the Workflow Job
// GitHub event type and an error if one occurs. The attributes are associated
// with the originally provided resource.
func (gtr *githubTracesReceiver) getWorkflowJobAttrs(resource pcommon.Resource, e *github.WorkflowJobEvent) error {
attrs := resource.Attributes()
var err error

svc, err := gtr.getServiceName(e.GetRepo().CustomProperties["service_name"], e.GetRepo().GetName())
if err != nil {
err = errors.New("failed to get service.name")
}

attrs.PutStr(semconv.AttributeServiceName, svc)

// VCS Attributes
attrs.PutStr(AttributeVCSRepositoryName, e.GetRepo().GetName())
attrs.PutStr(AttributeVCSVendorName, "github")
attrs.PutStr(AttributeVCSRefHead, e.GetWorkflowJob().GetHeadBranch())
attrs.PutStr(AttributeVCSRefHeadType, AttributeVCSRefHeadTypeBranch)
attrs.PutStr(AttributeVCSRefHeadRevision, e.GetWorkflowJob().GetHeadSHA())

// CICD Worker (GitHub Runner) Attributes
attrs.PutInt(AttributeCICDPipelineWorkerID, e.GetWorkflowJob().GetRunnerID())
attrs.PutInt(AttributeCICDPipelineWorkerGroupID, e.GetWorkflowJob().GetRunnerGroupID())
attrs.PutStr(AttributeCICDPipelineWorkerName, e.GetWorkflowJob().GetRunnerName())
attrs.PutStr(AttributeCICDPipelineWorkerGroupName, e.GetWorkflowJob().GetRunnerGroupName())
attrs.PutStr(AttributeCICDPipelineWorkerNodeID, e.GetWorkflowJob().GetNodeID())

if len(e.GetWorkflowJob().Labels) > 0 {
labels := attrs.PutEmptySlice(AttributeCICDPipelineWorkerLabels)
labels.EnsureCapacity(len(e.GetWorkflowJob().Labels))
for _, label := range e.GetWorkflowJob().Labels {
l := strings.ToLower(label)
labels.AppendEmpty().SetStr(l)
}
}

// CICD Attributes
attrs.PutStr(semconv.AttributeCicdPipelineName, e.GetWorkflowJob().GetName())
attrs.PutStr(AttributeCICDPipelineTaskRunSenderLogin, e.GetSender().GetLogin())
attrs.PutStr(semconv.AttributeCicdPipelineTaskRunURLFull, e.GetWorkflowJob().GetHTMLURL())
attrs.PutInt(semconv.AttributeCicdPipelineTaskRunID, e.GetWorkflowJob().GetID())
switch status := strings.ToLower(e.GetWorkflowJob().GetConclusion()); status {
case "success":
attrs.PutStr(AttributeCICDPipelineTaskRunStatus, AttributeCICDPipelineTaskRunStatusSuccess)
case "failure":
attrs.PutStr(AttributeCICDPipelineTaskRunStatus, AttributeCICDPipelineTaskRunStatusFailure)
case "skipped":
attrs.PutStr(AttributeCICDPipelineTaskRunStatus, AttributeCICDPipelineTaskRunStatusSkip)
case "cancelled":
attrs.PutStr(AttributeCICDPipelineTaskRunStatus, AttributeCICDPipelineTaskRunStatusCancellation)
// Default sets to whatever is provided by the event. GitHub provides the
// following additional values: neutral, timed_out, action_required, stale,
// and null.
default:
attrs.PutStr(AttributeCICDPipelineRunStatus, status)
}

return err
}

// splitRefWorkflowPath splits the reference workflow path into just the file
// name normalized to lowercase without the file type.
func splitRefWorkflowPath(path string) (fileName string, err error) {
Expand Down
Loading
Loading