From 11680fc78fe40fd089a84d3d325e0a56d544f886 Mon Sep 17 00:00:00 2001 From: Jonathan Tamsut Date: Thu, 1 Feb 2024 11:27:06 -0800 Subject: [PATCH] Upload the diagnostic logs to the Results Service (#3114) * upload diagnostic logs to results * correct casing * correct typo * update contract * update constant and define private method * fix access * fix reference to logs url * update * use results func * fix method naming * rename to match rpc * change API contract * fix lint issue * refactor * remove unused method * create new log type --- src/Runner.Common/JobServerQueue.cs | 15 +++++++++++++ src/Runner.Common/ResultsServer.cs | 14 ++++++++++++ src/Runner.Worker/DiagnosticLogManager.cs | 2 ++ src/Runner.Worker/ExecutionContext.cs | 13 +++++++++++ src/Sdk/DTWebApi/WebApi/TaskAttachment.cs | 1 + src/Sdk/WebApi/WebApi/Contracts.cs | 20 +++++++++++++++++ src/Sdk/WebApi/WebApi/ResultsHttpClient.cs | 26 ++++++++++++++++++++++ 7 files changed, 91 insertions(+) diff --git a/src/Runner.Common/JobServerQueue.cs b/src/Runner.Common/JobServerQueue.cs index 04450e011..c1425b807 100644 --- a/src/Runner.Common/JobServerQueue.cs +++ b/src/Runner.Common/JobServerQueue.cs @@ -551,6 +551,10 @@ namespace GitHub.Runner.Common { await UploadSummaryFile(file); } + if (string.Equals(file.Type, CoreAttachmentType.ResultsDiagnosticLog, StringComparison.OrdinalIgnoreCase)) + { + await UploadResultsDiagnosticLogsFile(file); + } else if (String.Equals(file.Type, CoreAttachmentType.ResultsLog, StringComparison.OrdinalIgnoreCase)) { if (file.RecordId != _jobTimelineRecordId) @@ -922,6 +926,17 @@ namespace GitHub.Runner.Common await UploadResultsFile(file, summaryHandler); } + private async Task UploadResultsDiagnosticLogsFile(ResultsUploadFileInfo file) + { + Trace.Info($"Starting to upload diagnostic logs file to results service {file.Name}, {file.Path}"); + ResultsFileUploadHandler diagnosticLogsHandler = async (file) => + { + await _resultsServer.CreateResultsDiagnosticLogsAsync(file.PlanId, file.JobId, file.Path, CancellationToken.None); + }; + + await UploadResultsFile(file, diagnosticLogsHandler); + } + private async Task UploadResultsStepLogFile(ResultsUploadFileInfo file) { Trace.Info($"Starting upload of step log file to results service {file.Name}, {file.Path}"); diff --git a/src/Runner.Common/ResultsServer.cs b/src/Runner.Common/ResultsServer.cs index f3bf9910c..8a1b35948 100644 --- a/src/Runner.Common/ResultsServer.cs +++ b/src/Runner.Common/ResultsServer.cs @@ -35,6 +35,8 @@ namespace GitHub.Runner.Common Task UpdateResultsWorkflowStepsAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, IEnumerable records, CancellationToken cancellationToken); + + Task CreateResultsDiagnosticLogsAsync(string planId, string jobId, string file, CancellationToken cancellationToken); } public sealed class ResultServer : RunnerService, IResultsServer @@ -141,6 +143,18 @@ namespace GitHub.Runner.Common throw new InvalidOperationException("Results client is not initialized."); } + public Task CreateResultsDiagnosticLogsAsync(string planId, string jobId, string file, + CancellationToken cancellationToken) + { + if (_resultsClient != null) + { + return _resultsClient.UploadResultsDiagnosticLogsAsync(planId, jobId, file, + cancellationToken: cancellationToken); + } + + throw new InvalidOperationException("Results client is not initialized."); + } + public ValueTask DisposeAsync() { CloseWebSocket(WebSocketCloseStatus.NormalClosure, CancellationToken.None); diff --git a/src/Runner.Worker/DiagnosticLogManager.cs b/src/Runner.Worker/DiagnosticLogManager.cs index 7259bab26..261689b5f 100644 --- a/src/Runner.Worker/DiagnosticLogManager.cs +++ b/src/Runner.Worker/DiagnosticLogManager.cs @@ -108,6 +108,8 @@ namespace GitHub.Runner.Worker parentContext.QueueAttachFile(type: CoreAttachmentType.DiagnosticLog, name: diagnosticsZipFileName, filePath: diagnosticsZipFilePath); + parentContext.QueueDiagnosticLogFile(name: diagnosticsZipFileName, filePath: diagnosticsZipFilePath); + executionContext.Debug("Diagnostic file upload complete."); } diff --git a/src/Runner.Worker/ExecutionContext.cs b/src/Runner.Worker/ExecutionContext.cs index cbd935b97..77c145d1d 100644 --- a/src/Runner.Worker/ExecutionContext.cs +++ b/src/Runner.Worker/ExecutionContext.cs @@ -90,6 +90,7 @@ namespace GitHub.Runner.Worker long Write(string tag, string message); void QueueAttachFile(string type, string name, string filePath); void QueueSummaryFile(string name, string filePath, Guid stepRecordId); + void QueueDiagnosticLogFile(string name, string filePath); // timeline record update methods void Start(string currentOperation = null); @@ -982,6 +983,18 @@ namespace GitHub.Runner.Worker _jobServerQueue.QueueResultsUpload(stepRecordId, name, filePath, ChecksAttachmentType.StepSummary, deleteSource: false, finalize: true, firstBlock: true, totalLines: 0); } + public void QueueDiagnosticLogFile(string name, string filePath) + { + ArgUtil.NotNullOrEmpty(name, nameof(name)); + ArgUtil.NotNullOrEmpty(filePath, nameof(filePath)); + + if (!File.Exists(filePath)) + { + throw new FileNotFoundException($"Can't upload diagnostic log file: {filePath}. File does not exist."); + } + _jobServerQueue.QueueResultsUpload(_record.Id, name, filePath, CoreAttachmentType.ResultsDiagnosticLog, deleteSource: false, finalize: true, firstBlock: true, totalLines: 0); + } + // Add OnMatcherChanged public void Add(OnMatcherChanged handler) { diff --git a/src/Sdk/DTWebApi/WebApi/TaskAttachment.cs b/src/Sdk/DTWebApi/WebApi/TaskAttachment.cs index 572b1f642..e1aa07417 100644 --- a/src/Sdk/DTWebApi/WebApi/TaskAttachment.cs +++ b/src/Sdk/DTWebApi/WebApi/TaskAttachment.cs @@ -101,6 +101,7 @@ namespace GitHub.DistributedTask.WebApi public static readonly String FileAttachment = "DistributedTask.Core.FileAttachment"; public static readonly String DiagnosticLog = "DistributedTask.Core.DiagnosticLog"; public static readonly String ResultsLog = "Results.Core.Log"; + public static readonly String ResultsDiagnosticLog = "Results.Core.DiagnosticLog"; } [GenerateAllConstants] diff --git a/src/Sdk/WebApi/WebApi/Contracts.cs b/src/Sdk/WebApi/WebApi/Contracts.cs index 95279e8ec..0018062ea 100644 --- a/src/Sdk/WebApi/WebApi/Contracts.cs +++ b/src/Sdk/WebApi/WebApi/Contracts.cs @@ -89,6 +89,26 @@ namespace GitHub.Services.Results.Contracts public long SoftSizeLimit; } + [DataContract] + [JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))] + public class GetSignedDiagnosticLogsURLRequest + { + [DataMember] + public string WorkflowJobRunBackendId; + [DataMember] + public string WorkflowRunBackendId; + } + + [DataContract] + [JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))] + public class GetSignedDiagnosticLogsURLResponse + { + [DataMember] + public string DiagLogsURL; + [DataMember] + public string BlobStorageType; + } + [DataContract] [JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))] public class JobLogsMetadataCreate diff --git a/src/Sdk/WebApi/WebApi/ResultsHttpClient.cs b/src/Sdk/WebApi/WebApi/ResultsHttpClient.cs index 9a7eb990b..53338dd15 100644 --- a/src/Sdk/WebApi/WebApi/ResultsHttpClient.cs +++ b/src/Sdk/WebApi/WebApi/ResultsHttpClient.cs @@ -81,6 +81,19 @@ namespace GitHub.Services.Results.Client return await GetResultsSignedURLResponse(getStepLogsSignedBlobURLEndpoint, cancellationToken, request); } + private async Task GetDiagnosticLogsUploadUrlAsync(string planId, string jobId, CancellationToken cancellationToken) + { + var request = new GetSignedDiagnosticLogsURLRequest() + { + WorkflowJobRunBackendId = jobId, + WorkflowRunBackendId = planId, + }; + + var getDiagnosticLogsSignedBlobURLEndpoint = new Uri(m_resultsServiceUrl, Constants.GetJobDiagLogsSignedBlobURL); + + return await GetResultsSignedURLResponse(getDiagnosticLogsSignedBlobURLEndpoint, cancellationToken, request); + } + private async Task GetJobLogUploadUrlAsync(string planId, string jobId, CancellationToken cancellationToken) { var request = new GetSignedJobLogsURLRequest() @@ -421,6 +434,18 @@ namespace GitHub.Services.Results.Client } } + public async Task UploadResultsDiagnosticLogsAsync(string planId, string jobId, string file, CancellationToken cancellationToken) + { + // Get the upload url + var uploadUrlResponse = await GetDiagnosticLogsUploadUrlAsync(planId, jobId, cancellationToken); + if (uploadUrlResponse == null || uploadUrlResponse.DiagLogsURL == null) + { + throw new Exception("Failed to get diagnostic logs upload url"); + } + + await UploadLogFile(file, true, true, uploadUrlResponse.DiagLogsURL, uploadUrlResponse.BlobStorageType, cancellationToken); + } + private Step ConvertTimelineRecordToStep(TimelineRecord r) { return new Step() @@ -511,6 +536,7 @@ namespace GitHub.Services.Results.Client public static readonly string CreateStepLogsMetadata = ResultsReceiverTwirpEndpoint + "CreateStepLogsMetadata"; public static readonly string GetJobLogsSignedBlobURL = ResultsReceiverTwirpEndpoint + "GetJobLogsSignedBlobURL"; public static readonly string CreateJobLogsMetadata = ResultsReceiverTwirpEndpoint + "CreateJobLogsMetadata"; + public static readonly string GetJobDiagLogsSignedBlobURL = ResultsReceiverTwirpEndpoint + "GetJobDiagLogsSignedBlobURL"; public static readonly string ResultsProtoApiV1Endpoint = "twirp/github.actions.results.api.v1.WorkflowStepUpdateService/"; public static readonly string WorkflowStepsUpdate = ResultsProtoApiV1Endpoint + "WorkflowStepsUpdate";