diff --git a/internal/app/run/runner.go b/internal/app/run/runner.go index 90aaeacf..9476c892 100644 --- a/internal/app/run/runner.go +++ b/internal/app/run/runner.go @@ -7,6 +7,7 @@ import ( "bytes" "cmp" "context" + "encoding/base64" "encoding/json/v2" "errors" "fmt" @@ -424,6 +425,10 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report. if err != nil { return err } + log.WithFields(taskLogFields(task, jobID)). + WithField("actions_url", r.getDefaultActionsURL(task)). + WithField("address", r.client.Address()). + Info("task started") plan, err := model.CombineWorkflowPlanner(workflow).PlanJob(jobID) if err != nil { @@ -464,10 +469,6 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report. } telemetry.AddJobEnv(ctx, envs) - log.Infof("task %v repo is %v %v %v", task.Id, taskContext["repository"].GetStringValue(), - r.getDefaultActionsURL(task), - r.client.Address()) - preset := model.GithubContextFromMap(task.Context.AsMap()) if t := task.Secrets["GITEA_TOKEN"]; t != "" { preset.Token = t @@ -896,3 +897,22 @@ func (r *Runner) detectIsolatedCacheContainer() string { } return cacheContainer } + +func taskLogFields(task *runnerv1.Task, job string) log.Fields { + taskContext := task.GetContext().GetFields() + fields := log.Fields{ + "task_id": task.Id, + "job": job, + "repository": taskContext["repository"].GetStringValue(), + "run_id": taskContext["run_id"].GetStringValue(), + "run_number": taskContext["run_number"].GetStringValue(), + } + if parts := strings.Split(taskContext["gitea_runtime_token"].GetStringValue(), "."); len(parts) == 3 { + var claims struct{ JobID int64 } // Gitea's actionsClaims fields are untagged, so the claim key is "JobID" + payload, err := base64.RawURLEncoding.DecodeString(parts[1]) + if err == nil && json.Unmarshal(payload, &claims) == nil && claims.JobID > 0 { + fields["job_id"] = claims.JobID + } + } + return fields +} diff --git a/internal/app/run/runner_test.go b/internal/app/run/runner_test.go index a61c00cc..25c8220b 100644 --- a/internal/app/run/runner_test.go +++ b/internal/app/run/runner_test.go @@ -5,6 +5,7 @@ package run import ( "context" + "encoding/base64" "io" "net/http" "net/http/httptest" @@ -26,6 +27,7 @@ import ( "connectrpc.com/connect" "gitea.dev/actionslib/pkg/model" runnerv1 "gitea.dev/actionslib/runner/v1" + log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -403,3 +405,15 @@ func TestRestoreCalledWorkflowContext(t *testing.T) { assert.Equal(t, "workflow_call", task.Context.AsMap()["event_name"]) }) } + +func TestTaskLogFields(t *testing.T) { + fields := func(token string) log.Fields { + taskContext, err := structpb.NewStruct(map[string]any{"repository": "owner/repo", "run_id": "159", "run_number": "14", "gitea_runtime_token": token}) + require.NoError(t, err) + return taskLogFields(&runnerv1.Task{Id: 72, Context: taskContext}, "build") + } + want := log.Fields{"task_id": int64(72), "job": "build", "repository": "owner/repo", "run_id": "159", "run_number": "14"} + assert.Equal(t, want, fields("malformed")) + want["job_id"] = int64(221) + assert.Equal(t, want, fields("header."+base64.RawURLEncoding.EncodeToString([]byte(`{"TaskID":72,"JobID":221}`))+".signature")) +}