From 4b07e2659ead57f290ef7f84e8db615d073a0b23 Mon Sep 17 00:00:00 2001 From: stas Date: Thu, 1 Jun 2023 12:05:32 -0700 Subject: [PATCH 1/8] Port logging to ILogger --- src/ApiService/ApiService/ApiService.csproj | 9 +- .../ApiService/Functions/AgentCanSchedule.cs | 29 +- .../ApiService/Functions/AgentCommands.cs | 10 +- .../ApiService/Functions/AgentEvents.cs | 50 +- .../ApiService/Functions/AgentRegistration.cs | 11 +- src/ApiService/ApiService/Functions/Config.cs | 8 +- .../ApiService/Functions/Containers.cs | 10 +- src/ApiService/ApiService/Functions/Events.cs | 6 +- .../ApiService/Functions/InstanceConfig.cs | 12 +- src/ApiService/ApiService/Functions/Jobs.cs | 14 +- .../Functions/Migrations/JinjaToScriban.cs | 18 +- src/ApiService/ApiService/Functions/Node.cs | 17 +- .../ApiService/Functions/NodeAddSshKey.cs | 5 +- .../ApiService/Functions/Notifications.cs | 12 +- .../ApiService/Functions/NotificationsTest.cs | 8 +- src/ApiService/ApiService/Functions/Pool.cs | 5 +- src/ApiService/ApiService/Functions/Proxy.cs | 10 +- .../ApiService/Functions/QueueFileChanges.cs | 20 +- .../Functions/QueueNodeHeartbeat.cs | 13 +- .../ApiService/Functions/QueueProxyUpdate.cs | 13 +- .../Functions/QueueSignalREvents.cs | 8 +- .../Functions/QueueTaskHeartbeat.cs | 15 +- .../ApiService/Functions/QueueWebhooks.cs | 8 +- .../ApiService/Functions/ReproVmss.cs | 12 +- .../ApiService/Functions/Scaleset.cs | 12 +- .../ApiService/Functions/TimerDaily.cs | 16 +- .../ApiService/Functions/TimerProxy.cs | 21 +- .../ApiService/Functions/TimerRepro.cs | 10 +- .../ApiService/Functions/TimerRetention.cs | 33 +- .../ApiService/Functions/TimerTasks.cs | 15 +- .../ApiService/Functions/TimerWorkers.cs | 30 +- .../ApiService/Functions/ValidateScriban.cs | 6 +- .../ApiService/Functions/WebhookLogs.cs | 8 +- .../ApiService/Functions/WebhookPing.cs | 8 +- .../ApiService/Functions/Webhooks.cs | 25 +- src/ApiService/ApiService/Log.cs | 721 +++++++++--------- src/ApiService/ApiService/LogExt.cs | 24 + .../ApiService/OneFuzzTypes/Model.cs | 1 + src/ApiService/ApiService/Program.cs | 74 +- .../TestHooks/ContainerTestHooks.cs | 11 +- .../ApiService/TestHooks/CredsTestHooks.cs | 19 +- .../TestHooks/DiskOperationsTestHooks.cs | 11 +- .../ApiService/TestHooks/EventsTestHooks.cs | 13 +- .../TestHooks/ExtensionsTestHooks.cs | 11 +- .../TestHooks/InstanceConfigTestHooks.cs | 15 +- .../TestHooks/IpOperationsTestHooks.cs | 17 +- .../TestHooks/JobOperationsTestHooks.cs | 15 +- .../TestHooks/LogAnalyticsTestHooks.cs | 13 +- .../TestHooks/NodeOperationsTestHooks.cs | 39 +- .../NotificationOperationsTestHooks.cs | 17 +- .../TestHooks/NsgOperationsTestHooks.cs | 15 +- .../TestHooks/PoolOperationsTestHooks.cs | 11 +- .../TestHooks/ProxyForwardTestHooks.cs | 12 +- .../ApiService/TestHooks/TestHooks.cs | 17 +- .../ApiService/TestHooks/VmssTestHooks.cs | 15 +- src/ApiService/ApiService/host.json | 4 +- src/ApiService/ApiService/onefuzzlib/Auth.cs | 12 +- .../ApiService/onefuzzlib/AutoScale.cs | 42 +- .../ApiService/onefuzzlib/Config.cs | 18 +- .../ApiService/onefuzzlib/ConfigOperations.cs | 15 +- .../ApiService/onefuzzlib/Containers.cs | 10 +- .../ApiService/onefuzzlib/DiskOperations.cs | 14 +- .../onefuzzlib/EndpointAuthorization.cs | 9 +- .../ApiService/onefuzzlib/Events.cs | 11 +- .../ApiService/onefuzzlib/IpOperations.cs | 44 +- .../ApiService/onefuzzlib/JobOperations.cs | 21 +- .../ApiService/onefuzzlib/Metrics.cs | 12 +- .../onefuzzlib/NodeMessageOperations.cs | 11 +- .../ApiService/onefuzzlib/NodeOperations.cs | 69 +- .../onefuzzlib/NodeTasksOperations.cs | 9 +- .../onefuzzlib/NotificationOperations.cs | 18 +- .../ApiService/onefuzzlib/NsgOperations.cs | 34 +- .../ApiService/onefuzzlib/PoolOperations.cs | 27 +- .../onefuzzlib/ProxyForwardOperations.cs | 7 +- .../ApiService/onefuzzlib/ProxyOperations.cs | 51 +- src/ApiService/ApiService/onefuzzlib/Queue.cs | 26 +- .../ApiService/onefuzzlib/Reports.cs | 14 +- .../ApiService/onefuzzlib/ReproOperations.cs | 34 +- .../ApiService/onefuzzlib/Request.cs | 14 +- .../onefuzzlib/ScalesetOperations.cs | 193 ++--- .../ApiService/onefuzzlib/Scheduler.cs | 20 +- .../ApiService/onefuzzlib/ShrinkQueue.cs | 16 +- .../ApiService/onefuzzlib/Storage.cs | 8 +- .../ApiService/onefuzzlib/Subnet.cs | 12 +- .../onefuzzlib/TaskEventOperations.cs | 4 +- .../ApiService/onefuzzlib/TaskOperations.cs | 49 +- .../ApiService/onefuzzlib/VmOperations.cs | 41 +- .../ApiService/onefuzzlib/VmssOperations.cs | 62 +- .../onefuzzlib/WebhookOperations.cs | 59 +- .../onefuzzlib/notifications/Ado.cs | 54 +- .../onefuzzlib/notifications/GithubIssues.cs | 20 +- .../notifications/JinjaTemplateAdapter.cs | 19 +- .../notifications/NotificationsBase.cs | 11 +- .../onefuzzlib/notifications/Teams.cs | 10 +- .../ApiService/onefuzzlib/orm/Orm.cs | 10 +- src/ApiService/ApiService/packages.lock.json | 117 +-- .../IntegrationTests/AgentEventsTests.cs | 3 +- src/ApiService/IntegrationTests/AuthTests.cs | 8 +- .../IntegrationTests/ContainersTests.cs | 2 + .../IntegrationTests/Fakes/TestContainers.cs | 5 +- .../IntegrationTests/Fakes/TestContext.cs | 41 +- .../IntegrationTests/Fakes/TestEvents.cs | 4 +- .../IntegrationTests/Fakes/TestMetrics.cs | 4 +- .../Fakes/TestWebhookMessageLogOperations.cs | 4 +- .../Fakes/TestWebhookOperations.cs | 4 +- .../IntegrationTests/TestLogTracer.cs | 440 ++++++++++- .../IntegrationTests/_FunctionTestBase.cs | 21 +- .../IntegrationTests/packages.lock.json | 98 +-- src/ApiService/Tests/TimerReproTests.cs | 6 +- src/ApiService/Tests/packages.lock.json | 98 +-- 110 files changed, 2031 insertions(+), 1516 deletions(-) create mode 100644 src/ApiService/ApiService/LogExt.cs diff --git a/src/ApiService/ApiService/ApiService.csproj b/src/ApiService/ApiService/ApiService.csproj index 4b1f14d8ad..29dd01c8b4 100644 --- a/src/ApiService/ApiService/ApiService.csproj +++ b/src/ApiService/ApiService/ApiService.csproj @@ -8,7 +8,10 @@ - + + + + @@ -23,8 +26,8 @@ - - + + diff --git a/src/ApiService/ApiService/Functions/AgentCanSchedule.cs b/src/ApiService/ApiService/Functions/AgentCanSchedule.cs index b4d54c9477..7302ea00d9 100644 --- a/src/ApiService/ApiService/Functions/AgentCanSchedule.cs +++ b/src/ApiService/ApiService/Functions/AgentCanSchedule.cs @@ -1,14 +1,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class AgentCanSchedule { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public AgentCanSchedule(ILogTracer log, IOnefuzzContext context) { + public AgentCanSchedule(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } @@ -20,7 +20,7 @@ public async Async.Task Run( HttpRequestData req) { var request = await RequestHandling.ParseRequest(req); if (!request.IsOk) { - _log.Warning($"Cannot schedule due to {request.ErrorV}"); + _log.LogWarning("Cannot schedule due to {error}", request.ErrorV); return await _context.RequestHandling.NotOk(req, request.ErrorV, typeof(CanScheduleRequest).ToString()); } @@ -28,7 +28,7 @@ public async Async.Task Run( var node = await _context.NodeOperations.GetByMachineId(canScheduleRequest.MachineId); if (node == null) { - _log.Warning($"Unable to find {canScheduleRequest.MachineId:Tag:MachineId}"); + _log.LogWarning("Unable to find {MachineId}", canScheduleRequest.MachineId); return await _context.RequestHandling.NotOk( req, Error.Create(ErrorCode.UNABLE_TO_FIND, "unable to find node"), @@ -43,29 +43,32 @@ public async Async.Task Run( var task = await _context.TaskOperations.GetByTaskId(canScheduleRequest.TaskId); var workStopped = task == null || task.State.ShuttingDown(); if (!allowed) { - _log.Info($"Node cannot process new work {node.PoolName:Tag:PoolName} {node.ScalesetId:Tag:ScalesetId} - {node.MachineId:Tag:MachineId} "); + _log.LogInformation("Node cannot process new work {PoolName} {ScalesetId} - {MachineId} ", node.PoolName, node.ScalesetId, node.MachineId); return await RequestHandling.Ok(req, new CanSchedule(Allowed: allowed, WorkStopped: workStopped, Reason: reason)); } if (workStopped) { - _log.Info($"Work stopped for: {canScheduleRequest.MachineId:Tag:MachineId} and {canScheduleRequest.TaskId:Tag:TaskId}"); + _log.LogInformation("Work stopped for: {MachineId} and {TaskId}", canScheduleRequest.MachineId, canScheduleRequest.TaskId); return await RequestHandling.Ok(req, new CanSchedule(Allowed: false, WorkStopped: workStopped, Reason: "Work stopped")); } var scp = await _context.NodeOperations.AcquireScaleInProtection(node); if (!scp.IsOk) { - _log.Warning($"Failed to acquire scale in protection for: {node.MachineId:Tag:MachineId} in: {node.PoolName:Tag:PoolName} due to {scp.ErrorV:Tag:Error}"); + _log.LogWarning("Failed to acquire scale in protection for: {MachineId} in: {PoolName} due to {Error}", node.MachineId, node.PoolName, scp.ErrorV); } _ = scp.OkV; // node could be updated but we don't use it after this allowed = scp.IsOk; if (allowed) { - _log.Metric($"TaskAllowedToSchedule", 1, new Dictionary { - {"MachineId", node.MachineId.ToString()}, - {"TaskId", task is not null ? task.TaskId.ToString() : string.Empty} - }); + using (_log.BeginScope("TaskAllowedToSchedule")) { + _log.AddTags( + new Dictionary { + {"MachineId", node.MachineId.ToString()}, + {"TaskId", task is not null ? task.TaskId.ToString() : string.Empty} } + ); + _log.LogMetric("TaskAllowedToSchedule", 1); + } } - return await RequestHandling.Ok(req, new CanSchedule(Allowed: allowed, WorkStopped: workStopped, Reason: reason)); } } diff --git a/src/ApiService/ApiService/Functions/AgentCommands.cs b/src/ApiService/ApiService/Functions/AgentCommands.cs index 2ba68e9e64..4ce88765a7 100644 --- a/src/ApiService/ApiService/Functions/AgentCommands.cs +++ b/src/ApiService/ApiService/Functions/AgentCommands.cs @@ -1,14 +1,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class AgentCommands { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public AgentCommands(ILogTracer log, IOnefuzzContext context) { + public AgentCommands(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } @@ -53,9 +53,9 @@ private async Async.Task Delete(HttpRequestData req) { if (message != null) { await _context.NodeMessageOperations.Delete(message).IgnoreResult(); } else { - _log.WithTag("HttpRequest", "DELETE").Verbose($"failed to find {nodeCommand.MachineId:Tag:MachineId} for {nodeCommand.MessageId:Tag:MessageId}"); + _log.AddTag("HttpRequest", "DELETE"); + _log.LogDebug("failed to find {MachineId} for {MessageId}", nodeCommand.MachineId, nodeCommand.MessageId); } - return await RequestHandling.Ok(req, new BoolResult(true)); } } diff --git a/src/ApiService/ApiService/Functions/AgentEvents.cs b/src/ApiService/ApiService/Functions/AgentEvents.cs index 63559dd102..da2be5dff9 100644 --- a/src/ApiService/ApiService/Functions/AgentEvents.cs +++ b/src/ApiService/ApiService/Functions/AgentEvents.cs @@ -1,16 +1,16 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; namespace Microsoft.OneFuzz.Service.Functions; public class AgentEvents { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public AgentEvents(ILogTracer log, IOnefuzzContext context) { + public AgentEvents(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } @@ -26,7 +26,8 @@ public async Async.Task Run( } var envelope = request.OkV; - _log.WithTag("HttpRequest", "POST").Info($"node event: {envelope.MachineId:Tag:MachineId} {EntityConverter.ToJsonString(envelope):Tag:Event}"); + _log.AddTag("HttpRequest", "POST"); + _log.LogInformation("node event: {MachineId} {Event}", envelope.MachineId, EntityConverter.ToJsonString(envelope)); var error = envelope.Event switch { NodeStateUpdate updateEvent => await OnStateUpdate(envelope.MachineId, updateEvent), @@ -63,7 +64,7 @@ public async Async.Task Run( private async Async.Task OnStateUpdate(Guid machineId, NodeStateUpdate ev) { var node = await _context.NodeOperations.GetByMachineId(machineId); if (node is null) { - _log.Warning($"unable to process state update event. {machineId:Tag:MachineId} {ev:Tag:Event}"); + _log.LogWarning("unable to process state update event. {MachineId} {Event}", machineId, ev); return null; } @@ -72,14 +73,14 @@ public async Async.Task Run( if (!node.Managed) { return null; } - _log.Info($"stopping free node with reset flags: {machineId:Tag:MachineId}"); + _log.LogInformation("stopping free node with reset flags: {MachineId}", machineId); // discard result: node not used after this point _ = await _context.NodeOperations.Stop(node); return null; } if (await _context.NodeOperations.CouldShrinkScaleset(node)) { - _log.Info($"stopping free node to resize scaleset: {machineId:Tag:MachineId}"); + _log.LogInformation("stopping free node to resize scaleset: {MachineId}", machineId); // discard result: node not used after this point _ = await _context.NodeOperations.SetHalt(node); return null; @@ -88,7 +89,7 @@ public async Async.Task Run( if (ev.State == NodeState.Init) { if (node.DeleteRequested) { - _log.Info($"stopping node (init and delete_requested): {machineId:Tag:MachineId}"); + _log.LogInformation("stopping node (init and delete_requested): {MachineId}", machineId); // discard result: node not used after this point _ = await _context.NodeOperations.Stop(node); return null; @@ -106,7 +107,7 @@ public async Async.Task Run( node = await _context.NodeOperations.SetState(node, ev.State); if (ev.State == NodeState.Free) { - _log.Info($"node now available for work: {machineId:Tag:MachineId}"); + _log.LogInformation("node now available for work: {MachineId}", machineId); } else if (ev.State == NodeState.SettingUp) { if (ev.Data is NodeSettingUpEventData settingUpData) { if (!settingUpData.Tasks.Any()) { @@ -123,7 +124,7 @@ public async Async.Task Run( $"unable to find task: {taskId}"); } - _log.Info($"node starting task. {machineId:Tag:MachineId} {task.JobId:Tag:JobId} {task.TaskId:Tag:TaskId}"); + _log.LogInformation("node starting task. {MachineId} {JobId} {TaskId}", machineId, task.JobId, task.TaskId); // The task state may be `running` if it has `vm_count` > 1, and // another node is concurrently executing the task. If so, leave @@ -141,7 +142,8 @@ public async Async.Task Run( State: NodeTaskState.SettingUp); var r = await _context.NodeTasksOperations.Replace(nodeTask); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"Failed to replace node task {task.TaskId:Tag:TaskId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("Failed to replace node task {TaskId}", task.TaskId); } } } @@ -151,7 +153,7 @@ public async Async.Task Run( if (doneData.Error is not null) { var errorText = EntityConverter.ToJsonString(doneData); error = Error.Create(ErrorCode.TASK_FAILED, errorText); - _log.Error($"node 'done' {machineId:Tag:MachineId} - {errorText:Tag:Error}"); + _log.LogError("node 'done' {MachineId} - {Error}", machineId, errorText); } } @@ -203,15 +205,16 @@ public async Async.Task Run( State: NodeTaskState.Running); var r = await _context.NodeTasksOperations.Replace(nodeTask); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"failed to replace node task {nodeTask.TaskId:Tag:TaskId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("failed to replace node task {TaskId}", nodeTask.TaskId); } if (task.State.ShuttingDown()) { - _log.Info($"ignoring task start from node. {machineId:Tag:MachineId} {task.JobId:Tag:JobId} {task.TaskId:Tag:TaskId} ({task.State:Tag:State})"); + _log.LogInformation("ignoring task start from node. {MachineId} {JobId} {TaskId} ({State})", machineId, task.JobId, task.TaskId, task.State); return null; } - _log.Info($"task started on node. {machineId:Tag:MachineId} {task.JobId:Tag:JobId} {task.TaskId:Tag:TaskId}"); + _log.LogInformation("task started on node. {MachineId} {JobId} {TaskId}", machineId, task.JobId, task.TaskId); task = await _context.TaskOperations.SetState(task, TaskState.Running); var taskEvent = new TaskEvent( @@ -220,7 +223,8 @@ public async Async.Task Run( EventData: new WorkerEvent(Running: running)); r = await _context.TaskEventOperations.Replace(taskEvent); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"failed to replace taskEvent {taskEvent.TaskId:Tag:TaskId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("failed to replace taskEvent {TaskId}", taskEvent.TaskId); } return null; @@ -246,7 +250,7 @@ public async Async.Task Run( }; if (done.ExitStatus.Success) { - _log.Info($"task done. {task.JobId:Tag:JobId}:{task.TaskId:Tag:TaskId} {done.ExitStatus:Tag:Status}"); + _log.LogInformation("task done. {JobId}:{TaskId} {Status}", task.JobId, task.TaskId, done.ExitStatus); await _context.TaskOperations.MarkStopping(task, "task is done"); // keep node if keep-on-completion is set @@ -254,7 +258,8 @@ public async Async.Task Run( node = node with { DebugKeepNode = true }; var r = await _context.NodeOperations.Replace(node); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"keepNodeOnCompletion: failed to replace node {node.MachineId:Tag:MachineId} when setting debug keep node to true"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("keepNodeOnCompletion: failed to replace node {MachineId} when setting debug keep node to true", node.MachineId); } } } else { @@ -273,7 +278,8 @@ await _context.TaskOperations.MarkFailed( node = node with { DebugKeepNode = true }; var r = await _context.NodeOperations.Replace(node); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"keepNodeOnfFailure: failed to replace node {node.MachineId:Tag:MachineId} when setting debug keep node to true"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("keepNodeOnfFailure: failed to replace node {MachineId} when setting debug keep node to true", node.MachineId); } } } @@ -281,14 +287,16 @@ await _context.TaskOperations.MarkFailed( if (!node.DebugKeepNode) { var r = await _context.NodeTasksOperations.Delete(new NodeTasks(machineId, done.TaskId)); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"failed to deleting node task {done.TaskId:Tag:TaskId} for: {machineId:Tag:MachineId} since DebugKeepNode is false"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("failed to deleting node task {TaskId} for: {MachineId} since DebugKeepNode is false", done.TaskId, machineId); } } var taskEvent = new TaskEvent(done.TaskId, machineId, new WorkerEvent { Done = done }); var r1 = await _context.TaskEventOperations.Replace(taskEvent); if (!r1.IsOk) { - _log.WithHttpStatus(r1.ErrorV).Error($"failed to update task event for done task {done.TaskId:Tag:TaskId}"); + _log.AddHttpStatus(r1.ErrorV); + _log.LogError("failed to update task event for done task {TaskId}", done.TaskId); } return null; } diff --git a/src/ApiService/ApiService/Functions/AgentRegistration.cs b/src/ApiService/ApiService/Functions/AgentRegistration.cs index 31134c78cb..42485b22d1 100644 --- a/src/ApiService/ApiService/Functions/AgentRegistration.cs +++ b/src/ApiService/ApiService/Functions/AgentRegistration.cs @@ -2,14 +2,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class AgentRegistration { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public AgentRegistration(ILogTracer log, IOnefuzzContext context) { + public AgentRegistration(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } @@ -115,7 +115,7 @@ private async Async.Task Post(HttpRequestData req) { var instanceId = machineName is not null ? InstanceIds.InstanceIdFromMachineName(machineName) : null; - _log.Info($"registration request: {machineId:Tag:MachineId} {poolName:Tag:PoolName} {scalesetId:Tag:ScalesetId} {version:Tag:Version}"); + _log.LogInformation("registration request: {MachineId} {PoolName} {ScalesetId} {Version}", machineId, poolName, scalesetId, version); var poolResult = await _context.PoolOperations.GetByName(poolName); if (!poolResult.IsOk) { return await _context.RequestHandling.NotOk( @@ -154,7 +154,8 @@ private async Async.Task Post(HttpRequestData req) { var r = await _context.NodeOperations.Replace(node); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"failed to replace node operations for {node.MachineId:Tag:MachineId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("failed to replace node operations for {MachineId}", node.MachineId); } return await RequestHandling.Ok(req, await CreateRegistrationResponse(pool)); diff --git a/src/ApiService/ApiService/Functions/Config.cs b/src/ApiService/ApiService/Functions/Config.cs index 6f4037584b..a8d6f57383 100644 --- a/src/ApiService/ApiService/Functions/Config.cs +++ b/src/ApiService/ApiService/Functions/Config.cs @@ -1,14 +1,14 @@ using System.Net; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class Config { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public Config(ILogTracer log, IOnefuzzContext context) { + public Config(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } @@ -18,7 +18,7 @@ public async Async.Task Run( [HttpTrigger(AuthorizationLevel.Anonymous, "GET")] HttpRequestData req) { - _log.Info($"getting endpoint config parameters"); + _log.LogInformation($"getting endpoint config parameters"); var endpointParams = new ConfigResponse( Authority: _context.ServiceConfiguration.Authority, diff --git a/src/ApiService/ApiService/Functions/Containers.cs b/src/ApiService/ApiService/Functions/Containers.cs index 8eed38e23b..ab71388317 100644 --- a/src/ApiService/ApiService/Functions/Containers.cs +++ b/src/ApiService/ApiService/Functions/Containers.cs @@ -2,14 +2,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class ContainersFunction { - private readonly ILogTracer _logger; + private readonly ILogger _logger; private readonly IOnefuzzContext _context; - public ContainersFunction(ILogTracer logger, IOnefuzzContext context) { + public ContainersFunction(ILogger logger, IEndpointAuthorization auth, IOnefuzzContext context) { _logger = logger; _context = context; } @@ -74,7 +74,7 @@ private async Async.Task Delete(HttpRequestData req) { } var delete = request.OkV; - _logger.Info($"deleting {delete.Name:Tag:ContainerName}"); + _logger.LogInformation("deleting {ContainerName}", delete.Name); var container = await _context.Containers.FindContainer(delete.Name, StorageType.Corpus); var deleted = false; @@ -92,7 +92,7 @@ private async Async.Task Post(HttpRequestData req) { } var post = request.OkV; - _logger.Info($"creating {post.Name:Tag:ContainerName}"); + _logger.LogInformation("creating {ContainerName}", post.Name); var sas = await _context.Containers.CreateContainer( post.Name, StorageType.Corpus, diff --git a/src/ApiService/ApiService/Functions/Events.cs b/src/ApiService/ApiService/Functions/Events.cs index 67c25febec..6cf6ad5728 100644 --- a/src/ApiService/ApiService/Functions/Events.cs +++ b/src/ApiService/ApiService/Functions/Events.cs @@ -1,14 +1,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class EventsFunction { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public EventsFunction(ILogTracer log, IOnefuzzContext context) { + public EventsFunction(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _context = context; _log = log; } diff --git a/src/ApiService/ApiService/Functions/InstanceConfig.cs b/src/ApiService/ApiService/Functions/InstanceConfig.cs index 4718c8e3f5..5300817e1c 100644 --- a/src/ApiService/ApiService/Functions/InstanceConfig.cs +++ b/src/ApiService/ApiService/Functions/InstanceConfig.cs @@ -3,14 +3,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class InstanceConfig { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public InstanceConfig(ILogTracer log, IOnefuzzContext context) { + public InstanceConfig(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } @@ -22,7 +22,7 @@ public InstanceConfig(ILogTracer log, IOnefuzzContext context) { public async Task Get( [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route=Route)] HttpRequestData req) { - _log.Info($"getting instance_config"); + _log.LogInformation("getting instance_config"); var config = await _context.ConfigOperations.Fetch(); var response = req.CreateResponse(HttpStatusCode.OK); @@ -35,7 +35,7 @@ public async Task Get( public async Task Post( [HttpTrigger(AuthorizationLevel.Anonymous, "POST", Route=Route)] HttpRequestData req) { - _log.Info($"attempting instance_config update"); + _log.LogInformation("getting instance_config"); var request = await RequestHandling.ParseRequest(req); if (!request.IsOk) { @@ -59,7 +59,7 @@ public async Task Post( if (updateNsg) { await foreach (var nsg in _context.NsgOperations.ListNsgs()) { - _log.Info($"Checking if nsg: {nsg.Data.Location!:Tag:Location} ({nsg.Data.Name:Tag:NsgName}) owned by OneFuzz"); + _log.LogInformation("Checking if nsg: {Location} ({NsgName}) owned by OneFuzz", nsg.Data.Location!, nsg.Data.Name); if (nsg.Data.Location! == nsg.Data.Name) { var result = await _context.NsgOperations.SetAllowedSources(new Nsg(nsg.Data.Location!, nsg.Data.Location!), request.OkV.config.ProxyNsgConfig!); if (!result.IsOk) { diff --git a/src/ApiService/ApiService/Functions/Jobs.cs b/src/ApiService/ApiService/Functions/Jobs.cs index 9326f773f1..bd1905a199 100644 --- a/src/ApiService/ApiService/Functions/Jobs.cs +++ b/src/ApiService/ApiService/Functions/Jobs.cs @@ -2,14 +2,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class Jobs { private readonly IOnefuzzContext _context; - private readonly ILogTracer _logTracer; + private readonly ILogger _logTracer; - public Jobs(IOnefuzzContext context, ILogTracer logTracer) { + public Jobs(IEndpointAuthorization auth, IOnefuzzContext context, ILogger logTracer) { _context = context; _logTracer = logTracer; } @@ -68,7 +68,9 @@ private async Task Post(HttpRequestData req, FunctionContext c job = job with { Config = job.Config with { Logs = logContainerUri.ToString() } }; var r = await _context.JobOperations.Insert(job); if (!r.IsOk) { - _logTracer.WithTag("HttpRequest", "POST").WithHttpStatus(r.ErrorV).Error($"failed to insert job {job.JobId:Tag:JobId}"); + _logTracer.AddTag("HttpRequest", "POST"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to insert job {JobId}", job.JobId); return await _context.RequestHandling.NotOk( req, Error.Create( @@ -103,7 +105,9 @@ private async Task Delete(HttpRequestData req) { job = job with { State = JobState.Stopping }; var r = await _context.JobOperations.Replace(job); if (!r.IsOk) { - _logTracer.WithTag("HttpRequest", "DELETE").WithHttpStatus(r.ErrorV).Error($"Failed to replace job {job.JobId:Tag:JobId}"); + _logTracer.AddTag("HttpRequest", "DELETE"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("Failed to replace job {JobId}", job.JobId); } } diff --git a/src/ApiService/ApiService/Functions/Migrations/JinjaToScriban.cs b/src/ApiService/ApiService/Functions/Migrations/JinjaToScriban.cs index 0e69ab5103..ce201f66be 100644 --- a/src/ApiService/ApiService/Functions/Migrations/JinjaToScriban.cs +++ b/src/ApiService/ApiService/Functions/Migrations/JinjaToScriban.cs @@ -1,16 +1,16 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class JinjaToScriban { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public JinjaToScriban(ILogTracer log, IOnefuzzContext context) { + public JinjaToScriban(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } @@ -29,7 +29,7 @@ public async Async.Task Run( "JinjaToScriban"); } - _log.Info($"Finding notifications to migrate"); + _log.LogInformation("Finding notifications to migrate"); var notifications = _context.NotificationOperations.SearchAll() .SelectAwait(async notification => { @@ -46,13 +46,13 @@ public async Async.Task Run( .Select(notificationTuple => notificationTuple.Notification); if (request.OkV.DryRun) { - _log.Info($"Dry run scriban migration"); + _log.LogInformation("Finding notifications to migrate"); return await RequestHandling.Ok(req, new JinjaToScribanMigrationDryRunResponse( await notifications.Select(notification => notification.NotificationId).ToListAsync() )); } - _log.Info($"Attempting to migrate {await notifications.CountAsync()} items"); + _log.LogInformation("Attempting to migrate {count} items", await notifications.CountAsync()); var updatedNotificationsIds = new List(); var failedNotificationIds = new List(); @@ -62,14 +62,14 @@ await notifications.Select(notification => notification.NotificationId).ToListAs var r = await _context.NotificationOperations.Replace(notification); if (r.IsOk) { updatedNotificationsIds.Add(notification.NotificationId); - _log.Info($"Migrated notification: {notification.NotificationId} to jinja"); + _log.LogInformation("Migrated notification: {id} to scriban", notification.NotificationId); } else { failedNotificationIds.Add(notification.NotificationId); - _log.Error(Error.Create(ErrorCode.UNABLE_TO_UPDATE, r.ErrorV.Reason, r.ErrorV.Status.ToString())); + _log.LogOneFuzzError(Error.Create(ErrorCode.UNABLE_TO_UPDATE, r.ErrorV.Reason, r.ErrorV.Status.ToString())); } } catch (Exception ex) { failedNotificationIds.Add(notification.NotificationId); - _log.Exception(ex); + _log.LogError(ex, "Failed to migrate notification to scriban {notificationId}", notification.NotificationId); } } diff --git a/src/ApiService/ApiService/Functions/Node.cs b/src/ApiService/ApiService/Functions/Node.cs index b7f033ce22..c3c7d9c09e 100644 --- a/src/ApiService/ApiService/Functions/Node.cs +++ b/src/ApiService/ApiService/Functions/Node.cs @@ -2,14 +2,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class Node { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public Node(ILogTracer log, IOnefuzzContext context) { + public Node(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } @@ -107,7 +107,8 @@ private async Async.Task Patch(HttpRequestData req) { if (node.DebugKeepNode) { var r = await _context.NodeOperations.Replace(node with { DebugKeepNode = false }); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"Failed to replace node {node.MachineId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("Failed to replace node {MachineId}", node.MachineId); } } @@ -138,7 +139,9 @@ private async Async.Task Post(HttpRequestData req) { var r = await _context.NodeOperations.Replace(node); if (!r.IsOk) { - _log.WithTag("HttpRequest", "POST").WithHttpStatus(r.ErrorV).Error($"Failed to replace node {node.MachineId:Tag:MachineId}"); + _log.AddTag("HttpRequest", "POST"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("Failed to replace node {MachineId}", node.MachineId); } return await RequestHandling.Ok(req, true); } @@ -165,7 +168,9 @@ private async Async.Task Delete(HttpRequestData req) { if (node.DebugKeepNode) { var r = await _context.NodeOperations.Replace(node with { DebugKeepNode = false }); if (!r.IsOk) { - _log.WithTag("HttpRequest", "DELETE").WithHttpStatus(r.ErrorV).Error($"Failed to replace node {node.MachineId:Tag:MachineId}"); + _log.AddTag("HttpRequest", "DELETE"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("Failed to replace node {MachineId}", node.MachineId); } } diff --git a/src/ApiService/ApiService/Functions/NodeAddSshKey.cs b/src/ApiService/ApiService/Functions/NodeAddSshKey.cs index 524acaf8fd..8744ce1d45 100644 --- a/src/ApiService/ApiService/Functions/NodeAddSshKey.cs +++ b/src/ApiService/ApiService/Functions/NodeAddSshKey.cs @@ -2,13 +2,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class NodeAddSshKey { + private readonly ILogTracer _log; private readonly IOnefuzzContext _context; - public NodeAddSshKey(IOnefuzzContext context) { + public NodeAddSshKey(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _context = context; } diff --git a/src/ApiService/ApiService/Functions/Notifications.cs b/src/ApiService/ApiService/Functions/Notifications.cs index 323ef65c61..e94dcf5a4f 100644 --- a/src/ApiService/ApiService/Functions/Notifications.cs +++ b/src/ApiService/ApiService/Functions/Notifications.cs @@ -2,20 +2,21 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class Notifications { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public Notifications(ILogTracer log, IOnefuzzContext context) { + public Notifications(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } private async Async.Task Get(HttpRequestData req) { - _log.WithTag("HttpRequest", "GET").Info($"Notification search"); + _log.AddTag("HttpRequest", "GET"); + _log.LogInformation("Notification search"); var request = await RequestHandling.ParseRequest(req); if (!request.IsOk) { return await _context.RequestHandling.NotOk(req, request.ErrorV, "notification search"); @@ -31,7 +32,8 @@ private async Async.Task Get(HttpRequestData req) { private async Async.Task Post(HttpRequestData req) { - _log.WithTag("HttpRequest", "POST").Info($"adding notification hook"); + _log.AddTag("HttpRequest", "POST"); + _log.LogInformation("adding notification hook"); var request = await RequestHandling.ParseRequest(req); if (!request.IsOk) { return await _context.RequestHandling.NotOk(req, request.ErrorV, "notification create"); diff --git a/src/ApiService/ApiService/Functions/NotificationsTest.cs b/src/ApiService/ApiService/Functions/NotificationsTest.cs index 11beedcf70..8a72fff777 100644 --- a/src/ApiService/ApiService/Functions/NotificationsTest.cs +++ b/src/ApiService/ApiService/Functions/NotificationsTest.cs @@ -2,14 +2,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class NotificationsTest { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public NotificationsTest(ILogTracer log, IOnefuzzContext context) { + public NotificationsTest(ILogger log log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } @@ -17,7 +17,7 @@ public NotificationsTest(ILogTracer log, IOnefuzzContext context) { [Function("NotificationsTest")] [Authorize(Allow.User)] public async Async.Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "POST", Route = "notifications/test")] HttpRequestData req) { - _log.WithTag("HttpRequest", "GET").Info($"Notification test"); + _log.LogInformation("Notification test"); var request = await RequestHandling.ParseRequest(req); if (!request.IsOk) { return await _context.RequestHandling.NotOk(req, request.ErrorV, "notification search"); diff --git a/src/ApiService/ApiService/Functions/Pool.cs b/src/ApiService/ApiService/Functions/Pool.cs index c160e3b163..10da25db57 100644 --- a/src/ApiService/ApiService/Functions/Pool.cs +++ b/src/ApiService/ApiService/Functions/Pool.cs @@ -3,13 +3,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class Pool { + private readonly ILogTracer _log; private readonly IOnefuzzContext _context; - public Pool(IOnefuzzContext context) { + public Pool(ILogger log log, IEndpointAuthorization auth, IOnefuzzContext context) { _context = context; } diff --git a/src/ApiService/ApiService/Functions/Proxy.cs b/src/ApiService/ApiService/Functions/Proxy.cs index 85e8b4221e..243f23bdc9 100644 --- a/src/ApiService/ApiService/Functions/Proxy.cs +++ b/src/ApiService/ApiService/Functions/Proxy.cs @@ -2,15 +2,15 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; +using Microsoft.Extensions.Logging; using VmProxy = Microsoft.OneFuzz.Service.Proxy; - namespace Microsoft.OneFuzz.Service.Functions; public class Proxy { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public Proxy(ILogTracer log, IOnefuzzContext context) { + public Proxy(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } @@ -113,7 +113,9 @@ private async Async.Task Post(HttpRequestData req) { var updated = forwardResult.OkV with { ProxyId = proxy.ProxyId }; var r = await _context.ProxyForwardOperations.Replace(updated); if (!r.IsOk) { - _log.WithTag("HttpRequest", "POST").WithHttpStatus(r.ErrorV).Error($"failed to update proxy forward with {updated.MachineId:Tag:MachineId} with new {proxy.ProxyId:Tag:ProxyId}"); + _log.AddTag("HttpRequest", "POST"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("failed to update proxy forward with {MachineId} with new {ProxyId}", updated.MachineId, proxy.ProxyId); } await _context.ProxyOperations.SaveProxyConfig(proxy); } diff --git a/src/ApiService/ApiService/Functions/QueueFileChanges.cs b/src/ApiService/ApiService/Functions/QueueFileChanges.cs index 3598a449e5..bae0b3a622 100644 --- a/src/ApiService/ApiService/Functions/QueueFileChanges.cs +++ b/src/ApiService/ApiService/Functions/QueueFileChanges.cs @@ -2,8 +2,8 @@ using System.Text.Json.Nodes; using Azure.Core; using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service.Functions; public class QueueFileChanges { @@ -14,7 +14,7 @@ public class QueueFileChanges { private const string QueueFileChangesPoisonQueueName = "file-changes-poison"; private const string QueueFileChangesQueueName = "file-changes"; - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IStorage _storage; @@ -22,7 +22,7 @@ public class QueueFileChanges { private readonly IOnefuzzContext _context; - public QueueFileChanges(ILogTracer log, IStorage storage, INotificationOperations notificationOperations, IOnefuzzContext context) { + public QueueFileChanges(ILogger log, IStorage storage, INotificationOperations notificationOperations, IOnefuzzContext context) { _log = log; _storage = storage; _notificationOperations = notificationOperations; @@ -41,16 +41,16 @@ public async Async.Task Run( const string expectedEventType = "Microsoft.Storage.BlobCreated"; if (!fileChangeEvent.RootElement.TryGetProperty(eventType, out var eventTypeElement) || eventTypeElement.GetString() != expectedEventType) { - _log.WithTag("queueMessage", msg) - .Info($"Expected fileChangeEvent to contain a property named '{eventType}' with value equal to {expectedEventType}"); + _log.AddTag("queueMessage", msg); + _log.LogInformation("Expected fileChangeEvent to contain a property named '{eventType}' with value equal to {expectedEventType}", eventType, expectedEventType); return; } const string topic = "topic"; if (!fileChangeEvent.RootElement.TryGetProperty(topic, out var topicElement) || !_storage.CorpusAccounts().Contains(new ResourceIdentifier(topicElement.GetString()!))) { - _log.WithTag("queueMessage", msg) - .Info($"Expected fileChangeEvent to contain a property named '{topic}' with a value contained in corpus accounts"); + _log.AddTag("queueMessage", msg); + _log.LogInformation("Expected fileChangeEvent to contain a property named '{topic}' with a value contained in corpus accounts", topic); return; } @@ -63,7 +63,7 @@ public async Async.Task Run( await FileAdded(fileChangeEvent, isLastRetryAttempt: false); } catch (Exception e) { - _log.Exception(e); + _log.LogError(e, "File Added failed"); await RequeueMessage(msg); } } @@ -76,7 +76,7 @@ private async Async.Task FileAdded(JsonDocument fileChangeEvent, bool isLastRetr var container = parts[0]; var path = string.Join('/', parts.Skip(1)); - _log.Info($"file added : {container:Tag:Container} - {path:Tag:Path}"); + _log.LogInformation("file added : {Container} - {Path}", container, path); await _notificationOperations.NewFiles(Container.Parse(container), path, isLastRetryAttempt); } @@ -93,7 +93,7 @@ private async Async.Task RequeueMessage(string msg) { var queueName = QueueFileChangesQueueName; if (newCustomDequeueCount > MAX_DEQUEUE_COUNT) { - _log.Warning($"Message retried more than {MAX_DEQUEUE_COUNT} times with no success: {msg}"); + _log.LogWarning("Message retried more than {MAX_DEQUEUE_COUNT} times with no success: {msg}", MAX_DEQUEUE_COUNT, msg); queueName = QueueFileChangesPoisonQueueName; } diff --git a/src/ApiService/ApiService/Functions/QueueNodeHeartbeat.cs b/src/ApiService/ApiService/Functions/QueueNodeHeartbeat.cs index 544dcc8231..ba19175938 100644 --- a/src/ApiService/ApiService/Functions/QueueNodeHeartbeat.cs +++ b/src/ApiService/ApiService/Functions/QueueNodeHeartbeat.cs @@ -1,16 +1,16 @@ using System.Text.Json; using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service.Functions; public class QueueNodeHearbeat { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public QueueNodeHearbeat(ILogTracer log, IOnefuzzContext context) { + public QueueNodeHearbeat(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } @@ -22,19 +22,20 @@ public async Async.Task Run([QueueTrigger("node-heartbeat", Connection = "AzureW var events = _context.Events; var metrics = _context.Metrics; - _log.Info($"heartbeat: {msg}"); + _log.LogInformation("heartbeat: {msg}", msg); var hb = JsonSerializer.Deserialize(msg, EntityConverter.GetJsonSerializerOptions()).EnsureNotNull($"wrong data {msg}"); var node = await nodes.GetByMachineId(hb.NodeId); if (node == null) { - _log.Warning($"invalid {hb.NodeId:Tag:NodeId}"); + _log.LogWarning("invalid {NodeId}", hb.NodeId); return; } var newNode = node with { Heartbeat = DateTimeOffset.UtcNow }; var r = await nodes.Replace(newNode); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"Failed to replace heartbeat: {hb.NodeId:Tag:NodeId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("Failed to replace heartbeat: {NodeId}", hb.NodeId); } var nodeHeartbeatEvent = new EventNodeHeartbeat(node.MachineId, node.ScalesetId, node.PoolName, node.State); diff --git a/src/ApiService/ApiService/Functions/QueueProxyUpdate.cs b/src/ApiService/ApiService/Functions/QueueProxyUpdate.cs index b6e343bcc0..460c011fd1 100644 --- a/src/ApiService/ApiService/Functions/QueueProxyUpdate.cs +++ b/src/ApiService/ApiService/Functions/QueueProxyUpdate.cs @@ -1,22 +1,22 @@ using System.Text.Json; using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service.Functions; public class QueueProxyHearbeat { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IProxyOperations _proxy; - public QueueProxyHearbeat(ILogTracer log, IProxyOperations proxy) { + public QueueProxyHearbeat(ILogger log, IProxyOperations proxy) { _log = log; _proxy = proxy; } [Function("QueueProxyUpdate")] public async Async.Task Run([QueueTrigger("proxy", Connection = "AzureWebJobsStorage")] string msg) { - _log.Info($"heartbeat: {msg}"); + _log.LogInformation("heartbeat: {msg}", msg); var hb = JsonSerializer.Deserialize(msg, EntityConverter.GetJsonSerializerOptions()).EnsureNotNull($"wrong data {msg}"); ; var newHb = hb with { TimeStamp = DateTimeOffset.UtcNow }; @@ -24,14 +24,15 @@ public async Async.Task Run([QueueTrigger("proxy", Connection = "AzureWebJobsSto var proxy = await _proxy.GetByProxyId(newHb.ProxyId); if (proxy == null) { - _log.Warning($"invalid proxy id: {newHb.ProxyId:Tag:ProxyId}"); + _log.LogWarning("invalid proxy id: {ProxyId}", newHb.ProxyId); return; } var newProxy = proxy with { Heartbeat = newHb }; var r = await _proxy.Replace(newProxy); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"Failed to replace proxy heartbeat {newHb.ProxyId:Tag:ProxyId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("Failed to replace proxy heartbeat {ProxyId}", newHb.ProxyId); } } } diff --git a/src/ApiService/ApiService/Functions/QueueSignalREvents.cs b/src/ApiService/ApiService/Functions/QueueSignalREvents.cs index 53e81c786b..7e87c08c75 100644 --- a/src/ApiService/ApiService/Functions/QueueSignalREvents.cs +++ b/src/ApiService/ApiService/Functions/QueueSignalREvents.cs @@ -1,12 +1,12 @@ using Microsoft.Azure.Functions.Worker; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class QueueSignalREvents { - private readonly ILogTracerFactory _loggerFactory; + private readonly ILogger _logger; - public QueueSignalREvents(ILogTracerFactory loggerFactory) { - _loggerFactory = loggerFactory; + public QueueSignalREvents(ILogger logger) { + _logger = logger; } [Function("QueueSignalREvents")] diff --git a/src/ApiService/ApiService/Functions/QueueTaskHeartbeat.cs b/src/ApiService/ApiService/Functions/QueueTaskHeartbeat.cs index d9f8daa67a..6eba20c9cf 100644 --- a/src/ApiService/ApiService/Functions/QueueTaskHeartbeat.cs +++ b/src/ApiService/ApiService/Functions/QueueTaskHeartbeat.cs @@ -1,15 +1,15 @@ using System.Text.Json; using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service.Functions; public class QueueTaskHearbeat { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public QueueTaskHearbeat(ILogTracer logTracer, IOnefuzzContext context) { + public QueueTaskHearbeat(ILogger logTracer, IOnefuzzContext context) { _log = logTracer; _context = context; } @@ -22,24 +22,25 @@ public async Async.Task Run([QueueTrigger("task-heartbeat", Connection = "AzureW var _events = _context.Events; var _metrics = _context.Metrics; - _log.Info($"heartbeat: {msg}"); + _log.LogInformation("heartbeat: {msg}", msg); var hb = JsonSerializer.Deserialize(msg, EntityConverter.GetJsonSerializerOptions()).EnsureNotNull($"wrong data {msg}"); var task = await _tasks.GetByTaskId(hb.TaskId); if (task == null) { - _log.Warning($"invalid {hb.TaskId:Tag:TaskId}"); + _log.LogWarning("invalid {TaskId}", hb.TaskId); return; } var job = await _jobs.Get(task.JobId); if (job == null) { - _log.Warning($"invalid {task.JobId:Tag:JobId}"); + _log.LogWarning("invalid {JobId}", task.JobId); return; } var newTask = task with { Heartbeat = DateTimeOffset.UtcNow }; var r = await _tasks.Replace(newTask); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"failed to replace with new task {hb.TaskId:Tag:TaskId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("failed to replace with new task {TaskId}", hb.TaskId); } var taskHeartBeatEvent = new EventTaskHeartbeat(newTask.JobId, newTask.TaskId, job.Config.Project, job.Config.Name, newTask.State, newTask.Config); diff --git a/src/ApiService/ApiService/Functions/QueueWebhooks.cs b/src/ApiService/ApiService/Functions/QueueWebhooks.cs index 1d5e2a21e0..0c24eadeaf 100644 --- a/src/ApiService/ApiService/Functions/QueueWebhooks.cs +++ b/src/ApiService/ApiService/Functions/QueueWebhooks.cs @@ -1,13 +1,13 @@ using System.Text.Json; using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service.Functions; public class QueueWebhooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IWebhookMessageLogOperations _webhookMessageLog; - public QueueWebhooks(ILogTracer log, IWebhookMessageLogOperations webhookMessageLog) { + public QueueWebhooks(ILogger log, IWebhookMessageLogOperations webhookMessageLog) { _log = log; _webhookMessageLog = webhookMessageLog; } @@ -15,7 +15,7 @@ public QueueWebhooks(ILogTracer log, IWebhookMessageLogOperations webhookMessage [Function("QueueWebhooks")] public async Async.Task Run([QueueTrigger("webhooks", Connection = "AzureWebJobsStorage")] string msg) { - _log.Info($"Webhook Message Queued: {msg}"); + _log.LogInformation("Webhook Message Queued: {msg}", msg); var obj = JsonSerializer.Deserialize(msg, EntityConverter.GetJsonSerializerOptions()).EnsureNotNull($"wrong data {msg}"); diff --git a/src/ApiService/ApiService/Functions/ReproVmss.cs b/src/ApiService/ApiService/Functions/ReproVmss.cs index 6061c44098..26146d1bff 100644 --- a/src/ApiService/ApiService/Functions/ReproVmss.cs +++ b/src/ApiService/ApiService/Functions/ReproVmss.cs @@ -4,14 +4,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class ReproVmss { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public ReproVmss(ILogTracer log, IOnefuzzContext context) { + public ReproVmss(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } @@ -96,7 +96,8 @@ private async Async.Task Post(HttpRequestData req, FunctionCon { var data = userInfo.UserInfo.ToString(); // rely on record ToString var hash = Convert.ToBase64String(SHA256.HashData(Encoding.UTF8.GetBytes(data))); - _log.Event($"created repro VM, user distinguisher: {hash:Tag:UserHash}"); + _log.AddTag("UserHash", hash); + _log.LogEvent("created repro VM"); } var response = req.CreateResponse(HttpStatusCode.OK); @@ -133,7 +134,8 @@ private async Async.Task Delete(HttpRequestData req) { var updatedRepro = vm with { State = VmState.Stopping }; var r = await _context.ReproOperations.Replace(updatedRepro); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"Failed to replace repro {updatedRepro.VmId:Tag:VmId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("Failed to replace repro {VmId}", updatedRepro.VmId); } if (vm.Auth != null) { diff --git a/src/ApiService/ApiService/Functions/Scaleset.cs b/src/ApiService/ApiService/Functions/Scaleset.cs index c01383fa83..5f20641695 100644 --- a/src/ApiService/ApiService/Functions/Scaleset.cs +++ b/src/ApiService/ApiService/Functions/Scaleset.cs @@ -2,14 +2,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class Scaleset { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public Scaleset(ILogTracer log, IOnefuzzContext context) { + public Scaleset(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } @@ -135,7 +135,8 @@ private async Task Post(HttpRequestData req) { var inserted = await _context.ScalesetOperations.Insert(scaleset); if (!inserted.IsOk) { - _log.WithHttpStatus(inserted.ErrorV).Error($"failed to insert new scaleset {scaleset.ScalesetId:Tag:ScalesetId}"); + _log.AddHttpStatus(inserted.ErrorV); + _log.LogError("failed to insert new scaleset {ScalesetId}", scaleset.ScalesetId); return await _context.RequestHandling.NotOk( req, Error.Create( @@ -158,7 +159,8 @@ private async Task Post(HttpRequestData req) { var r = await _context.AutoScaleOperations.Insert(autoScale); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"failed to insert autoscale options for sclaeset id {autoScale.ScalesetId:Tag:ScalesetId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("failed to insert autoscale options for sclaeset id {ScalesetId}", autoScale.ScalesetId); } } diff --git a/src/ApiService/ApiService/Functions/TimerDaily.cs b/src/ApiService/ApiService/Functions/TimerDaily.cs index 9406057ee6..d8e49fb844 100644 --- a/src/ApiService/ApiService/Functions/TimerDaily.cs +++ b/src/ApiService/ApiService/Functions/TimerDaily.cs @@ -1,16 +1,16 @@ using Microsoft.Azure.Functions.Worker; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class TimerDaily { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IScalesetOperations _scalesets; private readonly IWebhookMessageLogOperations _webhookMessageLogs; - public TimerDaily(ILogTracer log, IScalesetOperations scalesets, IWebhookMessageLogOperations webhookMessageLogs) { + public TimerDaily(ILogger log, IScalesetOperations scalesets, IWebhookMessageLogOperations webhookMessageLogs) { _log = log; _scalesets = scalesets; _webhookMessageLogs = webhookMessageLogs; @@ -20,19 +20,21 @@ public TimerDaily(ILogTracer log, IScalesetOperations scalesets, IWebhookMessage public async Async.Task Run([TimerTrigger("1.00:00:00")] TimerInfo myTimer) { var scalesets = _scalesets.Search(); await foreach (var scaleset in scalesets) { - _log.Info($"updating scaleset configs {scaleset.ScalesetId:Tag:ScalesetId}"); + _log.LogInformation("updating scaleset configs {ScalesetId}", scaleset.ScalesetId); // todo: do it in batches var r = await _scalesets.Replace(scaleset with { NeedsConfigUpdate = true }); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"failed to replace scaleset {scaleset.ScalesetId:Tag:ScalesetId} with NeedsConfigUpdate set to true"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("failed to replace scaleset {ScalesetId} with NeedsConfigUpdate set to true", scaleset.ScalesetId); } } var expiredWebhookLogs = _webhookMessageLogs.SearchExpired(); await foreach (var logEntry in expiredWebhookLogs) { - _log.Info($"stopping expired webhook {logEntry.WebhookId:Tag:WebhookId} message log for {logEntry.EventId:Tag:EventId}"); + _log.LogInformation("stopping expired webhook {WebhookId} message log for {EventId}", logEntry.WebhookId, logEntry.EventId); var r = await _webhookMessageLogs.Delete(logEntry); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"failed to delete log entry for an expired webhook {logEntry.WebhookId:Tag:WebhookId} message for {logEntry.EventId:Tag:EventId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("failed to delete log entry for an expired webhook {WebhookId} message for {EventId}", logEntry.WebhookId, logEntry.EventId); } } } diff --git a/src/ApiService/ApiService/Functions/TimerProxy.cs b/src/ApiService/ApiService/Functions/TimerProxy.cs index 763e2a55c6..c0b7e237a5 100644 --- a/src/ApiService/ApiService/Functions/TimerProxy.cs +++ b/src/ApiService/ApiService/Functions/TimerProxy.cs @@ -1,12 +1,12 @@ using Microsoft.Azure.Functions.Worker; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class TimerProxy { - private readonly ILogTracer _logger; + private readonly ILogger _logger; private readonly IOnefuzzContext _context; - public TimerProxy(ILogTracer logTracer, IOnefuzzContext context) { + public TimerProxy(ILogger logTracer, IOnefuzzContext context) { _logger = logTracer; _context = context; } @@ -29,11 +29,11 @@ public async Async.Task Run([TimerTrigger("00:00:30")] TimerInfo myTimer) { // requesting to use the proxy while this function is checking if it's // out of date if (proxy.Outdated && !(await _context.ProxyOperations.IsUsed(proxy))) { - _logger.Warning($"scaleset-proxy: outdated and not used: {proxy.Region:Tag:Region}"); + _logger.LogWarning("scaleset-proxy: outdated and not used: {Region}", proxy.Region); proxy = await proxyOperations.SetState(proxy, VmState.Stopping); // If something is "wrong" with a proxy, delete & recreate it } else if (!proxyOperations.IsAlive(proxy)) { - _logger.Error($"scaleset-proxy: alive check failed, stopping: {proxy.Region:Tag:Region}"); + _logger.LogError("scaleset-proxy: alive check failed, stopping: {Region}", proxy.Region); proxy = await proxyOperations.SetState(proxy, VmState.Stopping); } else { await proxyOperations.SaveProxyConfig(proxy); @@ -41,14 +41,15 @@ public async Async.Task Run([TimerTrigger("00:00:30")] TimerInfo myTimer) { } if (VmStateHelper.NeedsWork.Contains(proxy.State)) { - _logger.Info($"scaleset-proxy: update state. proxy:{proxy.Region:Tag:Region} - {proxy.State:Tag:State}"); + _logger.LogInformation("scaleset-proxy: update state. proxy:{Region} - {State}", proxy.Region, proxy.State); proxy = await proxyOperations.ProcessStateUpdate(proxy); } if (proxy is not null && proxy.State != VmState.Stopped && proxyOperations.IsOutdated(proxy)) { var r = await proxyOperations.Replace(proxy with { Outdated = true }); if (!r.IsOk) { - _logger.WithHttpStatus(r.ErrorV).Error($"Failed to replace proxy record for proxy {proxy.ProxyId:Tag:ProxyId}"); + _logger.AddHttpStatus(r.ErrorV); + _logger.LogError("Failed to replace proxy record for proxy {ProxyId}", proxy.ProxyId); } } } @@ -60,7 +61,7 @@ public async Async.Task Run([TimerTrigger("00:00:30")] TimerInfo myTimer) { var allOutdated = proxies.Where(x => x.Region == region).All(p => p.Outdated); if (allOutdated) { var proxy = await proxyOperations.GetOrCreate(region); - _logger.Info($"Creating new proxy with id {proxy.ProxyId:Tag:ProxyId} in {region:Tag:Region}"); + _logger.LogInformation("Creating new proxy with id {ProxyId} in {Region}", proxy.ProxyId, region); } // this is required in order to support upgrade from non-nsg to @@ -78,7 +79,7 @@ public async Async.Task Run([TimerTrigger("00:00:30")] TimerInfo myTimer) { if (vnet != null) { var result = await nsgOperations.AssociateSubnet(nsgName, vnet, subnet); if (!result.OkV) { - _logger.Error($"Failed to associate NSG and subnet due to {result.ErrorV} in {region:Tag:Region}"); + _logger.LogError("Failed to associate NSG and subnet due to {Error} in {Region}", result.ErrorV, region); } } } @@ -90,7 +91,7 @@ public async Async.Task Run([TimerTrigger("00:00:30")] TimerInfo myTimer) { if (nsgOperations.OkToDelete(regions, nsg.Data.Location!, nsg.Data.Name)) { if (nsg.Data.NetworkInterfaces.Count == 0 && nsg.Data.Subnets.Count == 0) { if (!await nsgOperations.StartDeleteNsg(nsg.Data.Name)) { - _logger.Warning($"failed to start deleting NSG {nsg.Data.Name:Tag:NsgName}"); + _logger.LogWarning("failed to start deleting NSG {NsgName}", nsg.Data.Name); } } } diff --git a/src/ApiService/ApiService/Functions/TimerRepro.cs b/src/ApiService/ApiService/Functions/TimerRepro.cs index 5e2d27223f..a151135b68 100644 --- a/src/ApiService/ApiService/Functions/TimerRepro.cs +++ b/src/ApiService/ApiService/Functions/TimerRepro.cs @@ -1,13 +1,13 @@ using Microsoft.Azure.Functions.Worker; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class TimerRepro { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _onefuzzContext; - public TimerRepro(ILogTracer log, IOnefuzzContext onefuzzContext) { + public TimerRepro(ILogger log, IOnefuzzContext onefuzzContext) { _log = log; _onefuzzContext = onefuzzContext; } @@ -18,7 +18,7 @@ public async Async.Task Run([TimerTrigger("00:00:30")] TimerInfo myTimer) { { var expired = _onefuzzContext.ReproOperations.SearchExpired(); await foreach (var repro in expired) { - _log.Info($"stopping repro: {repro.VmId:Tag:VmId}"); + _log.LogInformation("stopping repro: {VmId}", repro.VmId); _ = expiredVmIds.Add(repro.VmId); // ignoring result: value not used later _ = await _onefuzzContext.ReproOperations.Stopping(repro); @@ -31,7 +31,7 @@ public async Async.Task Run([TimerTrigger("00:00:30")] TimerInfo myTimer) { continue; } - _log.Info($"update repro: {repro.VmId:Tag:VmId}"); + _log.LogInformation("update repro: {VmId}", repro.VmId); // ignoring result: value not used later _ = await _onefuzzContext.ReproOperations.ProcessStateUpdates(repro); } diff --git a/src/ApiService/ApiService/Functions/TimerRetention.cs b/src/ApiService/ApiService/Functions/TimerRetention.cs index 99a036c8aa..5c84e1819e 100644 --- a/src/ApiService/ApiService/Functions/TimerRetention.cs +++ b/src/ApiService/ApiService/Functions/TimerRetention.cs @@ -1,12 +1,13 @@ using ApiService.OneFuzzLib.Orm; using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class TimerRetention { private readonly TimeSpan RETENTION_POLICY = TimeSpan.FromDays(18 * 30); private readonly TimeSpan SEARCH_EXTENT = TimeSpan.FromDays(20 * 30); - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly ITaskOperations _taskOps; private readonly INotificationOperations _notificaitonOps; private readonly IJobOperations _jobOps; @@ -15,7 +16,7 @@ public class TimerRetention { private readonly IPoolOperations _poolOps; public TimerRetention( - ILogTracer log, + ILogger log, ITaskOperations taskOps, INotificationOperations notificaitonOps, IJobOperations jobOps, @@ -59,50 +60,54 @@ from container in task.Config.Containers } await foreach (var notification in _notificaitonOps.QueryAsync(timeFilter)) { - _log.Verbose($"checking expired notification for removal: {notification.NotificationId:Tag:NotificationId}"); + _log.LogDebug("checking expired notification for removal: {NotificationId}", notification.NotificationId); var container = notification.Container; if (!usedContainers.Contains(container)) { - _log.Info($"deleting expired notification: {notification.NotificationId:Tag:NotificationId}"); + _log.LogInformation("deleting expired notification: {NotificationId}", notification.NotificationId); var r = await _notificaitonOps.Delete(notification); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"failed to delete notification {notification.NotificationId:Tag:NotificationId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("failed to delete notification {NotificationId}", notification.NotificationId); } } } await foreach (var job in _jobOps.QueryAsync(Query.And(timeFilter, Query.EqualEnum("state", JobState.Enabled)))) { if (job.UserInfo is not null && job.UserInfo.Upn is not null) { - _log.Info($"removing PII from job {job.JobId:Tag:JobId}"); + _log.LogInformation("removing PII from job {JobId}", job.JobId); var userInfo = job.UserInfo with { Upn = null }; var updatedJob = job with { UserInfo = userInfo }; var r = await _jobOps.Replace(updatedJob); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"Failed to save job {updatedJob.JobId:Tag:JobId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("Failed to save job {JobId}", updatedJob.JobId); } } } await foreach (var task in _taskOps.QueryAsync(Query.And(timeFilter, Query.EqualEnum("state", TaskState.Stopped)))) { if (task.UserInfo is not null && task.UserInfo.Upn is not null) { - _log.Info($"removing PII from task {task.TaskId:Tag:TaskId}"); + _log.LogInformation("removing PII from task {TaskId}", task.TaskId); var userInfo = task.UserInfo with { Upn = null }; var updatedTask = task with { UserInfo = userInfo }; var r = await _taskOps.Replace(updatedTask); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"Failed to save task {updatedTask.TaskId:Tag:TaskId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("Failed to save task {TaskId}", updatedTask.TaskId); } } } await foreach (var repro in _reproOps.QueryAsync(timeFilter)) { if (repro.UserInfo is not null && repro.UserInfo.Upn is not null) { - _log.Info($"removing PII from repro: {repro.VmId:Tag:VmId}"); + _log.LogInformation("removing PII from repro: {VmId}", repro.VmId); var userInfo = repro.UserInfo with { Upn = null }; var updatedRepro = repro with { UserInfo = userInfo }; var r = await _reproOps.Replace(updatedRepro); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"Failed to save repro {updatedRepro.VmId:Tag:VmId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("Failed to save repro {VmId}", updatedRepro.VmId); } } } @@ -117,7 +122,7 @@ from container in task.Config.Containers var pool = await _poolOps.GetById(queueId); if (!pool.IsOk) { //pool does not exist. Ok to delete the pool queue - _log.Info($"Deleting {q.Name:Tag:PoolQueueName} since pool could not be found in Pool table"); + _log.LogInformation("Deleting {PoolQueueName} since pool could not be found in Pool table", q.Name); await _queue.DeleteQueue(q.Name, StorageType.Corpus); } } @@ -126,13 +131,13 @@ from container in task.Config.Containers var taskQueue = await _taskOps.GetByTaskId(queueId); if (taskQueue is null) { // task does not exist. Ok to delete the task queue - _log.Info($"Deleting {q.Name:Tag:TaskQueueName} since task could not be found in Task table "); + _log.LogInformation("Deleting {TaskQueueName} since task could not be found in Task table", q.Name); await _queue.DeleteQueue(q.Name, StorageType.Corpus); } } else if (q.Name.StartsWith(ShrinkQueue.ShrinkQueueNamePrefix)) { //ignore Shrink Queues, since they seem to behave ok } else { - _log.Warning($"Unhandled {q.Name:Tag:QueueName} when doing garbage collection on queues"); + _log.LogWarning("Unhandled {QueueName} when doing garbage collection on queues", q.Name); } } } diff --git a/src/ApiService/ApiService/Functions/TimerTasks.cs b/src/ApiService/ApiService/Functions/TimerTasks.cs index 5283cb95a0..a2f08af277 100644 --- a/src/ApiService/ApiService/Functions/TimerTasks.cs +++ b/src/ApiService/ApiService/Functions/TimerTasks.cs @@ -1,10 +1,9 @@ using Microsoft.Azure.Functions.Worker; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; - public class TimerTasks { - private readonly ILogTracer _logger; + private readonly ILogger _logger; private readonly ITaskOperations _taskOperations; @@ -14,7 +13,7 @@ public class TimerTasks { private readonly IScheduler _scheduler; - public TimerTasks(ILogTracer logger, ITaskOperations taskOperations, IJobOperations jobOperations, IScheduler scheduler) { + public TimerTasks(ILogger logger, ITaskOperations taskOperations, IJobOperations jobOperations, IScheduler scheduler) { _logger = logger; _taskOperations = taskOperations; _jobOperations = jobOperations; @@ -25,7 +24,7 @@ public TimerTasks(ILogTracer logger, ITaskOperations taskOperations, IJobOperati public async Async.Task Run([TimerTrigger("00:00:15")] TimerInfo myTimer) { var expriredTasks = _taskOperations.SearchExpired(); await foreach (var task in expriredTasks) { - _logger.Info($"stopping expired task. job_id:{task.JobId:Tag:JobId} task_id:{task.TaskId:Tag:TaskId}"); + _logger.LogInformation("stopping expired task. job_id:{JobId} task_id:{TaskId}", task.JobId, task.TaskId); await _taskOperations.MarkStopping(task, "task is expired"); } @@ -33,20 +32,20 @@ public async Async.Task Run([TimerTrigger("00:00:15")] TimerInfo myTimer) { var expiredJobs = _jobOperations.SearchExpired(); await foreach (var job in expiredJobs) { - _logger.Info($"stopping expired job. job_id:{job.JobId:Tag:JobId}"); + _logger.LogInformation("stopping expired job. job_id:{JobId}", job.JobId); _ = await _jobOperations.Stopping(job); } var jobs = _jobOperations.SearchState(states: JobStateHelper.NeedsWork); await foreach (var job in jobs) { - _logger.Info($"update job: {job.JobId:Tag:JobId}"); + _logger.LogInformation("update job: {JobId}", job.JobId); _ = await _jobOperations.ProcessStateUpdates(job); } var tasks = _taskOperations.SearchStates(states: TaskStateHelper.NeedsWorkStates); await foreach (var task in tasks) { - _logger.Info($"update task: {task.TaskId:Tag:TaskId}"); + _logger.LogInformation("update task: {TaskId}", task.TaskId); _ = await _taskOperations.ProcessStateUpdate(task); } diff --git a/src/ApiService/ApiService/Functions/TimerWorkers.cs b/src/ApiService/ApiService/Functions/TimerWorkers.cs index 95280ee19a..136dbc33da 100644 --- a/src/ApiService/ApiService/Functions/TimerWorkers.cs +++ b/src/ApiService/ApiService/Functions/TimerWorkers.cs @@ -1,14 +1,14 @@ using Microsoft.Azure.Functions.Worker; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class TimerWorkers { - ILogTracer _log; + ILogger _log; IScalesetOperations _scaleSetOps; IPoolOperations _poolOps; INodeOperations _nodeOps; - public TimerWorkers(ILogTracer log, IOnefuzzContext context) { + public TimerWorkers(ILogger log, IOnefuzzContext context) { _log = log; _scaleSetOps = context.ScalesetOperations; _poolOps = context.PoolOperations; @@ -16,18 +16,18 @@ public TimerWorkers(ILogTracer log, IOnefuzzContext context) { } private async Async.Task ProcessScalesets(Service.Scaleset scaleset) { - _log.Verbose($"checking scaleset for updates: {scaleset.ScalesetId:Tag:ScalesetId}"); + _log.LogDebug("checking scaleset for updates: {ScalesetId}", scaleset.ScalesetId); scaleset = await _scaleSetOps.UpdateConfigs(scaleset); var r = await _scaleSetOps.SyncAutoscaleSettings(scaleset); if (!r.IsOk) { - _log.Error($"failed to sync auto scale settings {scaleset.ScalesetId:Tag:ScalesetId} due to {r.ErrorV:Tag:Error}"); + _log.LogError("failed to sync auto scale settings {ScalesetId} due to {Error}", scaleset.ScalesetId, r.ErrorV); } // if the scaleset is touched during cleanup, don't continue to process it var (touched, ss) = await _scaleSetOps.CleanupNodes(scaleset); if (touched) { - _log.Verbose($"scaleset needed cleanup: {scaleset.ScalesetId:Tag:ScalesetId}"); + _log.LogDebug("scaleset needed cleanup: {ScalesetId}", scaleset.ScalesetId); return ss; } @@ -46,11 +46,11 @@ public async Async.Task Run([TimerTrigger("00:01:30")] TimerInfo t) { var pools = _poolOps.SearchStates(states: PoolStateHelper.NeedsWork); await foreach (var pool in pools) { try { - _log.Info($"updating pool: {pool.PoolId:Tag:PoolId} ({pool.Name:Tag:PoolName}) - state: {pool.State:Tag:PoolState}"); + _log.LogInformation("updating pool: {PoolId} ({PoolName}) - state: {PoolState}", pool.PoolId, pool.Name, pool.State); var newPool = await _poolOps.ProcessStateUpdate(pool); - _log.Info($"completed updating pool: {pool.PoolId:Tag:PoolId} ({pool.Name:Tag:PoolName}) - now in state {newPool.State:Tag:PoolState}"); + _log.LogInformation("completed updating pool: {PoolId} ({PoolName}) - now in state {PoolState}", pool.PoolId, pool.Name, newPool.State); } catch (Exception ex) { - _log.Exception(ex, $"failed to process pool"); + _log.LogError(ex, "failed to process pool"); } } @@ -66,22 +66,22 @@ public async Async.Task Run([TimerTrigger("00:01:30")] TimerInfo t) { var nodes = _nodeOps.SearchStates(states: NodeStateHelper.NeedsWorkStates); await foreach (var node in nodes) { try { - _log.Info($"updating node: {node.MachineId:Tag:MachineId} - state: {node.State:Tag:NodeState}"); + _log.LogInformation("updating node: {MachineId} - state: {NodeState}", node.MachineId, node.State); var newNode = await _nodeOps.ProcessStateUpdate(node); - _log.Info($"completed updating node: {node.MachineId:Tag:MachineId} - now in state {newNode.State:Tag:NodeState}"); + _log.LogInformation("completed updating node: {MachineId} - now in state {NodeState}", node.MachineId, newNode.State); } catch (Exception ex) { - _log.Exception(ex, $"failed to process node"); + _log.LogError(ex, "failed to process node"); } } var scalesets = _scaleSetOps.SearchAll(); await foreach (var scaleset in scalesets) { try { - _log.Info($"updating scaleset: {scaleset.ScalesetId:Tag:ScalesetId} - state: {scaleset.State:Tag:ScalesetState}"); + _log.LogInformation("updating scaleset: {ScalesetId} - state: {ScalesetState}", scaleset.ScalesetId, scaleset.State); var newScaleset = await ProcessScalesets(scaleset); - _log.Info($"completed updating scaleset: {scaleset.ScalesetId:Tag:ScalesetId} - now in state {newScaleset.State:Tag:ScalesetState}"); + _log.LogInformation("completed updating scaleset: {ScalesetId} - now in state {ScalesetState}", scaleset.ScalesetId, newScaleset.State); } catch (Exception ex) { - _log.Exception(ex, $"failed to process scaleset"); + _log.LogError(ex, "failed to process scaleset"); } } } diff --git a/src/ApiService/ApiService/Functions/ValidateScriban.cs b/src/ApiService/ApiService/Functions/ValidateScriban.cs index 90bd90b723..c6e64bef8b 100644 --- a/src/ApiService/ApiService/Functions/ValidateScriban.cs +++ b/src/ApiService/ApiService/Functions/ValidateScriban.cs @@ -1,13 +1,13 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class ValidateScriban { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public ValidateScriban(ILogTracer log, IOnefuzzContext context) { + public ValidateScriban(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } diff --git a/src/ApiService/ApiService/Functions/WebhookLogs.cs b/src/ApiService/ApiService/Functions/WebhookLogs.cs index 1899fa1623..9206dff3af 100644 --- a/src/ApiService/ApiService/Functions/WebhookLogs.cs +++ b/src/ApiService/ApiService/Functions/WebhookLogs.cs @@ -1,15 +1,15 @@ using System.Net; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; public class WebhookLogs { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public WebhookLogs(ILogTracer log, IOnefuzzContext context) { + public WebhookLogs(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } @@ -33,7 +33,7 @@ public async Async.Task Run( return await _context.RequestHandling.NotOk(req, Error.Create(ErrorCode.INVALID_REQUEST, "unable to find webhook"), "webhook log"); } - _log.Info($"getting webhook logs: {request.OkV.WebhookId:Tag:WebhookId}"); + _log.LogInformation("getting webhook logs: {WebhookId}", request.OkV.WebhookId); var logs = _context.WebhookMessageLogOperations.SearchByPartitionKeys(new[] { $"{request.OkV.WebhookId}" }); var response = req.CreateResponse(HttpStatusCode.OK); diff --git a/src/ApiService/ApiService/Functions/WebhookPing.cs b/src/ApiService/ApiService/Functions/WebhookPing.cs index e3e4574d85..6828c599e1 100644 --- a/src/ApiService/ApiService/Functions/WebhookPing.cs +++ b/src/ApiService/ApiService/Functions/WebhookPing.cs @@ -1,15 +1,15 @@ using System.Net; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; public class WebhookPing { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public WebhookPing(ILogTracer log, IOnefuzzContext context) { + public WebhookPing(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } @@ -33,7 +33,7 @@ public async Async.Task Run( return await _context.RequestHandling.NotOk(req, Error.Create(ErrorCode.INVALID_REQUEST, "unable to find webhook"), "webhook ping"); } - _log.Info($"pinging webhook : {request.OkV.WebhookId:Tag:WebhookId}"); + _log.LogInformation("pinging webhook : {WebhookId}", request.OkV.WebhookId); EventPing ping = await _context.WebhookOperations.Ping(webhook); var response = req.CreateResponse(HttpStatusCode.OK); diff --git a/src/ApiService/ApiService/Functions/Webhooks.cs b/src/ApiService/ApiService/Functions/Webhooks.cs index 538e49217b..76fee6ce70 100644 --- a/src/ApiService/ApiService/Functions/Webhooks.cs +++ b/src/ApiService/ApiService/Functions/Webhooks.cs @@ -1,15 +1,15 @@ using System.Net; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; public class Webhooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; - public Webhooks(ILogTracer log, IOnefuzzContext context) { + public Webhooks(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } @@ -34,7 +34,7 @@ private async Async.Task Get(HttpRequestData req) { } if (request.OkV.WebhookId != null) { - _log.Info($"getting webhook: {request.OkV.WebhookId:Tag:WebhookId}"); + _log.LogInformation("getting webhook: {WebhookId}", request.OkV.WebhookId); var webhook = await _context.WebhookOperations.GetByWebhookId(request.OkV.WebhookId.Value); if (webhook == null) { @@ -46,7 +46,7 @@ private async Async.Task Get(HttpRequestData req) { return response; } - _log.Info($"listing webhooks"); + _log.LogInformation("listing webhooks"); var webhooks = _context.WebhookOperations.SearchAll().Select(w => w with { Url = null, SecretToken = null }); var response2 = req.CreateResponse(HttpStatusCode.OK); @@ -66,7 +66,7 @@ private async Async.Task Patch(HttpRequestData req) { "webhook update"); } - _log.Info($"updating webhook: {request.OkV.WebhookId:Tag:WebhookId}"); + _log.LogInformation("updating webhook: {WebhookId}", request.OkV.WebhookId); var webhook = await _context.WebhookOperations.GetByWebhookId(request.OkV.WebhookId); @@ -84,7 +84,8 @@ private async Async.Task Patch(HttpRequestData req) { var r = await _context.WebhookOperations.Replace(updated); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"failed to replace webhook with updated entry {updated.WebhookId:Tag:WebhookId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("failed to replace webhook with updated entry {WebhookId}", updated.WebhookId); } var response = req.CreateResponse(HttpStatusCode.OK); @@ -107,10 +108,11 @@ private async Async.Task Post(HttpRequestData req) { var r = await _context.WebhookOperations.Insert(webhook); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"failed to insert webhook {webhook.WebhookId:Tag:WebhookId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("failed to insert webhook {WebhookId}", webhook.WebhookId); } - _log.Info($"added webhook: {webhook.WebhookId:Tag:WebhookId}"); + _log.LogInformation("added webhook: {WebhookId}", webhook.WebhookId); var response = req.CreateResponse(HttpStatusCode.OK); await response.WriteAsJsonAsync(webhook with { Url = null, SecretToken = null }); @@ -127,7 +129,7 @@ private async Async.Task Delete(HttpRequestData req) { context: "webhook delete"); } - _log.Info($"deleting webhook: {request.OkV.WebhookId:Tag:WebhookId}"); + _log.LogInformation("deleting webhook: {WebhookId}", request.OkV.WebhookId); var webhook = await _context.WebhookOperations.GetByWebhookId(request.OkV.WebhookId); @@ -137,7 +139,8 @@ private async Async.Task Delete(HttpRequestData req) { var r = await _context.WebhookOperations.Delete(webhook); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"failed to delete webhook {webhook.Name:Tag:WebhookName} - {webhook.WebhookId:Tag:WebhookId}"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("failed to delete webhook {WebhookName} - {WebhookId}", webhook.Name, webhook.WebhookId); } var response = req.CreateResponse(HttpStatusCode.OK); diff --git a/src/ApiService/ApiService/Log.cs b/src/ApiService/ApiService/Log.cs index 6a6b5ed1b9..a3d5c8db64 100644 --- a/src/ApiService/ApiService/Log.cs +++ b/src/ApiService/ApiService/Log.cs @@ -1,418 +1,435 @@ -using System.Diagnostics; -using System.Net; -using System.Runtime.CompilerServices; -using System.Text; +using System.Collections.Concurrent; +using System.Diagnostics; +using System.Globalization; using Microsoft.ApplicationInsights; using Microsoft.ApplicationInsights.DataContracts; +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; -//See: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/interpolated-string-handler -//by ref struct works, but Moq does not support by-ref struct value so all the tests break... https://github.com/moq/moq4/issues/829 -[InterpolatedStringHandler] -public struct LogStringHandler { - - private readonly StringBuilder _builder; - private Dictionary? _tags; - - public LogStringHandler(int literalLength, int formattedCount) { - _builder = new StringBuilder(literalLength); - _tags = null; - } - - public void AppendLiteral(string message) { - _builder.Append(message); - } - - public void AppendFormatted(T message) { - if (message is not null) { - _builder.Append(message.ToString()); - } else { - _builder.Append(""); - } - } - - public void AppendFormatted(T message, string? format) { - if (format is not null && format.StartsWith("Tag:")) { - var tag = format["Tag:".Length..]; - if (_tags is null) { - _tags = new Dictionary(); - } - _tags[tag] = $"{message}"; - _builder.Append('{').Append(tag).Append('}'); - } else if (message is IFormattable msg) { - _builder.Append(msg?.ToString(format, null)); - } else { - _builder.Append(message?.ToString()).Append(':').Append(format); - } - } - - private bool HasData => _builder is not null && _builder.Length > 0; - - public override string ToString() => this.HasData ? _builder.ToString() : ""; - public IReadOnlyDictionary? Tags => _tags; +/// +/// +/// +public enum Telemetry { + /// + /// + /// + Trace, + /// + /// + /// + Exception, + /// + /// + /// + Request, + /// + /// + /// + Dependency, + /// + /// + /// + PageView, + /// + /// + /// + Availability, + /// + /// + /// + Metric, + /// + /// + /// + Event } +/// +/// +/// +/// +/// +public record TelemetryConfig(TelemetryClient TelemetryClient, ISet? EnabledTelemetry = null); -public interface ILog { - void Log(Guid correlationId, LogStringHandler message, SeverityLevel level, IReadOnlyDictionary tags, string? caller); - void LogEvent(Guid correlationId, LogStringHandler evt, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller); - void LogMetric(Guid correlationId, LogStringHandler metric, int value, IReadOnlyDictionary? customDimensions, IReadOnlyDictionary tags, string? caller); - - void LogException(Guid correlationId, Exception ex, LogStringHandler message, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller); - void Flush(); -} -sealed class AppInsights : ILog { - private readonly TelemetryClient _telemetryClient; +/// +/// +/// +public class OneFuzzLogger : ILogger { - public AppInsights(TelemetryClient client) { - _telemetryClient = client; - } + /// + /// + /// + public const string CorrelationId = "CorrelationId"; - private static void Copy(IDictionary target, IReadOnlyDictionary? source) { - if (source is not null) { - foreach (var kvp in source) { - target[kvp.Key] = kvp.Value; - } - } - } + private readonly string categoryName; - public void Log(Guid correlationId, LogStringHandler message, SeverityLevel level, IReadOnlyDictionary tags, string? caller) { - var telemetry = new TraceTelemetry(message.ToString(), level); + private readonly IEnumerable telemetryConfig; - // copy properties - Copy(telemetry.Properties, tags); - telemetry.Properties["CorrelationId"] = correlationId.ToString(); - if (caller is not null) telemetry.Properties["CalledBy"] = caller; - Copy(telemetry.Properties, message.Tags); - _telemetryClient.TrackTrace(telemetry); + /// + /// + /// + /// + /// + public OneFuzzLogger(string categoryName, IEnumerable telemetryConfig) { + this.categoryName = categoryName; + this.telemetryConfig = telemetryConfig; } - public void LogEvent(Guid correlationId, LogStringHandler evt, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller) { - var telemetry = new EventTelemetry(evt.ToString()); + private const string TagsActivityName = "OneFuzzLoggerActivity"; - // copy properties - Copy(telemetry.Properties, tags); - telemetry.Properties["CorrelationId"] = correlationId.ToString(); - if (caller is not null) telemetry.Properties["CalledBy"] = caller; - Copy(telemetry.Properties, evt.Tags); - - // copy metrics - Copy(telemetry.Metrics, metrics); - - _telemetryClient.TrackEvent(telemetry); - } - - public void LogMetric(Guid correlationId, LogStringHandler metric, int value, IReadOnlyDictionary? customDimensions, IReadOnlyDictionary tags, string? caller) { - var telemetry = new MetricTelemetry(metric.ToString(), value, value, value, value, value); - // copy properties - Copy(telemetry.Properties, customDimensions); - telemetry.Properties["CorrelationId"] = correlationId.ToString(); - if (caller is not null) telemetry.Properties["CalledBy"] = caller; - Copy(telemetry.Properties, metric.Tags); - - _telemetryClient.TrackMetric(telemetry); - } - - public void LogException(Guid correlationId, Exception ex, LogStringHandler message, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller) { - { - var telemetry = new ExceptionTelemetry(ex); - - // copy properties - Copy(telemetry.Properties, tags); - telemetry.Properties["CorrelationId"] = correlationId.ToString(); - if (caller is not null) telemetry.Properties["CalledBy"] = caller; - Copy(telemetry.Properties, message.Tags); - - // copy metrics - Copy(telemetry.Metrics, metrics); - - _telemetryClient.TrackException(telemetry); + /// + /// + /// + public static Activity Activity { + get { + var cur = Activity.Current; + if (cur is not null && string.Equals(cur.OperationName, TagsActivityName)) { + return cur; + } else { + cur = new Activity(TagsActivityName); + } + return cur; } - - Log(correlationId, $"[{message}] {ex.Message}", SeverityLevel.Error, tags, caller); } - public void Flush() { - _telemetryClient.Flush(); - } -} - -//TODO: Should we write errors and Exception to std err ? -sealed class Console : ILog { - - private static string DictToString(IReadOnlyDictionary? d) { - if (d is null) { - return string.Empty; - } else { - return string.Join("", d); + /// + /// / + /// + /// + /// + /// + IDisposable? ILogger.BeginScope(TState state) { + var activity = new Activity(TagsActivityName); + _ = activity.Start(); + return activity; + } + + /// + /// + /// + /// + /// + bool ILogger.IsEnabled(LogLevel logLevel) { + return logLevel != LogLevel.None && this.telemetryConfig.Any(c => c.TelemetryClient.IsEnabled()); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + void ILogger.Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) { + if (formatter == null) { + throw new ArgumentNullException(nameof(formatter)); } - } - - private static void LogTags(Guid correlationId, IReadOnlyDictionary tags) { - var ts = DictToString(tags); - if (!string.IsNullOrEmpty(ts)) { - System.Console.WriteLine($"[{correlationId}] Tags:{ts}"); + foreach (var config in this.telemetryConfig) { + if (state is RequestTelemetry request && (config.EnabledTelemetry is null || config.EnabledTelemetry.Contains(Telemetry.Request))) { + PopulateTags(request); + config.TelemetryClient.TrackRequest(request); + } else if (state is PageViewTelemetry pageView && (config.EnabledTelemetry is null || config.EnabledTelemetry.Contains(Telemetry.PageView))) { + PopulateTags(pageView); + config.TelemetryClient.TrackPageView(pageView); + } else if (state is AvailabilityTelemetry availability && (config.EnabledTelemetry is null || config.EnabledTelemetry.Contains(Telemetry.Availability))) { + PopulateTags(availability); + config.TelemetryClient.TrackAvailability(availability); + } else if (state is DependencyTelemetry dependency && (config.EnabledTelemetry is null || config.EnabledTelemetry.Contains(Telemetry.Dependency))) { + PopulateTags(dependency); + config.TelemetryClient.TrackDependency(dependency); + } else if (state is MetricTelemetry metric && (config.EnabledTelemetry is null || config.EnabledTelemetry.Contains(Telemetry.Metric))) { + PopulateTags(metric); + config.TelemetryClient.TrackMetric(metric); + } else if (state is EventTelemetry evt && (config.EnabledTelemetry is null || config.EnabledTelemetry.Contains(Telemetry.Event))) { + PopulateTags(evt); + config.TelemetryClient.TrackEvent(evt); + } else { + if ((this as ILogger).IsEnabled(logLevel)) { + if (exception is null) { + if (config.EnabledTelemetry is null || config.EnabledTelemetry.Contains(Telemetry.Trace)) { + TraceTelemetry traceTelemetry = new TraceTelemetry( + formatter(state, exception), + OneFuzzLogger.GetSeverityLevel(logLevel)); + + traceTelemetry.Context.Operation.Id = Activity.RootId; + traceTelemetry.Context.Operation.ParentId = Activity.SpanId.ToString(); + this.PopulateTelemetry(traceTelemetry, state, eventId); + config.TelemetryClient.TrackTrace(traceTelemetry); + } + } else { + if (config.EnabledTelemetry is null || config.EnabledTelemetry.Contains(Telemetry.Exception)) { + ExceptionTelemetry exceptionTelemetry = new ExceptionTelemetry(exception) { + Message = exception.Message, + SeverityLevel = OneFuzzLogger.GetSeverityLevel(logLevel), + }; + exceptionTelemetry.Context.Operation.Id = Activity.RootId; + exceptionTelemetry.Context.Operation.ParentId = Activity.SpanId.ToString(); + + exceptionTelemetry.Properties.Add("FormattedMessage", formatter(state, exception)); + this.PopulateTelemetry(exceptionTelemetry, state, eventId); + config.TelemetryClient.TrackException(exceptionTelemetry); + } + } + } + } } } - private static void LogMetrics(Guid correlationId, IReadOnlyDictionary? metrics) { - var ms = DictToString(metrics); - if (!string.IsNullOrEmpty(ms)) { - System.Console.Out.WriteLine($"[{correlationId}] Metrics:{DictToString(metrics)}"); - } - } - public void Log(Guid correlationId, LogStringHandler message, SeverityLevel level, IReadOnlyDictionary tags, string? caller) { - System.Console.Out.WriteLine($"[{correlationId}][{level}] {message.ToString()}"); - LogTags(correlationId, tags); - if (message.Tags is not null) { - LogTags(correlationId, message.Tags); + /// + /// Converts the into corresponding Application insights . + /// + /// Logging log level. + /// Application insights corresponding SeverityLevel for the LogLevel. + private static SeverityLevel GetSeverityLevel(LogLevel logLevel) { + switch (logLevel) { + case LogLevel.Critical: + return SeverityLevel.Critical; + case LogLevel.Error: + return SeverityLevel.Error; + case LogLevel.Warning: + return SeverityLevel.Warning; + case LogLevel.Information: + return SeverityLevel.Information; + case LogLevel.Debug: + case LogLevel.Trace: + default: + return SeverityLevel.Verbose; } } - public void LogMetric(Guid correlationId, LogStringHandler metric, int value, IReadOnlyDictionary? customDimensions, IReadOnlyDictionary tags, string? caller) { - System.Console.Out.WriteLine($"[{correlationId}][Metric] {metric}"); - LogTags(correlationId, tags); - } - - public void LogEvent(Guid correlationId, LogStringHandler evt, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller) { - System.Console.Out.WriteLine($"[{correlationId}][Event] {evt}"); - LogTags(correlationId, tags); - LogMetrics(correlationId, metrics); - } - - public void LogException(Guid correlationId, Exception ex, LogStringHandler message, IReadOnlyDictionary tags, IReadOnlyDictionary? metrics, string? caller) { - System.Console.Out.WriteLine($"[{correlationId}][Exception] {message}:{ex}"); - LogTags(correlationId, tags); - LogMetrics(correlationId, metrics); - } - public void Flush() { - System.Console.Out.Flush(); - } -} - -public interface ILogTracer { - IReadOnlyDictionary Tags { get; } - - void Critical(LogStringHandler message); - void Error(LogStringHandler message); - - void Error(Error error); - void Event(LogStringHandler evt, IReadOnlyDictionary? metrics = null); - void Metric(LogStringHandler metric, int value, IReadOnlyDictionary? customDimensions); - void Exception(Exception ex, LogStringHandler message = $"", IReadOnlyDictionary? metrics = null); - void ForceFlush(); - void Info(LogStringHandler message); - void Warning(LogStringHandler message); - void Warning(Error error); - void Verbose(LogStringHandler message); - - ILogTracer WithTag(string k, string v); - ILogTracer WithTags(IEnumerable<(string, string)>? tags); - ILogTracer WithHttpStatus((HttpStatusCode Status, string Reason) result); -} - -internal interface ILogTracerInternal : ILogTracer { - void ReplaceCorrelationId(Guid newCorrelationId); - void AddTags(IEnumerable<(string, string)> tags); -} - + /// + /// Populates the state, scope and event information for the logging event. + /// + /// State information for the current event. + /// Telemetry item. + /// Event state information. + /// Event Id information. + private void PopulateTelemetry(ISupportProperties telemetryItem, TState state, EventId eventId) { + IDictionary dict = telemetryItem.Properties; + dict["CategoryName"] = this.categoryName; + dict["Logger"] = nameof(OneFuzzLogger); -public class LogTracer : ILogTracerInternal { - private static string? GetCaller() { - return new StackTrace()?.GetFrame(2)?.GetMethod()?.DeclaringType?.FullName; - } - - private Guid _correlationId; - private IEnumerable _loggers; - private Dictionary _tags; - private SeverityLevel _logSeverityLevel; - - public Guid CorrelationId => _correlationId; - public IReadOnlyDictionary Tags => _tags; - - private static IEnumerable> ConvertTags(IEnumerable<(string, string)>? tags) { - List> converted = new List>(); - if (tags is null) { - return converted; - } else { - foreach (var (k, v) in tags) { - converted.Add(new KeyValuePair(k, v)); - } - return converted; + if (eventId.Id != 0) { + dict["EventId"] = eventId.Id.ToString(CultureInfo.InvariantCulture); } - } - - public LogTracer(Guid correlationId, IEnumerable<(string, string)>? tags, List loggers, SeverityLevel logSeverityLevel) : - this(correlationId, new Dictionary(ConvertTags(tags)), loggers, logSeverityLevel) { } - - - public LogTracer(Guid correlationId, IReadOnlyDictionary tags, IEnumerable loggers, SeverityLevel logSeverityLevel) { - _correlationId = correlationId; - _tags = new(tags); - _loggers = loggers; - _logSeverityLevel = logSeverityLevel; - } - - //Single threaded only - public void ReplaceCorrelationId(Guid newCorrelationId) { - _correlationId = newCorrelationId; - } - //single threaded only - public void AddTags(IEnumerable<(string, string)> tags) { - if (tags is not null) { - foreach (var (k, v) in tags) { - _tags[k] = v; - } + if (!string.IsNullOrEmpty(eventId.Name)) { + dict["EventName"] = eventId.Name; } - } - - public ILogTracer WithTag(string k, string v) { - return WithTags(new[] { (k, v) }); - } - - public ILogTracer WithHttpStatus((HttpStatusCode Status, string Reason) result) { - (string, string)[] tags = { - ("StatusCode", ((int)result.Status).ToString()), - ("ReasonPhrase", result.Reason), - }; - - return WithTags(tags); - } - - public ILogTracer WithTags(IEnumerable<(string, string)>? tags) { - var newTags = new Dictionary(Tags); - if (tags is not null) { - foreach (var (k, v) in tags) { - newTags[k] = v; + if (state is IReadOnlyCollection> stateDictionary) { + foreach (KeyValuePair item in stateDictionary) { + if (string.Equals(item.Key, "{OriginalFormat}")) { + dict["OriginalFormat"] = Convert.ToString(item.Value, CultureInfo.InvariantCulture) ?? $"Failed to convert {item.Value}"; + } else { + dict[item.Key] = Convert.ToString(item.Value, CultureInfo.InvariantCulture) ?? $"Failed to convert {item.Value}"; + } } } - return new LogTracer(CorrelationId, newTags, _loggers, _logSeverityLevel); + PopulateTags(telemetryItem); } - public void Verbose(LogStringHandler message) { - if (_logSeverityLevel <= SeverityLevel.Verbose) { - var caller = GetCaller(); - foreach (var logger in _loggers) { - logger.Log(CorrelationId, message, SeverityLevel.Verbose, Tags, caller); - } - } - } + /// + /// + /// + /// + private static void PopulateTags(ISupportProperties telemetryItem) { + IDictionary dict = telemetryItem.Properties; - public void Info(LogStringHandler message) { - if (_logSeverityLevel <= SeverityLevel.Information) { - var caller = GetCaller(); - foreach (var logger in _loggers) { - logger.Log(CorrelationId, message, SeverityLevel.Information, Tags, caller); + var ourActivities = new LinkedList(); + { + var activity = Activity; + while (activity is not null && string.Equals(activity.OperationName, TagsActivityName)) { + _ = ourActivities.AddFirst(activity); + activity = activity.Parent; } } - } - public void Warning(LogStringHandler message) { - if (_logSeverityLevel <= SeverityLevel.Warning) { - var caller = GetCaller(); - foreach (var logger in _loggers) { - logger.Log(CorrelationId, message, SeverityLevel.Warning, Tags, caller); + foreach (var activity in ourActivities) { + foreach (var kv in activity.Tags) { + dict[kv.Key] = Convert.ToString(kv.Value, CultureInfo.InvariantCulture) ?? $"Failed to convert {kv.Value}"; } } } +} - public void Error(LogStringHandler message) { - if (_logSeverityLevel <= SeverityLevel.Error) { - var caller = GetCaller(); - foreach (var logger in _loggers) { - logger.Log(CorrelationId, message, SeverityLevel.Error, Tags, caller); - } - } - } - public void Critical(LogStringHandler message) { - if (_logSeverityLevel <= SeverityLevel.Critical) { - var caller = GetCaller(); - foreach (var logger in _loggers) { - logger.Log(CorrelationId, message, SeverityLevel.Critical, Tags, caller); +/// +/// +/// +public static class OneFuzzLoggerExt { + private static EventId EmptyEventId = new EventId(0); + + /// + /// + /// + /// + public static string? GetCorrelationId(this ILogger _) { + foreach (var tag in OneFuzzLogger.Activity.Tags) { + if (string.Equals(tag.Key, OneFuzzLogger.CorrelationId)) { + return tag.Value; } } + return null; } - public void Event(LogStringHandler evt, IReadOnlyDictionary? metrics) { - var caller = GetCaller(); - foreach (var logger in _loggers) { - logger.LogEvent(CorrelationId, evt, Tags, metrics, caller); - } - } - public void Metric(LogStringHandler metric, int value, IReadOnlyDictionary? customDimensions) { - var caller = GetCaller(); - foreach (var logger in _loggers) { - logger.LogMetric(CorrelationId, metric, value, customDimensions, Tags, caller); - } + /// + /// + /// + /// + /// + /// + public static void AddTag(this ILogger logger, string key, string value) { + _ = OneFuzzLogger.Activity.AddTag(key, value); } - public void Exception(Exception ex, LogStringHandler message, IReadOnlyDictionary? metrics) { - var caller = GetCaller(); - foreach (var logger in _loggers) { - logger.LogException(CorrelationId, ex, message, Tags, metrics, caller); + /// + /// + /// + /// /// + /// + public static void AddTags(this ILogger logger, IDictionary tags) { + var activity = OneFuzzLogger.Activity; + foreach (var kv in tags) { + _ = activity.AddTag(kv.Key, kv.Value); } } - public void ForceFlush() { - foreach (var logger in _loggers) { - logger.Flush(); + /// + /// + /// + /// + /// + public static void AddTags(this ILogger logger, IEnumerable<(string, string)> tags) { + var activity = OneFuzzLogger.Activity; + foreach (var tag in tags) { + _ = activity.AddTag(tag.Item1, tag.Item2); } } - public void Error(Error error) { - Error($"{error:Tag:Error}"); - } - - public void Warning(Error error) { - Warning($"{error:Tag:Error}"); + /// + /// + /// + /// + /// + /// + public static void LogEvent(this ILogger logger, string name, IDictionary? metrics = null) { + var evt = new EventTelemetry(name); + if (metrics != null) { + foreach (var m in metrics) { + evt.Metrics[m.Key] = m.Value; + } + } + logger.Log(LogLevel.Information, EmptyEventId, evt, null, (state, exception) => state.ToString() ?? $"Failed to convert event {name}"); + } + + + /// + /// + /// + /// + /// + /// + public static void LogMetric(this ILogger logger, string name, double value) { + var metric = new MetricTelemetry(name, value); + logger.Log(LogLevel.Information, EmptyEventId, metric, null, (state, exception) => state.ToString() ?? $"Failed to convert metric {name}"); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void LogDependency(this ILogger logger, string dependencyTypeName, string target, string dependencyName, string data, DateTimeOffset startTime, TimeSpan duration, string resultCode, bool success) { + var dependency = new DependencyTelemetry(dependencyTypeName, target, dependencyName, data, startTime, duration, resultCode, success); + logger.Log(LogLevel.Information, EmptyEventId, dependency, null, (state, exception) => state.ToString() ?? $"Failed to convert dependency {dependencyName}"); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void LogAvailabilityTelemetry(this ILogger logger, string name, DateTimeOffset timeStamp, TimeSpan duration, string runLocation, bool success, string? message = null) { + var availability = new AvailabilityTelemetry(name, timeStamp, duration, runLocation, success, message); + logger.Log(LogLevel.Information, EmptyEventId, availability, null, (state, exception) => state.ToString() ?? $"Failed to convert availability {availability}"); + } + + /// + /// + /// + /// + /// + public static void LogPageView(this ILogger logger, string pageName) { + var pageView = new PageViewTelemetry(pageName); + logger.Log(LogLevel.Information, EmptyEventId, pageView, null, (state, exception) => state.ToString() ?? $"Failed to convert pageView {pageView}"); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void LogRequest(this ILogger logger, string name, DateTimeOffset startTime, TimeSpan duration, string responseCode, bool success) { + var request = new RequestTelemetry(name, startTime, duration, responseCode, success); + logger.Log(LogLevel.Information, EmptyEventId, request, null, (state, exception) => state.ToString() ?? $"Failed to convert request {request}"); } } -public interface ILogTracerFactory { - LogTracer CreateLogTracer(Guid correlationId, IEnumerable<(string, string)>? tags = null, SeverityLevel severityLevel = SeverityLevel.Verbose); -} - -public class LogTracerFactory : ILogTracerFactory { - private List _loggers; - - public LogTracerFactory(List loggers) { - _loggers = loggers; - } - - public LogTracer CreateLogTracer(Guid correlationId, IEnumerable<(string, string)>? tags = null, SeverityLevel severityLevel = SeverityLevel.Verbose) { - return new(correlationId, tags, _loggers, severityLevel); - } -} - -public interface ILogSinks { - List GetLogSinks(); -} -public class LogSinks : ILogSinks { - private readonly List _loggers; - - public LogSinks(IServiceConfig config, TelemetryClient telemetryClient) { - _loggers = new List(); - foreach (var dest in config.LogDestinations) { - _loggers.Add( - dest switch { - LogDestination.AppInsights => new AppInsights(telemetryClient), - LogDestination.Console => new Console(), - _ => throw new Exception($"Unhandled Log Destination type: {dest}"), - } - ); - } - } - public List GetLogSinks() { - return _loggers; +/// +/// +/// +[ProviderAlias("OneFuzzLoggerProvider")] +public sealed class OneFuzzLoggerProvider : ILoggerProvider { + private readonly ConcurrentDictionary _loggers = new(StringComparer.OrdinalIgnoreCase); + private readonly IEnumerable telemetryConfigs; + + /// + /// + /// + /// + public OneFuzzLoggerProvider(IEnumerable telemetryConfigs) { + this.telemetryConfigs = telemetryConfigs; + } + /// + /// + /// + /// + /// + public ILogger CreateLogger(string categoryName) { + return _loggers.GetOrAdd(categoryName, name => new OneFuzzLogger(name, telemetryConfigs)); + } + + /// + /// + /// + public void Dispose() { + _loggers.Clear(); } } diff --git a/src/ApiService/ApiService/LogExt.cs b/src/ApiService/ApiService/LogExt.cs new file mode 100644 index 0000000000..adc84ddc4f --- /dev/null +++ b/src/ApiService/ApiService/LogExt.cs @@ -0,0 +1,24 @@ +using System.Net; +using Microsoft.Extensions.Logging; + +namespace Microsoft.OneFuzz.Service; +public static class LogExt { + /// + /// + /// + /// + /// + /// + public static void LogOneFuzzError(this ILogger logger, Error err) { + var errors = err.Errors ?? new List(); + logger.LogError("Error: Code = {Code}, Errors = {errorsString}", err.Code, string.Join(';', errors)); + } + + + public static void AddHttpStatus(this ILogger logger, (HttpStatusCode Status, string Reason) result) { + logger.AddTag("StatusCode", ((int)result.Status).ToString()); + logger.AddTag("ReasonPhrase", result.Reason); + } + + +} diff --git a/src/ApiService/ApiService/OneFuzzTypes/Model.cs b/src/ApiService/ApiService/OneFuzzTypes/Model.cs index 0a9ecc093b..7d49429176 100644 --- a/src/ApiService/ApiService/OneFuzzTypes/Model.cs +++ b/src/ApiService/ApiService/OneFuzzTypes/Model.cs @@ -183,6 +183,7 @@ public sealed override string ToString() { } }; + public record UserInfo(Guid? ApplicationId, Guid? ObjectId, String? Upn) { } diff --git a/src/ApiService/ApiService/Program.cs b/src/ApiService/ApiService/Program.cs index f3fe03dc66..4f538c3a67 100644 --- a/src/ApiService/ApiService/Program.cs +++ b/src/ApiService/ApiService/Program.cs @@ -9,36 +9,58 @@ using Azure.Identity; using Microsoft.ApplicationInsights.DependencyCollector; using Microsoft.Azure.Functions.Worker; +using Microsoft.Azure.Functions.Worker.Http; using Microsoft.Azure.Functions.Worker.Middleware; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using Microsoft.FeatureManagement; using Microsoft.Graph; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service; public class Program { + + /// + /// + /// public class LoggingMiddleware : IFunctionsWorkerMiddleware { + /// + /// + /// + /// + /// + /// public async Async.Task Invoke(FunctionContext context, FunctionExecutionDelegate next) { - var log = (ILogTracerInternal?)context.InstanceServices.GetService(); - if (log is not null) { - //TODO - //if correlation ID is available in HTTP request - //if correlation ID is available in Queue message - //log.ReplaceCorrelationId(Guid from request) - - log.ReplaceCorrelationId(Guid.NewGuid()); - log.AddTags(new[] { - ("InvocationId", context.InvocationId.ToString()) - }); + //https://learn.microsoft.com/en-us/azure/azure-monitor/app/custom-operations-tracking#applicationinsights-operations-vs-systemdiagnosticsactivity + using var activity = OneFuzzLogger.Activity; + _ = activity.Start(); + string correlationId = Guid.NewGuid().ToString(); + + if (await context.GetHttpRequestDataAsync() is HttpRequestData requestData) { + //if header has 1f-CorrelationId then use that + //otherwise check if message can be deserialized to {"correlationId": "SOME-GUID"}, then use that + + if (requestData.Headers.TryGetValues("CorrelationId", out var values1f)) { + correlationId = values1f.First(); + } else if (requestData.Headers.TryGetValues("x-correlationId", out var values)) { + correlationId = values.First(); + } } + _ = activity.AddTag(OneFuzzLogger.CorrelationId, correlationId); + _ = activity.AddTag("FunctionId", context.FunctionId); + _ = activity.AddTag("InvocationId", context.InvocationId); + await next(context); + + context.GetHttpResponseData()?.Headers.Add("x-correlationId", correlationId); } } + //Move out expensive resources into separate class, and add those as Singleton // ArmClient, Table Client(s), Queue Client(s), HttpClient, etc. public static async Async.Task Main() { @@ -46,6 +68,7 @@ public static async Async.Task Main() { using var host = new HostBuilder() + .ConfigureAppConfiguration(builder => { // Using a connection string in dev allows us to run the functions locally. if (!string.IsNullOrEmpty(configuration.AppConfigurationConnectionString)) { @@ -72,14 +95,6 @@ public static async Async.Task Main() { }); services - .AddScoped(s => { - var logSinks = s.GetRequiredService(); - var cfg = s.GetRequiredService(); - return new LogTracerFactory(logSinks.GetLogSinks()) - .CreateLogTracer( - Guid.Empty, - severityLevel: cfg.LogSeverityLevel); - }) .AddScoped() .AddScoped() .AddScoped() @@ -126,21 +141,34 @@ public static async Async.Task Main() { .AddSingleton() .AddSingleton(configuration) .AddSingleton() - .AddSingleton() .AddHttpClient() .AddMemoryCache() .AddAzureAppConfiguration(); _ = services.AddFeatureManagement(); }) + .ConfigureLogging(loggingBuilder => { + loggingBuilder.Services.TryAddEnumerable(ServiceDescriptor.Singleton( + x => { + var appInsightsConnectionString = $"InstrumentationKey={configuration.ApplicationInsightsInstrumentationKey}"; + var tc = new ApplicationInsights.TelemetryClient(new ApplicationInsights.Extensibility.TelemetryConfiguration() { ConnectionString = appInsightsConnectionString }); + return new OneFuzzLoggerProvider(new List() { new TelemetryConfig(tc) }); + } + )); + }) .ConfigureFunctionsWorkerDefaults(builder => { - builder.UseAzureAppConfiguration(); builder.UseMiddleware(); builder.UseMiddleware(); builder.UseMiddleware(); + + //this is a must, to tell the host that worker logging is done by us + builder.Services.Configure(workerOptions => workerOptions.Capabilities["WorkerApplicationInsightsLoggingEnabled"] = bool.TrueString); builder.AddApplicationInsights(options => { - options.ConnectionString = $"InstrumentationKey={configuration.ApplicationInsightsInstrumentationKey}"; + options.DeveloperMode = false; + options.EnableDependencyTrackingTelemetryModule = false; }); + builder.AddApplicationInsightsLogger(); + }) .Build(); diff --git a/src/ApiService/ApiService/TestHooks/ContainerTestHooks.cs b/src/ApiService/ApiService/TestHooks/ContainerTestHooks.cs index d1abe74888..0329eb0006 100644 --- a/src/ApiService/ApiService/TestHooks/ContainerTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/ContainerTestHooks.cs @@ -2,26 +2,27 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; - +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; #if DEBUG namespace ApiService.TestHooks { public class ContainerTestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; private readonly IContainers _containers; - public ContainerTestHooks(ILogTracer log, IConfigOperations configOps, IContainers containers) { - _log = log.WithTag("TestHooks", nameof(ContainerTestHooks)); + public ContainerTestHooks(ILogger log, IConfigOperations configOps, IContainers containers) { + _log = log; + _log.AddTag("TestHooks", nameof(ContainerTestHooks)); _configOps = configOps; _containers = containers; } [Function("GetInstanceIdTestHook")] public async Task GetInstanceId([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/containers/instanceId")] HttpRequestData req) { - _log.Info($"Get instance ID"); + _log.LogInformation("Get instance ID"); var instanceId = await _containers.GetInstanceId(); var resp = req.CreateResponse(HttpStatusCode.OK); diff --git a/src/ApiService/ApiService/TestHooks/CredsTestHooks.cs b/src/ApiService/ApiService/TestHooks/CredsTestHooks.cs index 0743e00b8b..54dbfd3dca 100644 --- a/src/ApiService/ApiService/TestHooks/CredsTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/CredsTestHooks.cs @@ -2,26 +2,27 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; - +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; #if DEBUG namespace ApiService.TestHooks { public class CredsTestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; private readonly ICreds _creds; - public CredsTestHooks(ILogTracer log, IConfigOperations configOps, ICreds creds) { - _log = log.WithTag("TestHooks", nameof(CredsTestHooks)); + public CredsTestHooks(ILogger log, IConfigOperations configOps, ICreds creds) { + _log = log; + _log.AddTag("TestHooks", nameof(CredsTestHooks)); _configOps = configOps; _creds = creds; } [Function("GetSubscriptionTestHook")] public async Task GetSubscription([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/creds/subscription")] HttpRequestData req) { - _log.Info($"Get subscription"); + _log.LogInformation($"Get subscription"); var resp = req.CreateResponse(HttpStatusCode.OK); await resp.WriteStringAsync(_creds.GetSubscription().ToString()); return resp; @@ -30,7 +31,7 @@ public async Task GetSubscription([HttpTrigger(AuthorizationLe [Function("GetBaseResourceGroupTestHook")] public async Task GetBaseResourceGroup([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/creds/baseResourceGroup")] HttpRequestData req) { - _log.Info($"Get base resource group"); + _log.LogInformation("Get base resource group"); var resp = req.CreateResponse(HttpStatusCode.OK); await resp.WriteStringAsync(_creds.GetBaseResourceGroup().ToString()); return resp; @@ -38,7 +39,7 @@ public async Task GetBaseResourceGroup([HttpTrigger(Authorizat [Function("GetInstanceNameTestHook")] public async Task GetInstanceName([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/creds/instanceName")] HttpRequestData req) { - _log.Info($"Get instance name"); + _log.LogInformation("Get instance name"); var resp = req.CreateResponse(HttpStatusCode.OK); await resp.WriteStringAsync(_creds.GetInstanceName().ToString()); return resp; @@ -46,7 +47,7 @@ public async Task GetInstanceName([HttpTrigger(AuthorizationLe [Function("GetBaseRegionTestHook")] public async Task GetBaseRegion([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/creds/baseRegion")] HttpRequestData req) { - _log.Info($"Get base region"); + _log.LogInformation("Get base region"); var resp = req.CreateResponse(HttpStatusCode.OK); var region = await _creds.GetBaseRegion(); await resp.WriteStringAsync(region.String); @@ -55,7 +56,7 @@ public async Task GetBaseRegion([HttpTrigger(AuthorizationLeve [Function("GetInstanceUrlTestHook")] public async Task GetInstanceUrl([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/creds/instanceUrl")] HttpRequestData req) { - _log.Info($"Get instance url"); + _log.LogInformation("Get instance url"); var resp = req.CreateResponse(HttpStatusCode.OK); await resp.WriteStringAsync(_creds.GetInstanceUrl().ToString()); return resp; diff --git a/src/ApiService/ApiService/TestHooks/DiskOperationsTestHooks.cs b/src/ApiService/ApiService/TestHooks/DiskOperationsTestHooks.cs index 9a9259876a..84de74d60e 100644 --- a/src/ApiService/ApiService/TestHooks/DiskOperationsTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/DiskOperationsTestHooks.cs @@ -2,20 +2,21 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; - +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; #if DEBUG namespace ApiService.TestHooks { public class DiskOperationsTestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; private readonly IDiskOperations _diskOps; private readonly ICreds _creds; - public DiskOperationsTestHooks(ILogTracer log, IConfigOperations configOps, IDiskOperations diskOps, ICreds creds) { - _log = log.WithTag("TestHooks", nameof(DiskOperationsTestHooks)); + public DiskOperationsTestHooks(ILogger log, IConfigOperations configOps, IDiskOperations diskOps, ICreds creds) { + _log = log; + _log.AddTag("TestHooks", nameof(DiskOperationsTestHooks)); _configOps = configOps; _diskOps = diskOps; _creds = creds; @@ -23,7 +24,7 @@ public DiskOperationsTestHooks(ILogTracer log, IConfigOperations configOps, IDis [Function("GetDiskNamesTestHook")] public async Task GetSubscription([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/disks")] HttpRequestData req) { - _log.Info($"Get disk names"); + _log.LogInformation("Get disk names"); var resp = req.CreateResponse(HttpStatusCode.OK); var diskNames = _diskOps.ListDisks(_creds.GetBaseResourceGroup()).ToList().Select(x => x.Data.Name); await resp.WriteAsJsonAsync(diskNames); diff --git a/src/ApiService/ApiService/TestHooks/EventsTestHooks.cs b/src/ApiService/ApiService/TestHooks/EventsTestHooks.cs index d90611fbc4..e650e04292 100644 --- a/src/ApiService/ApiService/TestHooks/EventsTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/EventsTestHooks.cs @@ -3,26 +3,27 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - #if DEBUG namespace ApiService.TestHooks { public class EventsTestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; private readonly IEvents _events; - public EventsTestHooks(ILogTracer log, IConfigOperations configOps, IEvents events) { - _log = log.WithTag("TestHooks", nameof(EventsTestHooks)); + public EventsTestHooks(ILogger log, IConfigOperations configOps, IEvents events) { + _log = log; + _log.AddTag("TestHooks", nameof(EventsTestHooks)); _configOps = configOps; _events = events; } [Function("LogEventTestHook")] public async Task LogEvent([HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = "testhooks/events/logEvent")] HttpRequestData req) { - _log.Info($"Log event"); + _log.LogInformation("Log event"); var s = await req.ReadAsStringAsync(); var msg = JsonSerializer.Deserialize(s!, EntityConverter.GetJsonSerializerOptions()); @@ -34,7 +35,7 @@ public async Task LogEvent([HttpTrigger(AuthorizationLevel.Ano [Function("SendEventTestHook")] public async Task SendEvent([HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = "testhooks/events/sendEvent")] HttpRequestData req) { - _log.Info($"Send event"); + _log.LogInformation("Send event"); var s = await req.ReadAsStringAsync(); var msg = JsonSerializer.Deserialize(s!, EntityConverter.GetJsonSerializerOptions()); diff --git a/src/ApiService/ApiService/TestHooks/ExtensionsTestHooks.cs b/src/ApiService/ApiService/TestHooks/ExtensionsTestHooks.cs index c109e2dc68..87056ff5bd 100644 --- a/src/ApiService/ApiService/TestHooks/ExtensionsTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/ExtensionsTestHooks.cs @@ -2,27 +2,28 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; - #if DEBUG namespace ApiService.TestHooks { public class ExtensionsTestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; private readonly IExtensions _extensions; - public ExtensionsTestHooks(ILogTracer log, IConfigOperations configOps, IExtensions extensions) { - _log = log.WithTag("TestHooks", nameof(ExtensionsTestHooks)); + public ExtensionsTestHooks(ILogger log, IConfigOperations configOps, IExtensions extensions) { + _log = log; + _log.AddTag("TestHooks", nameof(ExtensionsTestHooks)); _configOps = configOps; _extensions = extensions; } [Function("GenericExtensionsHook")] public async Task GenericExtensions([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/extensions/genericExtensions")] HttpRequestData req) { - _log.Info($"Get Generic extensions"); + _log.LogInformation("Get Generic extensions"); var query = UriExtension.GetQueryComponents(req.Url); Os os = Enum.Parse(query["os"]); diff --git a/src/ApiService/ApiService/TestHooks/InstanceConfigTestHooks.cs b/src/ApiService/ApiService/TestHooks/InstanceConfigTestHooks.cs index 70120049f0..8ecd7efcaf 100644 --- a/src/ApiService/ApiService/TestHooks/InstanceConfigTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/InstanceConfigTestHooks.cs @@ -3,29 +3,30 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - #if DEBUG namespace ApiService.TestHooks { public class InstanceConfigTestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; - public InstanceConfigTestHooks(ILogTracer log, IConfigOperations configOps) { - _log = log.WithTag("TestHooks", nameof(InstanceConfigTestHooks)); + public InstanceConfigTestHooks(ILogger log, IConfigOperations configOps) { + _log = log; + _log.AddTag("TestHooks", nameof(InstanceConfigTestHooks)); _configOps = configOps; } [Function("GetInstanceConfigTestHook")] public async Task Get([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/instance-config")] HttpRequestData req) { - _log.Info($"Fetching instance config"); + _log.LogInformation("Fetching instance config"); var config = await _configOps.Fetch(); if (config is null) { - _log.Error($"Instance config is null"); + _log.LogError("Instance config is null"); Error err = Error.Create(ErrorCode.INVALID_REQUEST, "Instance config is null"); var resp = req.CreateResponse(HttpStatusCode.InternalServerError); await resp.WriteAsJsonAsync(err); @@ -41,7 +42,7 @@ public async Task Get([HttpTrigger(AuthorizationLevel.Anonymou [Function("PatchInstanceConfigTestHook")] public async Task Patch([HttpTrigger(AuthorizationLevel.Anonymous, "patch", Route = "testhooks/instance-config")] HttpRequestData req) { - _log.Info($"Patch instance config"); + _log.LogInformation("Patch instance config"); var s = await req.ReadAsStringAsync(); var newInstanceConfig = JsonSerializer.Deserialize(s!, EntityConverter.GetJsonSerializerOptions()); diff --git a/src/ApiService/ApiService/TestHooks/IpOperationsTestHooks.cs b/src/ApiService/ApiService/TestHooks/IpOperationsTestHooks.cs index 1e6926ed7e..c969274af0 100644 --- a/src/ApiService/ApiService/TestHooks/IpOperationsTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/IpOperationsTestHooks.cs @@ -2,25 +2,26 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; - #if DEBUG namespace ApiService.TestHooks { public class IpOperationsTestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; private readonly IIpOperations _ipOps; - public IpOperationsTestHooks(ILogTracer log, IConfigOperations configOps, IIpOperations ipOps) { - _log = log.WithTag("TestHooks", nameof(IpOperationsTestHooks)); + public IpOperationsTestHooks(ILogger log, IConfigOperations configOps, IIpOperations ipOps) { + _log = log; + _log.AddTag("TestHooks", nameof(IpOperationsTestHooks)); _configOps = configOps; _ipOps = ipOps; } [Function("GetPublicNicTestHook")] public async Task GetPublicNic([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/ipOps/publicNic")] HttpRequestData req) { - _log.Info($"Get public nic"); + _log.LogInformation("Get public nic"); var query = UriExtension.GetQueryComponents(req.Url); @@ -39,7 +40,7 @@ public async Task GetPublicNic([HttpTrigger(AuthorizationLevel [Function("GetIpTestHook")] public async Task GetIp([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/ipOps/ip")] HttpRequestData req) { - _log.Info($"Get public nic"); + _log.LogInformation("Get public nic"); var query = UriExtension.GetQueryComponents(req.Url); @@ -60,7 +61,7 @@ public async Task GetIp([HttpTrigger(AuthorizationLevel.Anonym [Function("DeletePublicNicTestHook")] public async Task DeletePublicNic([HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "testhooks/ipOps/publicNic")] HttpRequestData req) { - _log.Info($"Get public nic"); + _log.LogInformation("Get public nic"); var query = UriExtension.GetQueryComponents(req.Url); @@ -80,7 +81,7 @@ public async Task DeletePublicNic([HttpTrigger(AuthorizationLe [Function("DeleteIpTestHook")] public async Task DeleteIp([HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "testhooks/ipOps/ip")] HttpRequestData req) { - _log.Info($"Get public nic"); + _log.LogInformation("Get public nic"); var query = UriExtension.GetQueryComponents(req.Url); diff --git a/src/ApiService/ApiService/TestHooks/JobOperationsTestHooks.cs b/src/ApiService/ApiService/TestHooks/JobOperationsTestHooks.cs index 2995cfaf43..e268d14cd2 100644 --- a/src/ApiService/ApiService/TestHooks/JobOperationsTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/JobOperationsTestHooks.cs @@ -3,19 +3,20 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - #if DEBUG namespace ApiService.TestHooks { public class JobOperationsTestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; private readonly IJobOperations _jobOps; - public JobOperationsTestHooks(ILogTracer log, IConfigOperations configOps, IJobOperations jobOps) { - _log = log.WithTag("TestHooks", nameof(JobOperationsTestHooks)); + public JobOperationsTestHooks(ILogger log, IConfigOperations configOps, IJobOperations jobOps) { + _log = log; + _log.AddTag("TestHooks", nameof(JobOperationsTestHooks)); _configOps = configOps; _jobOps = jobOps; } @@ -23,7 +24,7 @@ public JobOperationsTestHooks(ILogTracer log, IConfigOperations configOps, IJobO [Function("JobTestHook")] public async Task GetJob([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/jobOps/job")] HttpRequestData req) { - _log.Info($"Get job info"); + _log.LogInformation("Get job info"); var query = UriExtension.GetQueryComponents(req.Url); var jobId = Guid.Parse(query["jobId"]); @@ -38,7 +39,7 @@ public async Task GetJob([HttpTrigger(AuthorizationLevel.Anony [Function("SearchExpiredTestHook")] public async Task SearchExpired([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/jobOps/searchExpired")] HttpRequestData req) { - _log.Info($"Search expired jobs"); + _log.LogInformation("Search expired jobs"); var jobs = await _jobOps.SearchExpired().ToListAsync(); @@ -50,7 +51,7 @@ public async Task SearchExpired([HttpTrigger(AuthorizationLeve [Function("SearchStateTestHook")] public async Task SearchState([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/jobOps/searchState")] HttpRequestData req) { - _log.Info($"Search jobs by state"); + _log.LogInformation("Search jobs by state"); var query = UriExtension.GetQueryComponents(req.Url); var init = UriExtension.GetBool("init", query, false); diff --git a/src/ApiService/ApiService/TestHooks/LogAnalyticsTestHooks.cs b/src/ApiService/ApiService/TestHooks/LogAnalyticsTestHooks.cs index 8d3590731e..245c0427b5 100644 --- a/src/ApiService/ApiService/TestHooks/LogAnalyticsTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/LogAnalyticsTestHooks.cs @@ -3,27 +3,28 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - #if DEBUG namespace ApiService.TestHooks { public class LogAnalyticsTestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; private readonly ILogAnalytics _logAnalytics; - public LogAnalyticsTestHooks(ILogTracer log, IConfigOperations configOps, ILogAnalytics logAnalytics) { - _log = log.WithTag("TestHooks", nameof(LogAnalyticsTestHooks)); + public LogAnalyticsTestHooks(ILogger log, IConfigOperations configOps, ILogAnalytics logAnalytics) { + _log = log; + _log.AddTag("TestHooks", nameof(LogAnalyticsTestHooks)); _configOps = configOps; _logAnalytics = logAnalytics; } [Function("MonitorSettingsTestHook")] public async Task GetMonitorSettings([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/logAnalytics/monitorSettings")] HttpRequestData req) { - _log.Info($"Get monitor settings"); + _log.LogInformation("Get monitor settings"); var monitorSettings = await _logAnalytics.GetMonitorSettings(); @@ -35,7 +36,7 @@ public async Task GetMonitorSettings([HttpTrigger(Authorizatio [Function("WorkspaceIdTestHook")] public async Task GetWorkspaceId([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/logAnalytics/workspaceId")] HttpRequestData req) { - _log.Info($"Get workspace id"); + _log.LogInformation("Get workspace id"); var workspaceId = _logAnalytics.GetWorkspaceId(); var resp = req.CreateResponse(HttpStatusCode.OK); diff --git a/src/ApiService/ApiService/TestHooks/NodeOperationsTestHooks.cs b/src/ApiService/ApiService/TestHooks/NodeOperationsTestHooks.cs index 11ad95891e..02fedc8021 100644 --- a/src/ApiService/ApiService/TestHooks/NodeOperationsTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/NodeOperationsTestHooks.cs @@ -3,29 +3,30 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - #if DEBUG namespace ApiService.TestHooks { sealed record MarkTasks(Node node, Error error); public class NodeOperationsTestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; private readonly INodeOperations _nodeOps; - public NodeOperationsTestHooks(ILogTracer log, IConfigOperations configOps, INodeOperations nodeOps) { - _log = log.WithTag("TestHooks", nameof(NodeOperationsTestHooks)); + public NodeOperationsTestHooks(ILogger log, IConfigOperations configOps, INodeOperations nodeOps) { + _log = log; + _log.AddTag("TestHooks", nameof(NodeOperationsTestHooks)); _configOps = configOps; _nodeOps = nodeOps; } [Function("GetByMachineIdTestHook")] public async Task GetByMachineId([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/nodeOperations/getByMachineId")] HttpRequestData req) { - _log.Info($"Get node by machine id"); + _log.LogInformation("Get node by machine id"); var query = UriExtension.GetQueryComponents(req.Url); var machineId = query["machineId"]; @@ -40,7 +41,7 @@ public async Task GetByMachineId([HttpTrigger(AuthorizationLev [Function("CanProcessNewWorkTestHook")] public async Task CanProcessNewWork([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "testhooks/nodeOperations/canProcessNewWork")] HttpRequestData req) { - _log.Info($"Can process new work"); + _log.LogInformation("Can process new work"); var s = await req.ReadAsStringAsync(); var node = JsonSerializer.Deserialize(s!, EntityConverter.GetJsonSerializerOptions()); @@ -54,7 +55,7 @@ public async Task CanProcessNewWork([HttpTrigger(Authorization [Function("IsOutdatedTestHook")] public async Task IsOutdated([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "testhooks/nodeOperations/isOutdated")] HttpRequestData req) { - _log.Info($"Is outdated"); + _log.LogInformation("Is outdated"); var s = await req.ReadAsStringAsync(); var node = JsonSerializer.Deserialize(s!, EntityConverter.GetJsonSerializerOptions()); @@ -68,7 +69,7 @@ public async Task IsOutdated([HttpTrigger(AuthorizationLevel.A [Function("IsTooOldTestHook")] public async Task IsTooOld([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "testhooks/nodeOperations/isTooOld")] HttpRequestData req) { - _log.Info($"Is too old"); + _log.LogInformation("Is too old"); var s = await req.ReadAsStringAsync(); var node = JsonSerializer.Deserialize(s!, EntityConverter.GetJsonSerializerOptions()); @@ -81,7 +82,7 @@ public async Task IsTooOld([HttpTrigger(AuthorizationLevel.Ano [Function("CouldShrinkScalesetTestHook")] public async Task CouldShrinkScaleset([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "testhooks/nodeOperations/couldShrinkScaleset")] HttpRequestData req) { - _log.Info($"Could shrink scaleset"); + _log.LogInformation("Could shrink scaleset"); var s = await req.ReadAsStringAsync(); var node = JsonSerializer.Deserialize(s!, EntityConverter.GetJsonSerializerOptions()); @@ -95,7 +96,7 @@ public async Task CouldShrinkScaleset([HttpTrigger(Authorizati [Function("SetHaltTestHook")] public async Task SetHalt([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "testhooks/nodeOperations/setHalt")] HttpRequestData req) { - _log.Info($"set halt"); + _log.LogInformation("set halt"); var s = await req.ReadAsStringAsync(); var node = JsonSerializer.Deserialize(s!, EntityConverter.GetJsonSerializerOptions()); @@ -108,7 +109,7 @@ public async Task SetHalt([HttpTrigger(AuthorizationLevel.Anon [Function("SetStateTestHook")] public async Task SetState([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "testhooks/nodeOperations/setState")] HttpRequestData req) { - _log.Info($"set state"); + _log.LogInformation("set state"); var query = UriExtension.GetQueryComponents(req.Url); var state = Enum.Parse(query["state"]); @@ -125,7 +126,7 @@ public async Task SetState([HttpTrigger(AuthorizationLevel.Ano [Function("ToReimageTestHook")] public async Task ToReimage([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "testhooks/nodeOperations/toReimage")] HttpRequestData req) { - _log.Info($"to reimage"); + _log.LogInformation("to reimage"); var query = UriExtension.GetQueryComponents(req.Url); var done = UriExtension.GetBool("done", query, false); @@ -141,7 +142,7 @@ public async Task ToReimage([HttpTrigger(AuthorizationLevel.An [Function("SendStopIfFreeTestHook")] public async Task SendStopIfFree([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "testhooks/nodeOperations/sendStopIfFree")] HttpRequestData req) { - _log.Info($"send stop if free"); + _log.LogInformation("send stop if free"); var s = await req.ReadAsStringAsync(); var node = JsonSerializer.Deserialize(s!, EntityConverter.GetJsonSerializerOptions()); @@ -155,7 +156,7 @@ public async Task SendStopIfFree([HttpTrigger(AuthorizationLev [Function("SearchStatesTestHook")] public async Task SearchStates([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "testhooks/nodeOperations/searchStates")] HttpRequestData req) { - _log.Info($"search states"); + _log.LogInformation("search states"); var query = UriExtension.GetQueryComponents(req.Url); Guid? poolId = UriExtension.GetGuid("poolId", query); @@ -184,7 +185,7 @@ is string scalesetId [Function("DeleteNodeTestHook")] public async Task DeleteNode([HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "testhooks/nodeOperations/node")] HttpRequestData req) { - _log.Info($"delete node"); + _log.LogInformation("delete node"); var s = await req.ReadAsStringAsync(); var node = JsonSerializer.Deserialize(s!, EntityConverter.GetJsonSerializerOptions()); @@ -196,7 +197,7 @@ public async Task DeleteNode([HttpTrigger(AuthorizationLevel.A [Function("ReimageLongLivedNodesTestHook")] public async Task ReimageLongLivedNodes([HttpTrigger(AuthorizationLevel.Anonymous, "patch", Route = "testhooks/nodeOperations/reimageLongLivedNodes")] HttpRequestData req) { - _log.Info($"reimage long lived nodes"); + _log.LogInformation("reimage long lived nodes"); var query = UriExtension.GetQueryComponents(req.Url); var r = _nodeOps.ReimageLongLivedNodes(ScalesetId.Parse(query["scaleSetId"])); @@ -208,7 +209,7 @@ public async Task ReimageLongLivedNodes([HttpTrigger(Authoriza [Function("CreateTestHook")] public async Task CreateNode([HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = "testhooks/nodeOperations/node")] HttpRequestData req) { - _log.Info($"create node"); + _log.LogInformation("create node"); var query = UriExtension.GetQueryComponents(req.Url); @@ -235,7 +236,7 @@ public async Task CreateNode([HttpTrigger(AuthorizationLevel.A [Function("GetDeadNodesTestHook")] public async Task GetDeadNodes([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "testhooks/nodeOperations/getDeadNodes")] HttpRequestData req) { - _log.Info($"get dead nodes"); + _log.LogInformation("get dead nodes"); var query = UriExtension.GetQueryComponents(req.Url); @@ -252,7 +253,7 @@ public async Task GetDeadNodes([HttpTrigger(AuthorizationLevel [Function("MarkTasksStoppedEarly")] public async Task MarkTasksStoppedEarly([HttpTrigger(AuthorizationLevel.Anonymous, "patch", Route = "testhooks/nodeOperations/markTasksStoppedEarly")] HttpRequestData req) { - _log.Info($"mark tasks stopped early"); + _log.LogInformation("mark tasks stopped early"); var s = await req.ReadAsStringAsync(); var markTasks = JsonSerializer.Deserialize(s!, EntityConverter.GetJsonSerializerOptions()); diff --git a/src/ApiService/ApiService/TestHooks/NotificationOperationsTestHooks.cs b/src/ApiService/ApiService/TestHooks/NotificationOperationsTestHooks.cs index cea9290ac9..247403fdf0 100644 --- a/src/ApiService/ApiService/TestHooks/NotificationOperationsTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/NotificationOperationsTestHooks.cs @@ -3,27 +3,28 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - #if DEBUG namespace ApiService.TestHooks { public class NotificationOperationsTestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; private readonly INotificationOperations _notificationOps; - public NotificationOperationsTestHooks(ILogTracer log, IConfigOperations configOps, INotificationOperations notificationOps) { - _log = log.WithTag("TestHooks", nameof(NotificationOperationsTestHooks)); + public NotificationOperationsTestHooks(ILogger log, IConfigOperations configOps, INotificationOperations notificationOps) { + _log = log; + _log.AddTag("TestHooks", nameof(NotificationOperationsTestHooks)); _configOps = configOps; ; _notificationOps = notificationOps; } [Function("NewFilesTestHook")] public async Task NewFiles([HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = "testhooks/notificationOperations/newFiles")] HttpRequestData req) { - _log.Info($"new files"); + _log.LogInformation("new files"); var query = UriExtension.GetQueryComponents(req.Url); var container = query["container"]; @@ -37,7 +38,7 @@ public async Task NewFiles([HttpTrigger(AuthorizationLevel.Ano [Function("GetNotificationsTestHook")] public async Task GetNotifications([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/notificationOperations/getNotifications")] HttpRequestData req) { - _log.Info($"get notifications"); + _log.LogInformation("get notifications"); var s = await req.ReadAsStringAsync(); @@ -54,7 +55,7 @@ public async Task GetNotifications([HttpTrigger(AuthorizationL [Function("GetQueueTasksTestHook")] public async Task GetQueueTasksTestHook([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/notificationOperations/getQueueTasks")] HttpRequestData req) { - _log.Info($"get queue tasks"); + _log.LogInformation("get queue tasks"); var queueuTasks = _notificationOps.GetQueueTasks(); var json = JsonSerializer.Serialize(await queueuTasks.ToListAsync(), EntityConverter.GetJsonSerializerOptions()); @@ -66,7 +67,7 @@ public async Task GetQueueTasksTestHook([HttpTrigger(Authoriza [Function("GetRegressionReportTaskTestHook")] public async Task GetRegressionReportTask([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "testhooks/notificationOperations/getRegressionReportTask")] HttpRequestData req) { - _log.Info($"get regression report task"); + _log.LogInformation("get regression report task"); var s = await req.ReadAsStringAsync(); var report = JsonSerializer.Deserialize(s!, EntityConverter.GetJsonSerializerOptions()); diff --git a/src/ApiService/ApiService/TestHooks/NsgOperationsTestHooks.cs b/src/ApiService/ApiService/TestHooks/NsgOperationsTestHooks.cs index 02285d0be3..e3c4a9173a 100644 --- a/src/ApiService/ApiService/TestHooks/NsgOperationsTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/NsgOperationsTestHooks.cs @@ -2,20 +2,21 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; - #if DEBUG namespace ApiService.TestHooks { public class NsgOperationsTestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; private readonly INsgOperations _nsgOperations; - public NsgOperationsTestHooks(ILogTracer log, IConfigOperations configOps, INsgOperations nsgOperations) { - _log = log.WithTag("TestHooks", nameof(NsgOperationsTestHooks)); + public NsgOperationsTestHooks(ILogger log, IConfigOperations configOps, INsgOperations nsgOperations) { + _log = log; + _log.AddTag("TestHooks", nameof(NsgOperationsTestHooks)); _configOps = configOps; ; _nsgOperations = nsgOperations; } @@ -23,7 +24,7 @@ public NsgOperationsTestHooks(ILogTracer log, IConfigOperations configOps, INsgO [Function("GetNsgTestHook")] public async Task GetNsg([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/nsgOperations/nsg")] HttpRequestData req) { - _log.Info($"get nsg"); + _log.LogInformation("get nsg"); var query = UriExtension.GetQueryComponents(req.Url); var nsg = await _nsgOperations.GetNsg(query["name"]); @@ -41,7 +42,7 @@ public async Task GetNsg([HttpTrigger(AuthorizationLevel.Anony [Function("ListNsgsTestHook")] public async Task ListNsgs([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/nsgOperations/listNsgs")] HttpRequestData req) { - _log.Info($"list nsgs"); + _log.LogInformation("list nsgs"); var nsgs = await _nsgOperations.ListNsgs().ToListAsync(); @@ -53,7 +54,7 @@ public async Task ListNsgs([HttpTrigger(AuthorizationLevel.Ano [Function("DeleteNsgTestHook")] public async Task DeleteNsg([HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "testhooks/nsgOperations/nsg")] HttpRequestData req) { - _log.Info($"delete nsgs"); + _log.LogInformation("delete nsgs"); var query = UriExtension.GetQueryComponents(req.Url); var name = query["name"]; diff --git a/src/ApiService/ApiService/TestHooks/PoolOperationsTestHooks.cs b/src/ApiService/ApiService/TestHooks/PoolOperationsTestHooks.cs index 29ca9a16c5..4f9b039720 100644 --- a/src/ApiService/ApiService/TestHooks/PoolOperationsTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/PoolOperationsTestHooks.cs @@ -3,18 +3,19 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - #if DEBUG namespace ApiService.TestHooks { public class PoolOperationsTestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; private readonly IPoolOperations _poolOps; - public PoolOperationsTestHooks(ILogTracer log, IConfigOperations configOps, IPoolOperations poolOps) { - _log = log.WithTag("TestHooks", nameof(PoolOperationsTestHooks)); + public PoolOperationsTestHooks(ILogger log, IConfigOperations configOps, IPoolOperations poolOps) { + _log = log; + _log.AddTag("TestHooks", nameof(PoolOperationsTestHooks)); _configOps = configOps; ; _poolOps = poolOps; } @@ -22,7 +23,7 @@ public PoolOperationsTestHooks(ILogTracer log, IConfigOperations configOps, IPoo [Function("GetPoolTestHook")] public async Task GetPool([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/poolOperations/pool")] HttpRequestData req) { - _log.Info($"get pool"); + _log.LogInformation("get pool"); var query = UriExtension.GetQueryComponents(req.Url); var poolRes = await _poolOps.GetByName(PoolName.Parse(query["name"])); diff --git a/src/ApiService/ApiService/TestHooks/ProxyForwardTestHooks.cs b/src/ApiService/ApiService/TestHooks/ProxyForwardTestHooks.cs index 3e83b8c820..5ec9896ded 100644 --- a/src/ApiService/ApiService/TestHooks/ProxyForwardTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/ProxyForwardTestHooks.cs @@ -3,26 +3,26 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - - #if DEBUG namespace ApiService.TestHooks { public class ProxyForwardTestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; private readonly IProxyForwardOperations _proxyForward; - public ProxyForwardTestHooks(ILogTracer log, IConfigOperations configOps, IProxyForwardOperations proxyForward) { - _log = log.WithTag("TestHooks", nameof(ProxyForwardTestHooks)); + public ProxyForwardTestHooks(ILogger log, IConfigOperations configOps, IProxyForwardOperations proxyForward) { + _log = log; + _log.AddTag("TestHooks", nameof(ProxyForwardTestHooks)); _configOps = configOps; ; _proxyForward = proxyForward; ; } [Function("SearchForwardTestHook")] public async Task SearchForward([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/proxyForwardOperations/search")] HttpRequestData req) { - _log.Info($"search proxy forward"); + _log.LogInformation("search proxy forward"); var query = UriExtension.GetQueryComponents(req.Url); diff --git a/src/ApiService/ApiService/TestHooks/TestHooks.cs b/src/ApiService/ApiService/TestHooks/TestHooks.cs index f0e9672974..e624c42c26 100644 --- a/src/ApiService/ApiService/TestHooks/TestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/TestHooks.cs @@ -3,21 +3,21 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service; #if DEBUG public record FunctionInfo(string Name, string ResourceGroup, string? SlotName); public class TestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; private readonly IEvents _events; private readonly IServiceConfig _config; private readonly ISecretsOperations _secretOps; private readonly ILogAnalytics _logAnalytics; - public TestHooks(ILogTracer log, IConfigOperations configOps, IEvents events, IServiceConfig config, ISecretsOperations secretOps, ILogAnalytics logAnalytics) { + public TestHooks(ILogger log, IConfigOperations configOps, IEvents events, IServiceConfig config, ISecretsOperations secretOps, ILogAnalytics logAnalytics) { _log = log; _configOps = configOps; _events = events; @@ -28,30 +28,29 @@ public TestHooks(ILogTracer log, IConfigOperations configOps, IEvents events, IS [Function("_Info")] public async Task Info([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/info")] HttpRequestData req) { - _log.Info($"Creating function info response"); + _log.LogInformation("Creating function info response"); var response = req.CreateResponse(); FunctionInfo info = new( $"{_config.OneFuzzInstanceName}", $"{_config.OneFuzzResourceGroup}", Environment.GetEnvironmentVariable("WEBSITE_SLOT_NAME")); - _log.Info($"Returning function info"); + _log.LogInformation("Returning function info"); await response.WriteAsJsonAsync(info); - _log.Info($"Returned function info"); + _log.LogInformation("Returned function info"); return response; } - [Function("SaveToKeyvault")] public async Task SaveToKeyvault([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "testhooks/secrets/keyvault")] HttpRequestData req) { var s = await req.ReadAsStringAsync(); var secretData = JsonSerializer.Deserialize>(s!, EntityConverter.GetJsonSerializerOptions()); if (secretData is null) { - _log.Error($"Secret data is null"); + _log.LogError("Secret data is null"); return req.CreateResponse(HttpStatusCode.BadRequest); } else { - _log.Info($"Saving secret data in the keyvault"); + _log.LogInformation("Saving secret data in the keyvault"); var r = await _secretOps.StoreSecretData(secretData); var resp = req.CreateResponse(HttpStatusCode.OK); diff --git a/src/ApiService/ApiService/TestHooks/VmssTestHooks.cs b/src/ApiService/ApiService/TestHooks/VmssTestHooks.cs index 73bf64878c..94b3769abb 100644 --- a/src/ApiService/ApiService/TestHooks/VmssTestHooks.cs +++ b/src/ApiService/ApiService/TestHooks/VmssTestHooks.cs @@ -3,20 +3,21 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - #if DEBUG namespace ApiService.TestHooks { public class VmssTestHooks { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IConfigOperations _configOps; private readonly IVmssOperations _vmssOps; private readonly IScalesetOperations _scalesetOperations; - public VmssTestHooks(ILogTracer log, IConfigOperations configOps, IVmssOperations vmssOps, IScalesetOperations scalesetOperations) { - _log = log.WithTag("TestHooks", nameof(VmssTestHooks)); + public VmssTestHooks(ILogger log, IConfigOperations configOps, IVmssOperations vmssOps, IScalesetOperations scalesetOperations) { + _log = log; + _log.AddTag("TestHooks", nameof(VmssTestHooks)); _configOps = configOps; _vmssOps = vmssOps; _scalesetOperations = scalesetOperations; @@ -25,7 +26,7 @@ public VmssTestHooks(ILogTracer log, IConfigOperations configOps, IVmssOperation [Function("ListInstanceIdsTesHook")] public async Task ListInstanceIds([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/vmssOperations/listInstanceIds")] HttpRequestData req) { - _log.Info($"list instance ids"); + _log.LogInformation("list instance ids"); var query = UriExtension.GetQueryComponents(req.Url); var name = UriExtension.GetString("name", query) ?? throw new Exception("name must be set"); var ids = await _vmssOps.ListInstanceIds(ScalesetId.Parse(name)); @@ -38,7 +39,7 @@ public async Task ListInstanceIds([HttpTrigger(AuthorizationLe [Function("GetInstanceIdsTesHook")] public async Task GetInstanceId([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/vmssOperations/getInstanceId")] HttpRequestData req) { - _log.Info($"list instance ids"); + _log.LogInformation("list instance ids"); var query = UriExtension.GetQueryComponents(req.Url); var name = UriExtension.GetString("name", query) ?? throw new Exception("name must be set"); var vmId = UriExtension.GetGuid("vmId", query) ?? throw new Exception("vmId must be set"); @@ -52,7 +53,7 @@ public async Task GetInstanceId([HttpTrigger(AuthorizationLeve [Function("UpdateScaleInProtectionTestHook")] public async Task UpdateScaleInProtection([HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = "testhooks/vmssOperations/updateScaleInProtection")] HttpRequestData req) { - _log.Info($"list instance ids"); + _log.LogInformation("list instance ids"); var query = UriExtension.GetQueryComponents(req.Url); var name = UriExtension.GetString("name", query) ?? throw new Exception("name must be set"); var instanceId = UriExtension.GetString("instanceId", query) ?? throw new Exception("instanceId must be set"); diff --git a/src/ApiService/ApiService/host.json b/src/ApiService/ApiService/host.json index 0a60d6e92a..beb2e4020b 100644 --- a/src/ApiService/ApiService/host.json +++ b/src/ApiService/ApiService/host.json @@ -3,8 +3,8 @@ "logging": { "applicationInsights": { "samplingSettings": { - "isEnabled": false, - "excludedTypes": "Request;Trace;Dependency;Event;Exception" + "isEnabled": true, + "excludedTypes": "Request" } } } diff --git a/src/ApiService/ApiService/onefuzzlib/Auth.cs b/src/ApiService/ApiService/onefuzzlib/Auth.cs index c2a6395254..32832553a5 100644 --- a/src/ApiService/ApiService/onefuzzlib/Auth.cs +++ b/src/ApiService/ApiService/onefuzzlib/Auth.cs @@ -1,7 +1,7 @@ namespace Microsoft.OneFuzz.Service; using System.Diagnostics; using System.IO; - +using Microsoft.Extensions.Logging; public static class AuthHelpers { private static ProcessStartInfo SshKeyGenProcConfig(string tempFile) { @@ -32,13 +32,13 @@ private static ProcessStartInfo SshKeyGenProcConfig(string tempFile) { } // This works both on Windows and Linux azure function hosts - private static async Async.Task<(string, string)> GenerateKeyValuePair(ILogTracer log) { + private static async Async.Task<(string, string)> GenerateKeyValuePair(ILogger log) { var tmpFile = Path.GetTempFileName(); try { File.Delete(tmpFile); } catch (Exception ex) { //bad but not worth the failure - log.Warning($"failed to delete temp file {tmpFile:Tag:TempFile} due to {ex:Tag:Exception}"); + log.LogWarning(ex, "failed to delete temp file {TempFile} due to {Exception}", tmpFile, ex.Message); } tmpFile = tmpFile + ".key"; var startInfo = SshKeyGenProcConfig(tmpFile); @@ -56,13 +56,13 @@ private static ProcessStartInfo SshKeyGenProcConfig(string tempFile) { File.Delete(tmpFile); } catch (Exception ex) { //bad but not worth failing - log.Warning($"failed to delete temp file {tmpFile:Tag:TempFile} due to {ex:Tag:Exception}"); + log.LogWarning(ex, "failed to delete temp file {TempFile} due to {Exception}", tmpFile, ex.Message); } try { File.Delete(tmpFilePub); } catch (Exception ex) { //bad but not worth failing - log.Warning($"failed to delete temp file {tmpFilePub:Tag:TempFile} due to {ex:Tag:Exception}"); + log.LogWarning(ex, "failed to delete temp file {TempFile} due to {Exception}", tmpFilePub, ex.Message); } return (priv, pub.Trim()); } else { @@ -71,7 +71,7 @@ private static ProcessStartInfo SshKeyGenProcConfig(string tempFile) { } - public static async Async.Task BuildAuth(ILogTracer log) { + public static async Async.Task BuildAuth(ILogger log) { var (priv, pub) = await GenerateKeyValuePair(log); return new Authentication( Password: Guid.NewGuid().ToString(), diff --git a/src/ApiService/ApiService/onefuzzlib/AutoScale.cs b/src/ApiService/ApiService/onefuzzlib/AutoScale.cs index 9d35085aba..d721715737 100644 --- a/src/ApiService/ApiService/onefuzzlib/AutoScale.cs +++ b/src/ApiService/ApiService/onefuzzlib/AutoScale.cs @@ -5,6 +5,7 @@ using Azure; using Azure.ResourceManager.Monitor; using Azure.ResourceManager.Monitor.Models; +using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Tokens; namespace Microsoft.OneFuzz.Service; @@ -48,7 +49,7 @@ Async.Task Update( public class AutoScaleOperations : Orm, IAutoScaleOperations { - public AutoScaleOperations(ILogTracer log, IOnefuzzContext context) + public AutoScaleOperations(ILogger log, IOnefuzzContext context) : base(log, context) { } @@ -76,7 +77,8 @@ public async Async.Task Create( var r = await Insert(entry); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"Failed to save auto-scale record {scalesetId:Tag:ScalesetId} {minAmount:Tag:MinAmount} {maxAmount:Tag:MaxAmount} {defaultAmount:Tag:DefaultAmount} {scaleOutAmount:Tag:ScaleoutAmount} {scaleOutCooldown:Tag:ScaleoutCooldown} {scaleInAmount:Tag:ScaleinAmount} {scaleInCooldown:Tag:ScaleInCooldown}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("Failed to save auto-scale record {ScalesetId} {MinAmount} {MaxAmount} {DefaultAmount} {ScaleoutAmount} {ScaleoutCooldown} {ScaleinAmount} {ScaleInCooldown}", scalesetId, minAmount, maxAmount, defaultAmount, scaleOutAmount, scaleOutCooldown, scaleInAmount, scaleInCooldown); } return entry; } @@ -86,13 +88,13 @@ public async Async.Task Create( var autoscale = await GetEntityAsync(scalesetId.ToString(), scalesetId.ToString()); return autoscale; } catch (Exception ex) { - _logTracer.Exception(ex, $"Failed to get auto-scale entity {scalesetId:Tag:ScalesetId}"); + _logTracer.LogError(ex, "Failed to get auto-scale entity {ScalesetId}", scalesetId); return null; } } public async Async.Task> GetAutoScaleProfile(ScalesetId scalesetId) { - _logTracer.Info($"getting scaleset for existing auto-scale resources {scalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("getting scaleset for existing auto-scale resources {ScalesetId}", scalesetId); var settings = _context.Creds.GetResourceGroupResource().GetAutoscaleSettings(); if (settings is null) { return OneFuzzResult.Error(ErrorCode.INVALID_CONFIGURATION, $"could not find any auto-scale settings for the resource group"); @@ -104,7 +106,7 @@ public async Async.Task> GetAutoScaleProfile(Sca return OneFuzzResult.Error(ErrorCode.INVALID_CONFIGURATION, $"found {setting.Data.Profiles.Count} auto-scale profiles for {scalesetId}"); } else { if (setting.Data.Profiles.Count != 1) { - _logTracer.Warning($"Found more than one autoscaling profile for scaleset {scalesetId:Tag:ScalesetId}"); + _logTracer.LogWarning("Found more than one autoscaling profile for scaleset {ScalesetId}", scalesetId); } return OneFuzzResult.Ok(setting.Data.Profiles.First()); } @@ -115,7 +117,7 @@ public async Async.Task> GetAutoScaleProfile(Sca } public async Async.Task AddAutoScaleToVmss(ScalesetId vmss, AutoscaleProfile autoScaleProfile) { - _logTracer.Info($"Checking scaleset {vmss:Tag:ScalesetId} for existing auto scale resource"); + _logTracer.LogInformation("Checking scaleset {ScalesetId} for existing auto scale resource", vmss); var existingAutoScaleResource = GetAutoscaleSettings(vmss); @@ -132,7 +134,7 @@ public async Async.Task AddAutoScaleToVmss(ScalesetId vmss, A return OneFuzzResultVoid.Error(autoScaleResource.ErrorV); } var workspaceId = _context.LogAnalytics.GetWorkspaceId().ToString(); - _logTracer.Info($"Setting up diagnostics for {autoScaleResource.OkV.Id!:Tag:AutoscaleResourceId} - {autoScaleResource.OkV.Data.Name:Tag:AutoscaleResourceName} - {workspaceId:Tag:WorkspaceId}"); + _logTracer.LogInformation("Setting up diagnostics for {AutoscaleResourceId} - {AutoscaleResourceName} - {WorkspaceId}", autoScaleResource.OkV.Id!, autoScaleResource.OkV.Data.Name, workspaceId); var diagnosticsResource = await SetupAutoScaleDiagnostics(autoScaleResource.OkV, workspaceId); if (!diagnosticsResource.IsOk) { @@ -142,7 +144,7 @@ public async Async.Task AddAutoScaleToVmss(ScalesetId vmss, A return OneFuzzResultVoid.Ok; } private async Async.Task> CreateAutoScaleResourceFor(ScalesetId resourceId, Region location, AutoscaleProfile profile) { - _logTracer.Info($"Creating auto-scale resource for: {resourceId:Tag:AutoscaleResourceId}"); + _logTracer.LogInformation("Creating auto-scale resource for: {AutoscaleResourceId}", resourceId); var resourceGroup = _context.Creds.GetBaseResourceGroup(); var subscription = _context.Creds.GetSubscription(); @@ -158,7 +160,7 @@ private async Async.Task> CreateAutoScal var autoScaleResource = await autoScaleSettings.CreateOrUpdateAsync(WaitUntil.Started, Guid.NewGuid().ToString(), parameters); if (autoScaleResource != null && autoScaleResource.HasValue) { - _logTracer.Info($"Successfully created auto scale resource {autoScaleResource.Value.Id:Tag:AutoscaleResourceId} for {resourceId:Tag:ResourceId}"); + _logTracer.LogInformation("Successfully created auto scale resource {AutoscaleResourceId} for {ResourceId}", autoScaleResource.Value.Id, resourceId); return OneFuzzResult.Ok(autoScaleResource.Value); } @@ -169,14 +171,14 @@ private async Async.Task> CreateAutoScal } catch (RequestFailedException ex) when (ex.Status == 409 && ex.Message.Contains("\"code\":\"SettingAlreadyExists\"")) { var existingAutoScaleResource = GetAutoscaleSettings(resourceId); if (existingAutoScaleResource.IsOk) { - _logTracer.Info($"Successfully created auto scale resource {existingAutoScaleResource.OkV!.Data.Id:Tag:AutoscaleResourceId} for {resourceId:Tag:ResourceId}"); + _logTracer.LogInformation("Successfully created auto scale resource {AutoscaleResourceId} for {ResourceId}", existingAutoScaleResource.OkV!.Data.Id, resourceId); return OneFuzzResult.Ok(existingAutoScaleResource.OkV!); } else { return existingAutoScaleResource.ErrorV; } } catch (Exception ex) { - _logTracer.Exception(ex); + _logTracer.LogError(ex, "CreateAutoScaleResourceFor"); return OneFuzzResult.Error( ErrorCode.UNABLE_TO_CREATE, $"unable to create auto scale resource for resource: {resourceId} with profile: {profile}"); @@ -279,7 +281,7 @@ private async Async.Task> SetupAutoSca $"The resulting diagnostics settings resource was null when attempting to create for {autoscaleSettingResource.Id}" ); } catch (Exception ex) { - _logTracer.Exception(ex); + _logTracer.LogError(ex, "SetupAutoScaleDiagnostics"); return OneFuzzResult.Error( ErrorCode.UNABLE_TO_CREATE, $"unable to setup diagnostics for auto-scale resource: {autoscaleSettingResource.Id} and name: {autoscaleSettingResource.Data.Name}" @@ -288,7 +290,7 @@ private async Async.Task> SetupAutoSca } public OneFuzzResult GetAutoscaleSettings(ScalesetId vmss) { - _logTracer.Info($"Checking scaleset {vmss:Tag:ScalesetId} for existing auto scale resource"); + _logTracer.LogInformation("Checking scaleset {ScalesetId} for existing auto scale resource", vmss); try { var autoscale = _context.Creds.GetResourceGroupResource().GetAutoscaleSettings() .ToEnumerable() @@ -296,19 +298,19 @@ private async Async.Task> SetupAutoSca .FirstOrDefault(); if (autoscale != null) { - _logTracer.Info($"Found autoscale settings for {vmss:Tag:ScalesetId}"); + _logTracer.LogInformation("Found autoscale settings for {ScalesetId}", vmss); return OneFuzzResult.Ok(autoscale); } } catch (Exception ex) { - _logTracer.Exception(ex); + _logTracer.LogError(ex, "GetAutoscaleSettings"); return OneFuzzResult.Error(ErrorCode.INVALID_CONFIGURATION, $"Failed to check if scaleset {vmss} already has an autoscale resource"); } return OneFuzzResult.Ok(null); } public async Task UpdateAutoscale(AutoscaleSettingData autoscale) { - _logTracer.Info($"Updating auto scale resource: {autoscale.Name:Tag:AutoscaleSettingName}"); + _logTracer.LogInformation("Updating auto scale resource: {AutoscaleSettingName}", autoscale.Name); try { var newResource = await _context.Creds.GetResourceGroupResource().GetAutoscaleSettings().CreateOrUpdateAsync( @@ -317,9 +319,9 @@ public async Task UpdateAutoscale(AutoscaleSettingData autosc autoscale ); - _logTracer.Info($"Successfully updated auto scale resource: {autoscale.Name:Tag:AutoscaleSettingName}"); + _logTracer.LogInformation("Successfully updated auto scale resource: {AutoscaleSettingName}", autoscale.Name); } catch (RequestFailedException ex) { - _logTracer.Exception(ex); + _logTracer.LogError(ex, "UpdateAutoscale"); return OneFuzzResultVoid.Error( ErrorCode.UNABLE_TO_UPDATE, $"unable to update auto scale resource with name: {autoscale.Name} and profile: {JsonSerializer.Serialize(autoscale)}" @@ -376,7 +378,9 @@ public async Async.Task Update( var r = await Replace(entry); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"Failed to replace auto-scale record {scalesetId:Tag:ScalesetId} {minAmount:Tag:MinAmount} {maxAmount:Tag:MaxAmount} {defaultAmount:Tag:DefaultAmount} {scaleOutAmount:Tag:ScaleoutAmount} {scaleOutCooldown:Tag:ScaleoutCooldown} {scaleInAmount:Tag:ScaleinAmount} {scaleInCooldown:Tag:ScaleinCooldown}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("Failed to replace auto-scale record {ScalesetId} {MinAmount} {MaxAmount} {DefaultAmount} {ScaleoutAmount} {ScaleoutCooldown} {ScaleinAmount} {ScaleinCooldown}", + scalesetId, minAmount, maxAmount, defaultAmount, scaleOutAmount, scaleOutCooldown, scaleInAmount, scaleInCooldown); } return entry; } diff --git a/src/ApiService/ApiService/onefuzzlib/Config.cs b/src/ApiService/ApiService/onefuzzlib/Config.cs index 14139fbed3..aa56a2a1a3 100644 --- a/src/ApiService/ApiService/onefuzzlib/Config.cs +++ b/src/ApiService/ApiService/onefuzzlib/Config.cs @@ -1,7 +1,7 @@ using System.IO; using System.Threading.Tasks; using Azure.Storage.Sas; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; @@ -17,10 +17,10 @@ public class Config : IConfig { private readonly IOnefuzzContext _context; private readonly IContainers _containers; private readonly IServiceConfig _serviceConfig; - private readonly ILogTracer _logTracer; + private readonly ILogger _logTracer; private readonly IQueue _queue; - public Config(ILogTracer logTracer, IOnefuzzContext context) { + public Config(ILogger logTracer, IOnefuzzContext context) { _context = context; _logTracer = logTracer; _containers = _context.Containers; @@ -56,7 +56,7 @@ private static BlobContainerSasPermissions ConvertPermissions(ContainerPermissio } if (job.Config.Logs == null) { - _logTracer.Warning($"Missing log container {job.JobId:Tag:JobId} - {task.TaskId:Tag:TaskId}"); + _logTracer.LogWarning("Missing log container {JobId} - {TaskId}", job.JobId, task.TaskId); return null; } @@ -314,7 +314,7 @@ public async Async.Task> CheckConfig(TaskConfig conf if (definition.Features.Contains(TaskFeature.SupervisorExe) && config.Task.SupervisorExe == null) { var err = "missing supervisor_exe"; - _logTracer.Error($"{err}"); + _logTracer.LogError("{err}", err); return ResultVoid.Error(new TaskConfigError(err)); } @@ -331,7 +331,7 @@ public async Async.Task> CheckConfig(TaskConfig conf } if (!CheckVal(definition.Vm.Compare, definition.Vm.Value, config.Pool!.Count)) { - _logTracer.Error($"invalid vm count: expected {definition.Vm.Compare:Tag:Comparison} {definition.Vm.Value:Tag:Expected} {config.Pool.Count:Tag:Actual}"); + _logTracer.LogError("invalid vm count: expected {Comparison} {Expected} {Actual}", definition.Vm.Compare, definition.Vm.Value, config.Pool.Count); return ResultVoid.Error(new TaskConfigError($"invalid vm count: expected {definition.Vm.Compare} {definition.Vm.Value}, actual {config.Pool.Count}")); } @@ -358,7 +358,7 @@ public async Async.Task> CheckConfig(TaskConfig conf if (config.Task.GeneratorExe.StartsWith(toolPath)) { var generator = config.Task.GeneratorExe.Replace(toolPath, ""); if (!await _containers.BlobExists(container.Name, generator, StorageType.Corpus)) { - _logTracer.Error($"{config.Task.GeneratorExe:Tag:GeneratorExe} does not exist in the tools `{container.Name:Tag:Container}`"); + _logTracer.LogError("{GeneratorExe} does not exist in the tools `{Container}`", config.Task.GeneratorExe, container.Name); return ResultVoid.Error(new TaskConfigError($"generator_exe `{config.Task.GeneratorExe}` does not exist in the tools container `{container.Name}`")); } } @@ -368,7 +368,7 @@ public async Async.Task> CheckConfig(TaskConfig conf if (definition.Features.Contains(TaskFeature.StatsFile)) { if (config.Task.StatsFile != null && config.Task.StatsFormat == null) { var err2 = "using a stats_file requires a stats_format"; - _logTracer.Error($"{err2}"); + _logTracer.LogError("{err2}", err2); return ResultVoid.Error(new TaskConfigError(err2)); } } @@ -403,7 +403,7 @@ private async Task> CheckTargetExe(TaskConfig config var container = config.Containers!.FirstOrDefault(x => x.Type == ContainerType.Setup); if (container != null) { if (!await _containers.BlobExists(container.Name, config.Task.TargetExe, StorageType.Corpus)) { - _logTracer.Warning($"target_exe `{config.Task.TargetExe:Tag:TargetExe}` does not exist in the setup container `{container.Name:Tag:Container}`"); + _logTracer.LogWarning("target_exe `{TargetExe}` does not exist in the setup container `{Container}`", config.Task.TargetExe, container.Name); } } diff --git a/src/ApiService/ApiService/onefuzzlib/ConfigOperations.cs b/src/ApiService/ApiService/onefuzzlib/ConfigOperations.cs index 6f8e6eb54a..99e2690405 100644 --- a/src/ApiService/ApiService/onefuzzlib/ConfigOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/ConfigOperations.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using ApiService.OneFuzzLib.Orm; using Microsoft.Extensions.Caching.Memory; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; @@ -13,10 +13,10 @@ public interface IConfigOperations : IOrm { } public class ConfigOperations : Orm, IConfigOperations { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IMemoryCache _cache; - public ConfigOperations(ILogTracer log, IOnefuzzContext context, IMemoryCache cache) + public ConfigOperations(ILogger log, IOnefuzzContext context, IMemoryCache cache) : base(log, context) { _log = log; _cache = cache; @@ -36,17 +36,20 @@ public async Async.Task Save(InstanceConfig config, bool isNew = false, bool req if (isNew) { r = await Insert(newConfig); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"Failed to save new instance config record"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("Failed to save new instance config record"); } } else if (requireEtag && config.ETag.HasValue) { r = await Update(newConfig); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"Failed to update instance config record"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError("Failed to update instance config record"); } } else { r = await Replace(newConfig); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"Failed to replace instance config record"); + _log.AddHttpStatus(r.ErrorV); + _log.LogError($"Failed to replace instance config record"); } } diff --git a/src/ApiService/ApiService/onefuzzlib/Containers.cs b/src/ApiService/ApiService/onefuzzlib/Containers.cs index d00b851ac2..2d160af648 100644 --- a/src/ApiService/ApiService/onefuzzlib/Containers.cs +++ b/src/ApiService/ApiService/onefuzzlib/Containers.cs @@ -7,7 +7,7 @@ using Azure.Storage.Blobs.Models; using Azure.Storage.Blobs.Specialized; using Azure.Storage.Sas; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; @@ -38,13 +38,13 @@ public interface IContainers { } public class Containers : IContainers { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IStorage _storage; private readonly IServiceConfig _config; static readonly TimeSpan CONTAINER_SAS_DEFAULT_DURATION = TimeSpan.FromDays(30); - public Containers(ILogTracer log, IStorage storage, IServiceConfig config) { + public Containers(ILogger log, IStorage storage, IServiceConfig config) { _log = log; _storage = storage; _config = config; @@ -110,12 +110,12 @@ private static readonly BlobContainerSasPermissions _containerCreatePermissions try { var r = await cc.CreateAsync(metadata: metadata); if (r.GetRawResponse().IsError) { - _log.Error($"failed to create blob {containerName:Tag:ContainerName} due to {r.GetRawResponse().ReasonPhrase:Tag:Error}"); + _log.LogError("failed to create blob {ContainerName} due to {Error}", containerName, r.GetRawResponse().ReasonPhrase); } } catch (RequestFailedException ex) when (ex.ErrorCode == "ContainerAlreadyExists") { // note: resource exists error happens during creation if the container // is being deleted - _log.Exception(ex, $"unable to create container. {account:Tag:Account} {container:Tag:Container} {metadata:Tag:Metadata}"); + _log.LogError(ex, "unable to create container. {Account} {Container} {Metadata}", account, container, metadata); return null; } diff --git a/src/ApiService/ApiService/onefuzzlib/DiskOperations.cs b/src/ApiService/ApiService/onefuzzlib/DiskOperations.cs index 35edcb94c4..bbc68a797c 100644 --- a/src/ApiService/ApiService/onefuzzlib/DiskOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/DiskOperations.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using Azure; using Azure.ResourceManager.Compute; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; public interface IDiskOperations { @@ -11,32 +11,32 @@ public interface IDiskOperations { } public class DiskOperations : IDiskOperations { - private ILogTracer _logTracer; + private ILogger _logTracer; private ICreds _creds; - public DiskOperations(ILogTracer log, ICreds creds) { + public DiskOperations(ILogger log, ICreds creds) { _logTracer = log; _creds = creds; } public async Task DeleteDisk(string resourceGroup, string name) { try { - _logTracer.Info($"deleting disks {resourceGroup:Tag:ResourceGroup} - {name:Tag:Name}"); + _logTracer.LogInformation("deleting disks {ResourceGroup} - {Name}", resourceGroup, name); var disk = await _creds.GetResourceGroupResource().GetDiskAsync(name); if (disk != null) { _ = await disk.Value.DeleteAsync(WaitUntil.Started); return true; } } catch (Exception e) { - _logTracer.Error($"unable to delete disk: {name:Tag:Name} {e.Message:Tag:Error}"); - _logTracer.Exception(e); + _logTracer.LogError("unable to delete disk: {Name} {Error}", name, e.Message); + _logTracer.LogError(e, "DeleteDisk"); } return false; } public DiskCollection ListDisks(string resourceGroup) { - _logTracer.Info($"listing disks {resourceGroup:Tag:ResourceGroup}"); + _logTracer.LogInformation("listing disks {ResourceGroup}", resourceGroup); return _creds.GetResourceGroupResource().GetDisks(); } } diff --git a/src/ApiService/ApiService/onefuzzlib/EndpointAuthorization.cs b/src/ApiService/ApiService/onefuzzlib/EndpointAuthorization.cs index cc88d1d924..50d25badc2 100644 --- a/src/ApiService/ApiService/onefuzzlib/EndpointAuthorization.cs +++ b/src/ApiService/ApiService/onefuzzlib/EndpointAuthorization.cs @@ -1,7 +1,7 @@ using System.Net.Http; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.Graph; - namespace Microsoft.OneFuzz.Service; public record UserAuthInfo(UserInfo UserInfo, List Roles); @@ -15,16 +15,17 @@ public interface IEndpointAuthorization { public class EndpointAuthorization : IEndpointAuthorization { private readonly IOnefuzzContext _context; - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly GraphServiceClient _graphClient; private static readonly IReadOnlySet _agentRoles = new HashSet() { "UnmanagedNode", "ManagedNode" }; - public EndpointAuthorization(IOnefuzzContext context, ILogTracer log, GraphServiceClient graphClient) { + public EndpointAuthorization(IOnefuzzContext context, ILogger log, GraphServiceClient graphClient) { _context = context; _log = log; _graphClient = graphClient; } + _log.Error($"reject token. reason:{reason} url:{req.Url:Tag:Url} token:{token:Tag:Token} body:{body:Tag:Body}"); public async Async.Task CheckRequireAdmins(UserAuthInfo authInfo) { var config = await _context.ConfigOperations.Fetch(); if (config is null) { @@ -86,7 +87,7 @@ public async Async.Task CheckAccess(HttpRequestData req) { var membershipChecker = CreateGroupMembershipChecker(instanceConfig); var allowed = await membershipChecker.IsMember(rule.AllowedGroupsIds, memberId); if (!allowed) { - _log.Error($"unauthorized access: {memberId:Tag:MemberId} is not authorized to access {path:Tag:Path}"); + _log.LogError("unauthorized access: {MemberId} is not authorized to access {Path}", memberId, path); return Error.Create(ErrorCode.UNAUTHORIZED, "not approved to use this endpoint"); } else { return OneFuzzResultVoid.Ok; diff --git a/src/ApiService/ApiService/onefuzzlib/Events.cs b/src/ApiService/ApiService/onefuzzlib/Events.cs index c374117735..2a8039094d 100644 --- a/src/ApiService/ApiService/onefuzzlib/Events.cs +++ b/src/ApiService/ApiService/onefuzzlib/Events.cs @@ -2,8 +2,8 @@ using System.Text.Json.Serialization; using System.Threading.Tasks; using Azure.Storage.Sas; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service { @@ -33,13 +33,13 @@ public interface IEvents { public class Events : IEvents { private readonly IQueue _queue; private readonly IWebhookOperations _webhook; - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IContainers _containers; private readonly ICreds _creds; private readonly JsonSerializerOptions _options; private readonly JsonSerializerOptions _deserializingFromBlobOptions; - public Events(ILogTracer log, IOnefuzzContext context) { + public Events(ILogger log, IOnefuzzContext context) { _queue = context.Queue; _webhook = context.WebhookOperations; _log = log; @@ -63,7 +63,8 @@ public virtual async Async.Task QueueSignalrEvent(DownloadableEventMessage messa var queueResult = await _queue.QueueObject("signalr-events", ev, StorageType.Config, serializerOptions: _options); if (!queueResult) { - _log.WithTags(tags).Error($"Fsailed to queue signalr event"); + _log.AddTags(tags); + _log.LogError("Failed to queue signalr event"); } } @@ -90,7 +91,7 @@ public async Async.Task SendEvent(BaseEvent anEvent) { public virtual void LogEvent(BaseEvent anEvent) { var serializedEvent = JsonSerializer.Serialize(anEvent, anEvent.GetType(), _options); - _log.Info($"sending event: {anEvent.GetEventType():Tag:EventType} - {serializedEvent}"); + _log.LogInformation("sending event: {EventType} - {serializedEvent}", anEvent.GetEventType(), serializedEvent); } public async Async.Task> GetEvent(Guid eventId) { diff --git a/src/ApiService/ApiService/onefuzzlib/IpOperations.cs b/src/ApiService/ApiService/onefuzzlib/IpOperations.cs index e4e00febe1..7fa4d83e56 100644 --- a/src/ApiService/ApiService/onefuzzlib/IpOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/IpOperations.cs @@ -6,7 +6,7 @@ using Azure.ResourceManager.Network; using Azure.ResourceManager.Network.Models; using Faithlife.Utility; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; public interface IIpOperations { @@ -31,18 +31,18 @@ public interface IIpOperations { public class IpOperations : IIpOperations { - private readonly ILogTracer _logTracer; + private readonly ILogger _logTracer; private readonly IOnefuzzContext _context; private readonly NetworkInterfaceQuery _networkInterfaceQuery; - public IpOperations(ILogTracer log, IOnefuzzContext context) { + public IpOperations(ILogger log, IOnefuzzContext context) { _logTracer = log; _context = context; _networkInterfaceQuery = new NetworkInterfaceQuery(context, log); } public async Async.Task GetPublicNic(string resourceGroup, string name) { - _logTracer.Info($"getting nic: {resourceGroup:Tag:ResourceGroup} - {name:Tag:Name}"); + _logTracer.LogInformation("getting nic: {ResourceGroup} - {Name}", resourceGroup, name); try { return await _context.Creds.GetResourceGroupResource().GetNetworkInterfaceAsync(name); } catch (RequestFailedException) { @@ -51,7 +51,7 @@ public IpOperations(ILogTracer log, IOnefuzzContext context) { } public async Async.Task GetIp(string resourceGroup, string name) { - _logTracer.Info($"getting ip {resourceGroup:Tag:ResourceGroup} - {name:Tag:Name}"); + _logTracer.LogInformation("getting ip {ResourceGroup} - {Name}", resourceGroup, name); try { return await _context.Creds.GetResourceGroupResource().GetPublicIPAddressAsync(name); } catch (RequestFailedException) { @@ -60,35 +60,35 @@ public IpOperations(ILogTracer log, IOnefuzzContext context) { } public async System.Threading.Tasks.Task DeleteNic(string resourceGroup, string name) { - _logTracer.Info($"deleting nic {resourceGroup:Tag:ResourceGroup} - {name:Tag:Name}"); + _logTracer.LogInformation("deleting nic {ResourceGroup} - {Name}", resourceGroup, name); var networkInterface = await _context.Creds.GetResourceGroupResource().GetNetworkInterfaceAsync(name); try { var r = await networkInterface.Value.DeleteAsync(WaitUntil.Started); if (r.GetRawResponse().IsError) { - _logTracer.Error($"failed to start deleting nic {name:Tag:Name} due to {r.GetRawResponse().ReasonPhrase:Tag:Error}"); + _logTracer.LogError("failed to start deleting nic {Name} due to {Error}", name, r.GetRawResponse().ReasonPhrase); } } catch (RequestFailedException ex) { - _logTracer.Exception(ex); + _logTracer.LogError(ex, "DeleteNic"); if (ex.ErrorCode != "NicReservedForAnotherVm") { throw; } - _logTracer.Warning($"unable to delete nic {resourceGroup:Tag:ResourceGroup} - {name:Tag:Name} {ex.Message:Tag:Error}"); + _logTracer.LogWarning("unable to delete nic {ResourceGroup} - {Name} {Error}", resourceGroup, name, ex.Message); } } public async System.Threading.Tasks.Task DeleteIp(string resourceGroup, string name) { - _logTracer.Info($"deleting ip {resourceGroup:Tag:ResourceGroup} - {name:Tag:Name}"); + _logTracer.LogInformation("deleting ip {ResourceGroup} - {Name}", resourceGroup, name); var publicIpAddressAsync = await _context.Creds.GetResourceGroupResource().GetPublicIPAddressAsync(name); var r = await publicIpAddressAsync.Value.DeleteAsync(WaitUntil.Started); if (r.GetRawResponse().IsError) { - _logTracer.Error($"failed to start deleting ip address {resourceGroup:Tag:ResourceGroup} - {name:Tag:Name} due to {r.GetRawResponse().ReasonPhrase:Tag:Error}"); + _logTracer.LogError("failed to start deleting ip address {ResourceGroup} - {Name} due to {Error}", resourceGroup, name, r.GetRawResponse().ReasonPhrase); } } public async Task GetScalesetInstanceIp(ScalesetId scalesetId, Guid machineId) { var instance = await _context.VmssOperations.GetInstanceId(scalesetId, machineId); if (!instance.IsOk) { - _logTracer.Verbose($"failed to get vmss {scalesetId:Tag:ScalesetId} for instance id {machineId:Tag:MachineId} due to {instance.ErrorV:Tag:Error}"); + _logTracer.LogDebug("failed to get vmss {ScalesetId} for instance id {MachineId} due to {Error}", scalesetId, machineId, instance.ErrorV); return null; } @@ -102,7 +102,7 @@ public async System.Threading.Tasks.Task DeleteIp(string resourceGroup, string n public async Task GetPublicIp(ResourceIdentifier resourceId) { // TODO: Parts of this function seem redundant, but I'm mirroring // the python code exactly. We should revisit this. - _logTracer.Info($"getting ip for {resourceId:Tag:ResourceId}"); + _logTracer.LogInformation("getting ip for {ResourceId}", resourceId); try { var resource = await (_context.Creds.GetData(_context.Creds.ParseResourceId(resourceId))); var networkInterfaces = await _context.Creds.GetResourceGroupResource().GetNetworkInterfaceAsync( @@ -128,7 +128,7 @@ public async System.Threading.Tasks.Task DeleteIp(string resourceGroup, string n } public async Task CreatePublicNic(string resourceGroup, string name, Region region, Nsg? nsg) { - _logTracer.Info($"creating nic for {resourceGroup:Tag:ResourceGroup} - {name:Tag:Name} in {region:Tag:Region}"); + _logTracer.LogInformation("creating nic for {ResourceGroup} - {Name} in {Region}", resourceGroup, name, region); var network = await Network.Init(region, _context); var subnetId = await network.GetId(); @@ -136,7 +136,7 @@ public async Task CreatePublicNic(string resourceGroup, strin if (subnetId is null) { var r = await network.Create(); if (!r.IsOk) { - _logTracer.Error($"failed to create network in region {region:Tag:Region} due to {r.ErrorV:Tag:Error}"); + _logTracer.LogError("failed to create network in region {Region} due to {Error}", region, r.ErrorV); } return r; } @@ -175,7 +175,7 @@ public async Task CreatePublicNic(string resourceGroup, strin var onefuzzOwner = _context.ServiceConfiguration.OneFuzzOwner; if (!string.IsNullOrEmpty(onefuzzOwner)) { if (!networkInterface.Tags.TryAdd("OWNER", onefuzzOwner)) { - _logTracer.Warning($"Failed to add tag 'OWNER':{onefuzzOwner:Tag:Owner} to nic {resourceGroup:Tag:ResourceGroup}:{name:Tag:Name}"); + _logTracer.LogWarning("Failed to add tag 'OWNER':{Owner} to nic {ResourceGroup}:{Name}", onefuzzOwner, resourceGroup, name); } } @@ -188,7 +188,7 @@ await _context.Creds.GetResourceGroupResource().GetNetworkInterfaces().CreateOrU ); if (r.GetRawResponse().IsError) { - _logTracer.Error($"failed to createOrUpdate network interface {name:Tag:Name} due to {r.GetRawResponse().ReasonPhrase:Tag:Error}"); + _logTracer.LogError("failed to createOrUpdate network interface {Name} due to {Error}", name, r.GetRawResponse().ReasonPhrase); } } catch (RequestFailedException ex) { if (!ex.ToString().Contains("RetryableError")) { @@ -211,7 +211,7 @@ public async Async.Task CreateIp(string resourceGroup, string name, Region regio var onefuzzOwner = _context.ServiceConfiguration.OneFuzzOwner; if (!string.IsNullOrEmpty(onefuzzOwner)) { if (!ipParams.Tags.TryAdd("OWNER", onefuzzOwner)) { - _logTracer.Warning($"Failed to add tag 'OWNER':{onefuzzOwner:Tag:Owner} to ip {resourceGroup:Tag:ResourceGroup}:{name:Tag:Name}"); + _logTracer.LogWarning("Failed to add tag 'OWNER':{Owner} to ip {ResourceGroup}:{Name}", onefuzzOwner, resourceGroup, name); } } @@ -219,7 +219,7 @@ public async Async.Task CreateIp(string resourceGroup, string name, Region regio WaitUntil.Started, name, ipParams ); if (r.GetRawResponse().IsError) { - _logTracer.Error($"Failed to create or update Public Ip Address {name:Tag:Name} due to {r.GetRawResponse().ReasonPhrase:Tag:Error}"); + _logTracer.LogError("Failed to create or update Public Ip Address {Name} due to {Error}", name, r.GetRawResponse().ReasonPhrase); } return; @@ -244,9 +244,9 @@ sealed record ValueList(List value); private readonly IOnefuzzContext _context; - private readonly ILogTracer _logTracer; + private readonly ILogger _logTracer; - public NetworkInterfaceQuery(IOnefuzzContext context, ILogTracer logTracer) { + public NetworkInterfaceQuery(IOnefuzzContext context, ILogger logTracer) { _context = context; _logTracer = logTracer; } @@ -270,7 +270,7 @@ public async Task> ListInstancePrivateIps(ScalesetId scalesetId, st return nics.value.SelectMany(x => x.properties.ipConfigurations.Select(i => i.properties.privateIPAddress)).WhereNotNull().ToList(); } else { var body = await response.Content.ReadAsStringAsync(); - _logTracer.Error($"failed to get ListInstancePrivateIps due to {body}"); + _logTracer.LogError("failed to get ListInstancePrivateIps due to {body}", body); } return new List(); } diff --git a/src/ApiService/ApiService/onefuzzlib/JobOperations.cs b/src/ApiService/ApiService/onefuzzlib/JobOperations.cs index dcd473e5c8..781df97943 100644 --- a/src/ApiService/ApiService/onefuzzlib/JobOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/JobOperations.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; using ApiService.OneFuzzLib.Orm; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; public interface IJobOperations : IStatefulOrm { @@ -21,7 +21,7 @@ public interface IJobOperations : IStatefulOrm { public class JobOperations : StatefulOrm, IJobOperations { private static readonly TimeSpan JOB_NEVER_STARTED_DURATION = TimeSpan.FromDays(30); - public JobOperations(ILogTracer logTracer, IOnefuzzContext context) : base(logTracer, context) { + public JobOperations(ILogger logTracer, IOnefuzzContext context) : base(logTracer, context) { } public async Async.Task Get(Guid jobId) { @@ -32,7 +32,8 @@ public async Async.Task OnStart(Job job) { if (job.EndTime == null) { var r = await Replace(job with { EndTime = DateTimeOffset.UtcNow + TimeSpan.FromHours(job.Config.Duration) }); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to replace job {job.JobId:Tag:JobId} when calling OnStart"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to replace job {JobId} when calling OnStart", job.JobId); } } } @@ -54,7 +55,7 @@ public async Async.Task StopIfAllDone(Job job) { var tasks = _context.TaskOperations.GetByJobId(job.JobId); if (!await tasks.AnyAsync()) { - _logTracer.Warning($"StopIfAllDone could not find any tasks for job with id {job.JobId:Tag:JobId}"); + _logTracer.LogWarning("StopIfAllDone could not find any tasks for job with id {JobId}", job.JobId); } var anyNotStoppedTasks = await tasks.AnyAsync(task => task.State != TaskState.Stopped); @@ -63,7 +64,7 @@ public async Async.Task StopIfAllDone(Job job) { return; } - _logTracer.Info($"stopping job as all tasks are stopped: {job.JobId:Tag:JobId}"); + _logTracer.LogInformation("stopping job as all tasks are stopped: {JobId}", job.JobId); _ = await Stopping(job); } @@ -82,7 +83,7 @@ public async Async.Task StopNeverStartedJobs() { await foreach (var task in _context.TaskOperations.QueryAsync(Query.PartitionKey(job.JobId.ToString()))) { await _context.TaskOperations.MarkFailed(task, Error.Create(ErrorCode.TASK_FAILED, "job never not start")); } - _logTracer.Info($"stopping job that never started: {job.JobId:Tag:JobId}"); + _logTracer.LogInformation("stopping job that never started: {JobId}", job.JobId); // updated result ignored: not used after this loop _ = await _context.JobOperations.Stopping(job); @@ -90,13 +91,14 @@ public async Async.Task StopNeverStartedJobs() { } public async Async.Task Init(Job job) { - _logTracer.Info($"init job: {job.JobId:Tag:JobId}"); + _logTracer.LogInformation("init job: {JobId}", job.JobId); var enabled = job with { State = JobState.Enabled }; var result = await Replace(enabled); if (result.IsOk) { return enabled; } else { - _logTracer.WithHttpStatus(result.ErrorV).Error($"Failed to save job when init {job.JobId:Tag:JobId} : {result.ErrorV:Tag:Error}"); + _logTracer.AddHttpStatus(result.ErrorV); + _logTracer.LogError("Failed to save job when init {JobId} : {Error}", job.JobId, result.ErrorV); throw new Exception($"Failed to save job when init {job.JobId} : {result.ErrorV}"); } } @@ -124,7 +126,8 @@ public async Async.Task Stopping(Job job) { if (result.IsOk) { return job; } else { - _logTracer.WithHttpStatus(result.ErrorV).Error($"Failed to save job when stopping {job.JobId:Tag:JobId} : {result.ErrorV:Tag:Error}"); + _logTracer.AddHttpStatus(result.ErrorV); + _logTracer.LogError("Failed to save job when stopping {JobId} : {Error}", job.JobId, result.ErrorV); throw new Exception($"Failed to save job when stopping {job.JobId} : {result.ErrorV}"); } } diff --git a/src/ApiService/ApiService/onefuzzlib/Metrics.cs b/src/ApiService/ApiService/onefuzzlib/Metrics.cs index e40a9cc974..884f6ac9bd 100644 --- a/src/ApiService/ApiService/onefuzzlib/Metrics.cs +++ b/src/ApiService/ApiService/onefuzzlib/Metrics.cs @@ -1,7 +1,7 @@ using System.Text.Json; using System.Text.Json.Serialization; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service { public record CustomMetric( @@ -18,11 +18,11 @@ public interface IMetrics { } public class Metrics : IMetrics { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IOnefuzzContext _context; private readonly JsonSerializerOptions _options; - public Metrics(ILogTracer log, IOnefuzzContext context) { + public Metrics(ILogger log, IOnefuzzContext context) { _context = context; _log = log; _options = new JsonSerializerOptions(EntityConverter.GetJsonSerializerOptions()) { @@ -41,14 +41,14 @@ public void SendMetric(int metricValue, BaseEvent customDimensions) { var dimensionNode = JsonSerializer.SerializeToNode(customDimensions, customDimensions.GetType(), _options); _ = dimensionNode ?? throw new JsonException("Was not able to properly serialize the custom dimensions."); var dimensionDict = dimensionNode.AsObject().ToDictionary(kvp => kvp.Key.ToString(), kvp => kvp.Value is not null ? kvp.Value.ToString() : ""); - - _log.Metric($"{metricTypeSnakeCase}", metricValue, dimensionDict); + _log.AddTags(dimensionDict); + _log.LogMetric($"{metricTypeSnakeCase}", metricValue); LogMetric(customDimensions); } public void LogMetric(BaseEvent metric) { var serializedMetric = JsonSerializer.Serialize(metric, metric.GetType(), _options); - _log.Info($"sending metric: {metric.GetEventType():Tag:MetricType} - {serializedMetric}"); + _log.LogInformation("sending metric: {MetricType} - {SerializedMetric}", metric.GetEventType(), serializedMetric); } } } diff --git a/src/ApiService/ApiService/onefuzzlib/NodeMessageOperations.cs b/src/ApiService/ApiService/onefuzzlib/NodeMessageOperations.cs index 9d31d41cbf..9d40299741 100644 --- a/src/ApiService/ApiService/onefuzzlib/NodeMessageOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/NodeMessageOperations.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using ApiService.OneFuzzLib.Orm; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service; //# this isn't anticipated to be needed by the client, hence it not @@ -25,19 +25,19 @@ public interface INodeMessageOperations : IOrm { public class NodeMessageOperations : Orm, INodeMessageOperations { - public NodeMessageOperations(ILogTracer log, IOnefuzzContext context) + public NodeMessageOperations(ILogger log, IOnefuzzContext context) : base(log, context) { } public IAsyncEnumerable GetMessages(Guid machineId) => QueryAsync(Query.PartitionKey(machineId.ToString())); public async Async.Task ClearMessages(Guid machineId) { - _logTracer.Info($"clearing messages for node {machineId:Tag:MachineId}"); + _logTracer.LogInformation("clearing messages for node {MachineId}", machineId); var result = await DeleteAll(new (string?, string?)[] { (machineId.ToString(), null) }); if (result.FailureCount > 0) { - _logTracer.Error($"failed to delete {result.FailureCount:Tag:FailedDeleteMessageCount} messages for node {machineId:Tag:MachineId}"); + _logTracer.LogError("failed to delete {FailedDeleteMessageCount} messages for node {MachineId}", result.FailureCount, machineId); } } @@ -45,7 +45,8 @@ public async Async.Task SendMessage(Guid machineId, NodeCommand message, string? messageId ??= EntityBase.NewSortedKey; var r = await Insert(new NodeMessage(machineId, messageId, message)); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to insert message with id: {messageId:Tag:MessageId} for machine id: {machineId:Tag:MachineId} message: {message:Tag:Message}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to insert message with id: {MessageId} for machine id: {MachineId} message: {Message}", messageId, machineId, message); } } diff --git a/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs b/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs index 9626ec3478..dbf4cf031c 100644 --- a/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using ApiService.OneFuzzLib.Orm; using Azure; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; public record CanProcessNewWorkResponse(bool IsAllowed, string? Reason) { @@ -83,7 +83,7 @@ IAsyncEnumerable SearchStates(Guid? poolId = default, public class NodeOperations : StatefulOrm, INodeOperations { - public NodeOperations(ILogTracer log, IOnefuzzContext context) + public NodeOperations(ILogger log, IOnefuzzContext context) : base(log, context) { } @@ -94,7 +94,8 @@ await TryGetNodeInfo(node) is NodeInfo nodeInfo) { var metricDimensions = new Dictionary { {"MachineId", node.MachineId.ToString()} }; - _logTracer.Info($"Setting scale-in protection on node {node.MachineId:Tag:MachineId}"); + _logTracer.AddTags(metricDimensions); + _logTracer.LogInformation("Setting scale-in protection on node {MachineId}", node.MachineId); var instanceId = node.InstanceId; if (instanceId is null) { @@ -112,12 +113,12 @@ await TryGetNodeInfo(node) is NodeInfo nodeInfo) { var r = await _context.VmssOperations.UpdateScaleInProtection(nodeInfo.Scaleset, instanceId, protectFromScaleIn: true); if (!r.IsOk) { - _logTracer.Error(r.ErrorV); - _logTracer.Metric($"FailedAcquiringScaleInProtection", 1, metricDimensions); + _logTracer.LogOneFuzzError(r.ErrorV); + _logTracer.LogMetric("FailedAcquiringScaleInProtection", 1); return r.ErrorV; } - _logTracer.Metric($"AcquiredScaleInProtection", 1, metricDimensions); + _logTracer.LogMetric("AcquiredScaleInProtection", 1); return OneFuzzResult.Ok(node); } @@ -132,7 +133,8 @@ await TryGetNodeInfo(node) is NodeInfo nodeInfo) { var metricDimensions = new Dictionary { {"MachineId", node.MachineId.ToString()} }; - _logTracer.Info($"Removing scale-in protection on node {node.MachineId:Tag:MachineId}"); + _logTracer.AddTags(metricDimensions); + _logTracer.LogInformation("Removing scale-in protection on node {MachineId}", node.MachineId); var instanceId = node.InstanceId; if (instanceId is null) { @@ -146,12 +148,12 @@ await TryGetNodeInfo(node) is NodeInfo nodeInfo) { var r = await _context.VmssOperations.UpdateScaleInProtection(nodeInfo.Scaleset, instanceId, protectFromScaleIn: false); if (!r.IsOk) { - _logTracer.Error(r.ErrorV); - _logTracer.Metric($"FailedReleasingScaleInProtection", 1, metricDimensions); + _logTracer.LogOneFuzzError(r.ErrorV); + _logTracer.LogMetric("FailedReleasingScaleInProtection", 1); return r; } - _logTracer.Metric($"ReleasedScaleInProection", 1, metricDimensions); + _logTracer.LogMetric("ReleasedScaleInProection", 1); return r; } @@ -255,7 +257,7 @@ public async Async.Task ReimageLongLivedNodes(ScalesetId scaleSetId) { await foreach (var node in QueryAsync(Query.And(Query.CreateQueryFilter($"scaleset_id eq {scaleSetId}"), timeFilter))) { if (node.DebugKeepNode) { - _logTracer.Info($"removing debug_keep_node for expired node. scaleset_id:{node.ScalesetId} machine_id:{node.MachineId}"); + _logTracer.LogInformation("removing debug_keep_node for expired node. scaleset_id:{scaleSetId} machine_id:{machineId}", node.ScalesetId, node.MachineId); } _ = await ToReimage(node with { DebugKeepNode = false }); } @@ -271,7 +273,7 @@ public async Async.Task MarkOutdatedNodes() { var outdated = SearchOutdated(excludeUpdateScheduled: true); await foreach (var node in outdated) { - _logTracer.Info($"node is outdated: {node.MachineId:Tag:MachineId} - {node.Version:Tag:NodeVersion}"); + _logTracer.LogInformation("node is outdated: {MachineId} - {NodeVersion}", node.MachineId, node.Version); if (node.Version == "1.0.0") { _ = await ToReimage(node, done: true); @@ -352,7 +354,7 @@ public async Async.Task CleanupBusyNodesWithoutWork() { public async Async.Task ToReimage(Node node, bool done = false) { if (!node.Managed) { - _logTracer.Info($"skip reimage for unmanaged node: {node.MachineId:Tag:MachineId}"); + _logTracer.LogInformation("skip reimage for unmanaged node: {MachineId}", node.MachineId); return node; } @@ -365,7 +367,7 @@ public async Async.Task ToReimage(Node node, bool done = false) { var reimageRequested = node.ReimageRequested; if (!node.ReimageRequested && !node.DeleteRequested) { - _logTracer.Info($"setting reimage_requested: {node.MachineId:Tag:MachineId} {node.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("setting reimage_requested: {MachineId} {ScalesetId}", node.MachineId, node.ScalesetId); reimageRequested = true; } @@ -375,7 +377,8 @@ public async Async.Task ToReimage(Node node, bool done = false) { var r = await Replace(updatedNode); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"Failed to save Node record for node {updatedNode.MachineId:Tag:MachineId} {node.ScalesetId:Tag:ScalesetId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("Failed to save Node record for node {MachineId} {ScalesetId}", updatedNode.MachineId, node.ScalesetId); } return updatedNode; @@ -418,11 +421,11 @@ public IAsyncEnumerable GetDeadNodes(ScalesetId scaleSetId, TimeSpan expir var existingNode = await QueryAsync(Query.SingleEntity(poolName.ToString(), machineId.ToString())).FirstOrDefaultAsync(); if (existingNode is not null) { if (existingNode.State != node.State || existingNode.ReimageRequested != node.ReimageRequested || existingNode.Version != node.Version || existingNode.DeleteRequested != node.DeleteRequested) { - _logTracer.Error($"Not replacing {existingNode:Tag:ExistingNode} with a new-and-different {node:Tag:Node}"); + _logTracer.LogError("Not replacing {ExistingNode} with a new-and-different {Node}", existingNode, node); } return null; } else { - _logTracer.Critical($"Failed to get node when node insertion returned EntityAlreadyExists {poolName.ToString():Tag:PoolName} {machineId:Tag:MachineId}"); + _logTracer.LogCritical("Failed to get node when node insertion returned EntityAlreadyExists {PoolName} {MachineId}", poolName.ToString(), machineId); r = await Replace(node); } } @@ -431,7 +434,8 @@ public IAsyncEnumerable GetDeadNodes(ScalesetId scaleSetId, TimeSpan expir } if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to save NodeRecord for node {node.MachineId:Tag:MachineId} isNew: {isNew:Tag:IsNew}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to save NodeRecord for node {MachineId} isNew: {IsNew}", node.MachineId, isNew); return null; } @@ -456,7 +460,7 @@ public async Async.Task Stop(Node node, bool done = false) { /// /// public async Async.Task SetHalt(Node node) { - _logTracer.Info($"setting halt: {node.MachineId:Tag:MachineId}"); + _logTracer.LogInformation("setting halt: {MachineId}", node.MachineId); node = node with { DeleteRequested = true }; node = await Stop(node, true); await SendStopIfFree(node); @@ -465,11 +469,12 @@ public async Async.Task SetHalt(Node node) { public async Async.Task SetShutdown(Node node) { //don't give out more work to the node, but let it finish existing work - _logTracer.Info($"setting delete_requested: {node.MachineId:Tag:MachineId}"); + _logTracer.LogInformation("setting delete_requested: {MachineId}", node.MachineId); node = node with { DeleteRequested = true }; var r = await Replace(node); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to update node with delete requested. {node.MachineId:Tag:MachineId} {node.PoolName:Tag:PoolName} {node.PoolId:Tag:PoolId} {node.ScalesetId:Tag:ScalesetId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to update node with delete requested. {MachineId} {PoolName} {PoolId} {ScalesetId}", node.MachineId, node.PoolName, node.PoolId, node.ScalesetId); } await SendStopIfFree(node); @@ -487,7 +492,8 @@ public async Async.Task SendStopIfFree(Node node) { public async Async.Task SendMessage(Node node, NodeCommand message) { var r = await _context.NodeMessageOperations.Replace(new NodeMessage(node.MachineId, message)); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to replace NodeMessge record for {node.MachineId:Tag:MachineId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to replace NodeMessge record for {MachineId}", node.MachineId); } } @@ -529,7 +535,12 @@ public async Task CouldShrinkScaleset(Node node) { public async Async.Task SetState(Node node, NodeState state) { if (node.State != state) { - _logTracer.Event($"SetState Node {node.MachineId:Tag:MachineId} {node.State:Tag:From} - {state:Tag:To}"); + _logTracer.AddTags(new Dictionary() { + { "MachineId", node.MachineId.ToString() }, + { "From", node.State.ToString() }, + { "To", state.ToString() } } + ); + _logTracer.LogEvent("SetState Node"); node = node with { State = state }; await _context.Events.SendEvent(new EventNodeStateUpdated( @@ -542,7 +553,7 @@ await _context.Events.SendEvent(new EventNodeStateUpdated( var r = await Update(node); if (!r.IsOk) { - _logTracer.Error($"Failed to update node for: {node.MachineId:Tag:MachineId} {state:Tag:State} due to {r.ErrorV:Tag:Error}"); + _logTracer.LogError("Failed to update node for: {MachineId} {State} due to {Error}", node.MachineId, state, r.ErrorV); // TODO: this should error out } @@ -618,7 +629,8 @@ public async Async.Task MarkTasksStoppedEarly(Node node, Error? error) { if (!node.DebugKeepNode) { var r = await _context.NodeTasksOperations.Delete(entry); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to delete task operation for {entry.TaskId:Tag:TaskId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to delete task operation for {TaskId}", entry.TaskId); } } } @@ -632,7 +644,8 @@ public async Async.Task Delete(Node node, string reason) { await _context.NodeMessageOperations.ClearMessages(node.MachineId); var r = await base.Delete(node); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"Failed to delete node {node.MachineId:Tag:MachineId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("Failed to delete node {MachineId}", node.MachineId); } await _context.Events.SendEvent(new EventNodeDeleted(node.MachineId, node.ScalesetId, node.PoolName, node.State)); @@ -649,7 +662,7 @@ public async Async.Task StopTask(Guid task_id) { await _context.NodeMessageOperations.SendMessage(node.MachineId, new NodeCommand(StopTask: new StopTaskNodeCommand(task_id))); if (!await StopIfComplete(node)) { - _logTracer.Info($"nodes: stopped task on node, but not reimaging due to other tasks: {task_id:Tag:TaskId} {node.MachineId:Tag:MachineId}"); + _logTracer.LogInformation("nodes: stopped task on node, but not reimaging due to other tasks: {TaskId} {MachineId}", task_id, node.MachineId); } } @@ -680,7 +693,7 @@ private async Task StopIfComplete(Node node, bool done = false) { return false; } } - _logTracer.Info($"node: stopping busy node with all tasks complete: {node.MachineId:Tag:MachineId}"); + _logTracer.LogInformation("node: stopping busy node with all tasks complete: {MachineId}", node.MachineId); _ = await Stop(node, done: done); return true; diff --git a/src/ApiService/ApiService/onefuzzlib/NodeTasksOperations.cs b/src/ApiService/ApiService/onefuzzlib/NodeTasksOperations.cs index 5f98060b4c..52bb6b9700 100644 --- a/src/ApiService/ApiService/onefuzzlib/NodeTasksOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/NodeTasksOperations.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; using ApiService.OneFuzzLib.Orm; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; public interface INodeTasksOperations : IStatefulOrm { @@ -18,7 +18,7 @@ public interface INodeTasksOperations : IStatefulOrm { public class NodeTasksOperations : StatefulOrm, INodeTasksOperations { - public NodeTasksOperations(ILogTracer log, IOnefuzzContext context) + public NodeTasksOperations(ILogger log, IOnefuzzContext context) : base(log, context) { } @@ -53,11 +53,12 @@ public IAsyncEnumerable GetByTaskId(Guid taskId) { } public async Async.Task ClearByMachineId(Guid machineId) { - _logTracer.Info($"clearing tasks for node {machineId:Tag:MachineId}"); + _logTracer.LogInformation("clearing tasks for node {MachineId}", machineId); await foreach (var entry in GetByMachineId(machineId)) { var res = await Delete(entry); if (!res.IsOk) { - _logTracer.WithHttpStatus(res.ErrorV).Error($"failed to delete node task entry for {entry.MachineId:Tag:MachineId}"); + _logTracer.AddHttpStatus(res.ErrorV); + _logTracer.LogError("failed to delete node task entry for {MachineId}", entry.MachineId); } } } diff --git a/src/ApiService/ApiService/onefuzzlib/NotificationOperations.cs b/src/ApiService/ApiService/onefuzzlib/NotificationOperations.cs index d7f4c266b6..fc0edae74e 100644 --- a/src/ApiService/ApiService/onefuzzlib/NotificationOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/NotificationOperations.cs @@ -1,7 +1,7 @@ using System.Text.Json; using ApiService.OneFuzzLib.Orm; using Azure.Storage.Sas; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; public interface INotificationOperations : IOrm { @@ -17,7 +17,7 @@ System.Threading.Tasks.Task TriggerNotification(Container con public class NotificationOperations : Orm, INotificationOperations { - public NotificationOperations(ILogTracer log, IOnefuzzContext context) + public NotificationOperations(ILogger log, IOnefuzzContext context) : base(log, context) { } @@ -44,7 +44,7 @@ public async Async.Task NewFiles(Container container, string filename, bool isLa await foreach (var (task, containers) in GetQueueTasks()) { if (containers.Contains(container)) { - _logTracer.Info($"queuing input {container} {filename} {task.TaskId}"); + _logTracer.LogInformation("queuing input {Container} {Filename} {TaskId}", container, filename, task.TaskId); var url = await _context.Containers.GetFileSasUrl(container, filename, StorageType.Corpus, BlobSasPermissions.Read | BlobSasPermissions.Delete); await _context.Queue.SendMessage(task.TaskId.ToString(), url.ToString(), StorageType.Corpus); } @@ -118,10 +118,11 @@ public async Async.Task> Create(Container container, if (replaceExisting) { var existing = this.SearchByRowKeys(new[] { container.String }); await foreach (var existingEntry in existing) { - _logTracer.Info($"deleting existing notification: {existingEntry.NotificationId:Tag:NotificationId} - {container:Tag:Container}"); + _logTracer.LogInformation("deleting existing notification: {NotificationId} - {Container}", existingEntry.NotificationId, container); var rr = await this.Delete(existingEntry); if (!rr.IsOk) { - _logTracer.WithHttpStatus(rr.ErrorV).Error($"failed to delete existing notification {existingEntry.NotificationId:Tag:NotificationId} - {container:Tag:Container}"); + _logTracer.AddHttpStatus(rr.ErrorV); + _logTracer.LogError("failed to delete existing notification {NotificationId} - {Container}", existingEntry.NotificationId, container); } } } @@ -129,9 +130,10 @@ public async Async.Task> Create(Container container, var entry = new Notification(Guid.NewGuid(), container, configWithHiddenSecret); var r = await this.Insert(entry); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to insert notification {entry.NotificationId:Tag:NotificationId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to insert notification {NotificationId}", entry.NotificationId); } - _logTracer.Info($"created notification {entry.NotificationId:Tag:NotificationId} - {entry.Container:Tag:Container}"); + _logTracer.LogInformation("created notification {NotificationId} - {Container}", entry.NotificationId, entry.Container); return OneFuzzResult.Ok(entry); } @@ -163,7 +165,7 @@ private async Async.Task HideSecrets(NotificationTemplate return await _context.TaskOperations.GetByJobIdAndTaskId(report.CrashTestResult.NoReproReport.JobId, report.CrashTestResult.NoReproReport.TaskId); } - _logTracer.Error($"unable to find crash_report or no repro entry for report: {JsonSerializer.Serialize(report)}"); + _logTracer.LogError("unable to find crash_report or no repro entry for report: {report}", JsonSerializer.Serialize(report)); return null; } diff --git a/src/ApiService/ApiService/onefuzzlib/NsgOperations.cs b/src/ApiService/ApiService/onefuzzlib/NsgOperations.cs index 2c0164fae8..3af6046746 100644 --- a/src/ApiService/ApiService/onefuzzlib/NsgOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/NsgOperations.cs @@ -2,7 +2,7 @@ using Azure; using Azure.ResourceManager.Network; using Azure.ResourceManager.Network.Models; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service { public interface INsgOperations { Async.Task GetNsg(string name); @@ -24,12 +24,12 @@ public interface INsgOperations { public class NsgOperations : INsgOperations { - private readonly ILogTracer _logTracer; + private readonly ILogger _logTracer; private readonly IOnefuzzContext _context; - public NsgOperations(ILogTracer logTracer, IOnefuzzContext context) { + public NsgOperations(ILogger logTracer, IOnefuzzContext context) { _logTracer = logTracer; _context = context; } @@ -48,7 +48,7 @@ public async Async.Task> AssociateSubnet(string name, Virtua } if (subnet.Data.NetworkSecurityGroup != null && subnet.Data.NetworkSecurityGroup.Id == nsg.Id) { - _logTracer.Info($"Subnet {subnet.Data.Name:Tag:SubnetName} - {name:Tag:NsgName} already associated, not updating"); + _logTracer.LogInformation("Subnet {SubnetName} - {NsgName} already associated, not updating", subnet.Data.Name, name); return OneFuzzResult.Ok(true); } @@ -80,7 +80,7 @@ public async Async.Task DissociateNic(Nsg nsg, NetworkInterfa ); } - _logTracer.Info($"dissociating {nic.Data.Name:Tag:NicName} with {_context.Creds.GetBaseResourceGroup():Tag:ResourceGroup} - {nsg.Name:Tag:NsgName}"); + _logTracer.LogInformation("dissociating {NicName} with {ResourceGroup} - {NsgName}", nic.Data.Name, _context.Creds.GetBaseResourceGroup(), nsg.Name); nic.Data.NetworkSecurityGroup = null; try { _ = await _context.Creds.GetResourceGroupResource() @@ -114,10 +114,10 @@ public async Async.Task DissociateNic(Nsg nsg, NetworkInterfa return response?.Value; } catch (RequestFailedException ex) { if (ex.ErrorCode == "ResourceNotFound") { - _logTracer.Verbose($"could not find {name:Tag:NsgName}"); + _logTracer.LogDebug("could not find {NsgName}", name); return null; } else { - _logTracer.Exception(ex, $"failed to get {name:Tag:NsgName}"); + _logTracer.LogError(ex, "failed to get {NsgName}", name); throw; } } @@ -136,19 +136,19 @@ public bool OkToDelete(IReadOnlySet active_regions, Region nsg_region, s /// Returns False if failed to start deletion. /// public async Async.Task StartDeleteNsg(string name) { - _logTracer.Info($"deleting nsg: {name:Tag:NsgName}"); + _logTracer.LogInformation("deleting nsg: {NsgName}", name); try { var nsg = await _context.Creds.GetResourceGroupResource().GetNetworkSecurityGroupAsync(name); var r = await nsg.Value.DeleteAsync(WaitUntil.Started); if (r.GetRawResponse().IsError) { - _logTracer.Error($"failed to start nsg deletion for: {name:Tag:NsgName} due to {r.GetRawResponse().ReasonPhrase:Tag:Error}"); + _logTracer.LogError("failed to start nsg deletion for: {NsgName} due to {Error}", name, r.GetRawResponse().ReasonPhrase); } return true; } catch (RequestFailedException ex) { if (ex.ErrorCode == "ResourceNotFound") { return true; } else { - _logTracer.Exception(ex, $"failed to delete {name:Tag:NsgName}"); + _logTracer.LogError(ex, "failed to delete {NsgName}", name); throw; } } @@ -168,7 +168,7 @@ public async Task Create(Nsg nsg) { private async Task CreateNsg(string name, Region location) { var resourceGroup = _context.Creds.GetBaseResourceGroup(); - _logTracer.Info($"creating nsg {resourceGroup}:{location}:{name}"); + _logTracer.LogInformation("creating nsg {ResourceGroup}:{Location}:{Name}", resourceGroup, location, name); var nsgParams = new NetworkSecurityGroupData { Location = location @@ -177,7 +177,7 @@ private async Task CreateNsg(string name, Region location) { var onefuzzOwner = _context.ServiceConfiguration.OneFuzzOwner; if (!string.IsNullOrEmpty(onefuzzOwner)) { if (!nsgParams.Tags.TryAdd("OWNER", onefuzzOwner)) { - _logTracer.Warning($"Failed to add tag 'OWNER':{onefuzzOwner} to nic {resourceGroup}:{name}"); + _logTracer.LogWarning("Failed to add tag 'OWNER':{OnefuzzOwner} to nic {ResourceGroup}:{Name}", onefuzzOwner, resourceGroup, name); } } @@ -213,8 +213,8 @@ private async Task SetAllowed(string name, NetworkSecurityGro ); } - _logTracer.Info( - $"setting allowed incoming connection sources for nsg: {_context.Creds.GetBaseResourceGroup():Tag:ResourceGroup} {name:Tag:NsgName}" + _logTracer.LogInformation( + "setting allowed incoming connection sources for nsg: {ResourceGroup} {NsgName}", _context.Creds.GetBaseResourceGroup(), name ); var allSources = new List(); @@ -281,12 +281,12 @@ private async Task AssociateNic(string name, NetworkInterface } if (nic.Data.NetworkSecurityGroup != null && nic.Data.NetworkSecurityGroup.Id == nsg.Id) { - _logTracer.Info($"{nic.Data.Name:Tag:NicName} - {nsg.Data.Name:Tag:NsgName} already associated, not updating"); + _logTracer.LogInformation("{NicName} - {NsgName} already associated, not updating", nic.Data.Name, nsg.Data.Name); return OneFuzzResultVoid.Ok; } nic.Data.NetworkSecurityGroup = nsg.Data; - _logTracer.Info($"associating {nic.Data.Name:Tag:NicName} - {_context.Creds.GetBaseResourceGroup():Tag:ResourceGroup} - {nsg.Data.Name:Tag:NsgName}"); + _logTracer.LogInformation("associating {NicName} - {ResourceGroup} - {NsgName}", nic.Data.Name, _context.Creds.GetBaseResourceGroup(), nsg.Data.Name); try { _ = await _context.Creds.GetResourceGroupResource().GetNetworkInterfaces().CreateOrUpdateAsync( @@ -306,7 +306,7 @@ private async Task AssociateNic(string name, NetworkInterface } public async Task UpdateNsg(NetworkSecurityGroupData nsg) { - _logTracer.Info($"updating nsg {_context.Creds.GetBaseResourceGroup():Tag:ResourceGroup} - {nsg.Location:Tag:Location} - {nsg.Name:Tag:NsgName}"); + _logTracer.LogInformation("updating nsg {ResourceGroup} - {Location} - {NsgName}", _context.Creds.GetBaseResourceGroup(), nsg.Location, nsg.Name); try { _ = await _context.Creds.GetResourceGroupResource().GetNetworkSecurityGroups().CreateOrUpdateAsync( diff --git a/src/ApiService/ApiService/onefuzzlib/PoolOperations.cs b/src/ApiService/ApiService/onefuzzlib/PoolOperations.cs index 9a3662f3b6..1464db4c8d 100644 --- a/src/ApiService/ApiService/onefuzzlib/PoolOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/PoolOperations.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using ApiService.OneFuzzLib.Orm; namespace Microsoft.OneFuzz.Service; - +using Microsoft.Extensions.Logging; public interface IPoolOperations : IStatefulOrm { Async.Task> GetByName(PoolName poolName); Async.Task> GetById(Guid poolId); @@ -27,7 +27,7 @@ public interface IPoolOperations : IStatefulOrm { public class PoolOperations : StatefulOrm, IPoolOperations { - public PoolOperations(ILogTracer log, IOnefuzzContext context) + public PoolOperations(ILogger log, IOnefuzzContext context) : base(log, context) { } @@ -44,7 +44,8 @@ public async Async.Task Create(PoolName name, Os os, Architecture architec var r = await Insert(newPool); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"Failed to save new pool. {newPool.Name:Tag:PoolName} - {newPool.PoolId:Tag:PoolId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("Failed to save new pool. {PoolName} - {PoolId}", newPool.Name, newPool.PoolId); } await _context.Events.SendEvent(new EventPoolCreated(PoolName: newPool.Name, Os: newPool.Os, Arch: newPool.Arch, Managed: newPool.Managed)); return newPool; @@ -141,7 +142,13 @@ public async Async.Task SetState(Pool pool, PoolState state) { return pool; } - _logTracer.WithTag("PoolName", pool.Name.ToString()).Event($"SetState Pool {pool.PoolId:Tag:PoolId} {pool.State:Tag:From} - {state:Tag:To}"); + _logTracer.AddTags(new Dictionary(){ + { "PoolName", pool.Name.ToString() }, + { "PoolId", pool.PoolId.ToString()}, + { "From", pool.State.ToString()}, + { "To", state.ToString()} + }); + _logTracer.LogEvent("SetState Pool"); // scalesets should never leave the `halt` state // it is terminal if (pool.State == PoolState.Halt) { @@ -151,7 +158,8 @@ public async Async.Task SetState(Pool pool, PoolState state) { pool = pool with { State = state }; var r = await Replace(pool); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to replace pool {pool.PoolId:Tag:PoolId} when setting state"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to replace pool when setting state"); } return pool; } @@ -167,7 +175,8 @@ public async Async.Task Init(Pool pool) { new public async Async.Task Delete(Pool pool) { var r = await base.Delete(pool); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"Failed to delete pool: {pool.Name:Tag:PoolName}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("Failed to delete pool: {PoolName}", pool.Name); } var poolQueue = GetPoolQueue(pool.PoolId); await _context.Queue.DeleteQueue(poolQueue, StorageType.Corpus); @@ -183,7 +192,7 @@ public async Async.Task Shutdown(Pool pool) { var nodes = await _context.NodeOperations.SearchByPoolName(pool.Name).ToListAsync(); if (!scalesets.Any() && !nodes.Any()) { - _logTracer.Info($"pool stopped, deleting {pool.Name:Tag:PoolName}"); + _logTracer.LogInformation("pool stopped, deleting {PoolName}", pool.Name); await Delete(pool); return pool; } @@ -201,7 +210,7 @@ public async Async.Task Shutdown(Pool pool) { //if it was changed by the caller - caller should perform save operation var r = await Update(pool); if (!r.IsOk) { - _logTracer.Error($"Failed to update pool record. {pool.Name:Tag:PoolName} - {pool.PoolId:Tag:PoolId}"); + _logTracer.LogError("Failed to update pool record. {PoolName} - {PoolId}", pool.Name, pool.PoolId); } return pool; @@ -213,7 +222,7 @@ public async Async.Task Halt(Pool pool) { var nodes = await _context.NodeOperations.SearchByPoolName(pool.Name).ToListAsync(); if (!scalesets.Any() && !nodes.Any()) { - _logTracer.Info($"pool stopped, deleting: {pool.Name:Tag:PoolName}"); + _logTracer.LogInformation("pool stopped, deleting: {PoolName}", pool.Name); await Delete(pool); return pool; } diff --git a/src/ApiService/ApiService/onefuzzlib/ProxyForwardOperations.cs b/src/ApiService/ApiService/onefuzzlib/ProxyForwardOperations.cs index 2a8dd31844..66faacd228 100644 --- a/src/ApiService/ApiService/onefuzzlib/ProxyForwardOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/ProxyForwardOperations.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; using ApiService.OneFuzzLib.Orm; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; @@ -15,7 +15,7 @@ public interface IProxyForwardOperations : IOrm { public class ProxyForwardOperations : Orm, IProxyForwardOperations { private static readonly List PORT_RANGES = Enumerable.Range(28000, 32000 - 28000).ToList(); - public ProxyForwardOperations(ILogTracer log, IOnefuzzContext context) + public ProxyForwardOperations(ILogger log, IOnefuzzContext context) : base(log, context) { } @@ -77,7 +77,8 @@ public async Task> UpdateOrCreate(Region region, Sca var result = await Replace(entry); if (!result.IsOk) { - _logTracer.WithHttpStatus(result.ErrorV).Info($"port is already used {entry:Tag:Entry}"); + _logTracer.AddHttpStatus(result.ErrorV); + _logTracer.LogInformation("port is already used {Entry}", entry); } return OneFuzzResult.Ok(entry); diff --git a/src/ApiService/ApiService/onefuzzlib/ProxyOperations.cs b/src/ApiService/ApiService/onefuzzlib/ProxyOperations.cs index 8f192235ef..39bbc46b54 100644 --- a/src/ApiService/ApiService/onefuzzlib/ProxyOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/ProxyOperations.cs @@ -2,8 +2,8 @@ using ApiService.OneFuzzLib.Orm; using Azure.ResourceManager.Compute.Models; using Azure.Storage.Sas; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service; public interface IProxyOperations : IStatefulOrm { @@ -28,11 +28,13 @@ public interface IProxyOperations : IStatefulOrm { public class ProxyOperations : StatefulOrm, IProxyOperations { static readonly TimeSpan PROXY_LIFESPAN = TimeSpan.FromDays(7); - public ProxyOperations(ILogTracer log, IOnefuzzContext context) - : base(log.WithTag("Component", "scaleset-proxy"), context) { + public ProxyOperations(ILogger log, IOnefuzzContext context) + : base(log, context) { + _logTracer.AddTag("Component", "scaleset-proxy"); } + public async Task GetByProxyId(Guid proxyId) { var data = QueryAsync(filter: Query.RowKey(proxyId.ToString())); return await data.FirstOrDefaultAsync(); @@ -45,7 +47,8 @@ public async Async.Task GetOrCreate(Region region) { if (IsOutdated(proxy)) { var r1 = await Replace(proxy with { Outdated = true }); if (!r1.IsOk) { - _logTracer.WithHttpStatus(r1.ErrorV).Error($"failed to replace record to mark proxy {proxy.ProxyId:Tag:ProxyId} as outdated"); + _logTracer.AddHttpStatus(r1.ErrorV); + _logTracer.LogError("failed to replace record to mark proxy {ProxyId} as outdated", proxy.ProxyId); } continue; } @@ -58,7 +61,7 @@ public async Async.Task GetOrCreate(Region region) { } } - _logTracer.Info($"creating proxy: region:{region:Tag:Region}"); + _logTracer.LogInformation("creating proxy: region:{Region}", region); var newProxy = new Proxy( region, Guid.NewGuid(), @@ -73,7 +76,8 @@ public async Async.Task GetOrCreate(Region region) { var r = await Replace(newProxy); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to save new proxy {newProxy.ProxyId:Tag:ProxyId} in {region:Tag:Region}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to save new proxy {ProxyId} in {Region}", newProxy.ProxyId, region); } await _context.Events.SendEvent(new EventProxyCreated(region, newProxy.ProxyId)); @@ -83,7 +87,7 @@ public async Async.Task GetOrCreate(Region region) { public async Task IsUsed(Proxy proxy) { var forwards = await GetForwards(proxy); if (forwards.Count == 0) { - _logTracer.Info($"no forwards {proxy.Region:Tag:Region}"); + _logTracer.LogInformation("no forwards {Region}", proxy.Region); return false; } return true; @@ -93,12 +97,12 @@ public bool IsAlive(Proxy proxy) { var tenMinutesAgo = DateTimeOffset.UtcNow - TimeSpan.FromMinutes(10); if (proxy.Heartbeat is not null && proxy.Heartbeat.TimeStamp < tenMinutesAgo) { - _logTracer.Info($"last heartbeat is more than an 10 minutes old: {proxy.Region:Tag:Region} {proxy.Heartbeat:Tag:LastHeartbeat} {tenMinutesAgo:Tag:ComparedToMinutesAgo}"); + _logTracer.LogInformation("last heartbeat is more than an 10 minutes old: {Region} {LastHeartbeat} {ComparedToMinutesAgo}", proxy.Region, proxy.Heartbeat, tenMinutesAgo); return false; } if (proxy.Heartbeat is not null && proxy.TimeStamp is not null && proxy.TimeStamp < tenMinutesAgo) { - _logTracer.Error($"no heartbeat in the last 10 minutes: {proxy.Region:Tag:Region} {proxy.TimeStamp:Tag:Timestamp} {tenMinutesAgo:Tag:ComparedToMinutesAgo}"); + _logTracer.LogError("no heartbeat in the last 10 minutes: {Region} {Timestamp} {ComparedToMinutesAgo}", proxy.Region, proxy.TimeStamp, tenMinutesAgo); return false; } @@ -111,13 +115,13 @@ public bool IsOutdated(Proxy proxy) { } if (proxy.Version != _context.ServiceConfiguration.OneFuzzVersion) { - _logTracer.Info($"mismatch version: proxy:{proxy.Version:Tag:ProxyVersion} {_context.ServiceConfiguration.OneFuzzVersion:Tag:ServiceVersion} {proxy.State:Tag:State}"); + _logTracer.LogInformation("mismatch version: proxy:{ProxyVersion} {ServiceVersion} {State}", proxy.Version, _context.ServiceConfiguration.OneFuzzVersion, proxy.State); return true; } if (proxy.CreatedTimestamp is not null) { if (proxy.CreatedTimestamp < (DateTimeOffset.UtcNow - PROXY_LIFESPAN)) { - _logTracer.Info($"proxy older than 7 days: {proxy.CreatedTimestamp:Tag:ProxyCreated} - {proxy.State:Tag:State}"); + _logTracer.LogInformation("proxy older than 7 days: {ProxyCreated} - {State}", proxy.CreatedTimestamp, proxy.State); return true; } } @@ -148,12 +152,19 @@ public async Async.Task SetState(Proxy proxy, VmState state) { return proxy; } - _logTracer.Event($"SetState Proxy {proxy.ProxyId:Tag:ProxyId} {proxy.State:Tag:From} - {state:Tag:To}"); + _logTracer.AddTags(new Dictionary { + { "ProxyId", proxy.ProxyId.ToString() }, + { "From", proxy.State.ToString()}, + { "To", state.ToString()} + }); + + _logTracer.LogEvent("SetState Proxy"); var newProxy = proxy with { State = state }; var r = await Replace(newProxy); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"Failed to replace proxy with {newProxy.ProxyId:Tag:ProxyId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("Failed to replace proxy with {ProxyId}", newProxy.ProxyId); } await _context.Events.SendEvent(new EventProxyStateUpdated(newProxy.Region, newProxy.ProxyId, newProxy.State)); return newProxy; @@ -167,7 +178,8 @@ public async Async.Task> GetForwards(Proxy proxy) { if (entry.EndTime < DateTimeOffset.UtcNow) { var r = await _context.ProxyForwardOperations.Delete(entry); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to delete proxy forward for {proxy.ProxyId:Tag:ProxyId} in {proxy.Region:Tag:Region}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to delete proxy forward for {ProxyId} in {Region}", proxy.ProxyId, proxy.Region); } } else { forwards.Add(new Forward(entry.Port, entry.DstPort, entry.DstIp)); @@ -215,7 +227,8 @@ public async Async.Task Init(Proxy proxy) { } var r = await Replace(proxy); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"Failed to save proxy {proxy.ProxyId:Tag:ProxyId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("Failed to save proxy {ProxyId}", proxy.ProxyId); } return proxy; } @@ -231,7 +244,7 @@ private async Task SetFailed(Proxy proxy, Error error) { return proxy; } - _logTracer.Error($"vm failed: {proxy.Region:Tag:Region} -{error:Tag:Error}"); + _logTracer.LogError("vm failed: {Region} -{Error}", proxy.Region, error); await _context.Events.SendEvent(new EventProxyFailed(proxy.Region, proxy.ProxyId, error)); return await SetState(proxy with { Error = error }, VmState.Stopping); } @@ -316,9 +329,9 @@ public async Task Stopping(Proxy proxy) { var config = await _context.ConfigOperations.Fetch(); var vm = GetVm(proxy, config); if (!await _context.VmOperations.IsDeleted(vm)) { - _logTracer.Info($"stopping proxy: {proxy.Region:Tag:Region}"); + _logTracer.LogInformation("stopping proxy: {Region}", proxy.Region); if (await _context.VmOperations.Delete(vm)) { - _logTracer.Info($"deleted proxy vm for region {proxy.Region:Tag:Region}, name: {vm.Name:Tag:Name}"); + _logTracer.LogInformation("deleted proxy vm for region {Region}, name: {Name}", proxy.Region, vm.Name); } return proxy; } @@ -328,7 +341,7 @@ public async Task Stopping(Proxy proxy) { public async Task Stopped(Proxy proxy) { var stoppedVm = await SetState(proxy, VmState.Stopped); - _logTracer.Info($"removing proxy: {stoppedVm.Region:Tag:Region}"); + _logTracer.LogInformation("removing proxy: {Region}", stoppedVm.Region); await _context.Events.SendEvent(new EventProxyDeleted(stoppedVm.Region, stoppedVm.ProxyId)); await Delete(stoppedVm).IgnoreResult(); return stoppedVm; diff --git a/src/ApiService/ApiService/onefuzzlib/Queue.cs b/src/ApiService/ApiService/onefuzzlib/Queue.cs index 91434302df..5e7772a137 100644 --- a/src/ApiService/ApiService/onefuzzlib/Queue.cs +++ b/src/ApiService/ApiService/onefuzzlib/Queue.cs @@ -5,8 +5,8 @@ using Azure.Storage.Queues; using Azure.Storage.Queues.Models; using Azure.Storage.Sas; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service; public interface IQueue { Async.Task SendMessage(string name, string message, StorageType storageType, TimeSpan? visibilityTimeout = null, TimeSpan? timeToLive = null); @@ -25,11 +25,11 @@ public interface IQueue { public class Queue : IQueue { readonly IStorage _storage; - readonly ILogTracer _log; + readonly ILogger _log; static readonly TimeSpan DEFAULT_DURATION = TimeSpan.FromDays(30); - public Queue(IStorage storage, ILogTracer log) { + public Queue(IStorage storage, ILogger log) { _storage = storage; _log = log; } @@ -46,7 +46,7 @@ public async Async.Task SendMessage(string name, string message, StorageType sto try { _ = await queue.SendMessageAsync(message, visibilityTimeout: visibilityTimeout, timeToLive: timeToLive); } catch (Exception ex) { - _log.Exception(ex, $"Failed to send {message:Tag:Message}"); + _log.LogError(ex, "Failed to send {Message}", message); throw; } } @@ -63,14 +63,14 @@ public async Task QueueObject(string name, T obj, StorageType storageTy try { return await QueueObjectInternal(obj, queueClient, serializerOptions, visibilityTimeout, timeToLive); } catch (Exception ex) { - _log.Exception(ex, $"Failed to queue message in {name:Tag:QueueName}"); + _log.LogError(ex, "Failed to queue message in {QueueName}", name); if (IsMessageTooLargeException(ex) && obj is ITruncatable truncatable) { obj = truncatable.Truncate(1000); try { return await QueueObjectInternal(obj, queueClient, serializerOptions, visibilityTimeout, timeToLive); } catch (Exception ex2) { - _log.Exception(ex2, $"Failed to queue message in {name:Tag:QueueName} after truncation"); + _log.LogError(ex2, "Failed to queue message in {QueueName} after truncation", name); } } return false; @@ -81,7 +81,7 @@ private async Task QueueObjectInternal(T obj, QueueClient queueClient, var serialized = JsonSerializer.Serialize(obj, serializerOptions); var res = await queueClient.SendMessageAsync(serialized, visibilityTimeout: visibilityTimeout, timeToLive); if (res.GetRawResponse().IsError) { - _log.Error($"Failed to send {serialized:Tag:Message} in {queueClient.Name:Tag:QueueName} due to {res.GetRawResponse().ReasonPhrase:Tag:Error}"); + _log.LogError("Failed to send {Message} in {QueueName} due to {Error}", serialized, queueClient.Name, res.GetRawResponse().ReasonPhrase); return false; } else { return true; @@ -105,7 +105,7 @@ public async Async.Task CreateQueue(string name, StorageType storageType) { var resp = await client.CreateIfNotExistsAsync(); if (resp is not null && resp.IsError) { - _log.Error($"failed to create {name:Tag:QueueName} due to {resp.ReasonPhrase:Tag:Error}"); + _log.LogError("failed to create {QueueName} due to {Error}", name, resp.ReasonPhrase); } } @@ -113,7 +113,7 @@ public async Async.Task DeleteQueue(string name, StorageType storageType) { var client = await GetQueueClient(name, storageType); var resp = await client.DeleteIfExistsAsync(); if (resp.GetRawResponse() is not null && resp.GetRawResponse().IsError) { - _log.Error($"failed to delete {name:Tag:QueueName} due to {resp.GetRawResponse().ReasonPhrase:Tag:Error}"); + _log.LogError("failed to delete {QueueName} due to {Error}", name, resp.GetRawResponse().ReasonPhrase); } } @@ -121,7 +121,7 @@ public async Async.Task ClearQueue(string name, StorageType storageType) { var client = await GetQueueClient(name, storageType); var resp = await client.ClearMessagesAsync(); if (resp is not null && resp.IsError) { - _log.Error($"failed to clear the {name:Tag:QueueName} due to {resp.ReasonPhrase:Tag:Error}"); + _log.LogError("failed to clear the {QueueName} due to {Error}", name, resp.ReasonPhrase); } } @@ -132,14 +132,14 @@ public async Async.Task RemoveFirstMessage(string name, StorageType storag foreach (var msg in msgs.Value) { var resp = await client.DeleteMessageAsync(msg.MessageId, msg.PopReceipt); if (resp.IsError) { - _log.Error($"failed to delete message from the {name:Tag:QueueName} due to {resp.ReasonPhrase:Tag:Error}"); + _log.LogError("failed to delete message from the {QueueName} due to {Error}", name, resp.ReasonPhrase); return false; } else { return true; } } } catch (RequestFailedException ex) when (ex.Status == 404 || ex.ErrorCode == "QueueNotFound") { - _log.Info($"tried to remove message from queue {name:Tag:QueueName} but it doesn't exist"); + _log.LogInformation("tried to remove message from queue {QueueName} but it doesn't exist", name); return false; } @@ -156,7 +156,7 @@ public async Task> PeekQueue(string name, StorageType storageType) { return result; } else if (msgs.GetRawResponse().IsError) { - _log.Error($"failed to peek messages in {name:Tag:QueueName} due to {msgs.GetRawResponse().ReasonPhrase:Tag:Error}"); + _log.LogError("failed to peek messages in {QueueName} due to {Error}", name, msgs.GetRawResponse().ReasonPhrase); return result; } else { foreach (var msg in msgs.Value) { diff --git a/src/ApiService/ApiService/onefuzzlib/Reports.cs b/src/ApiService/ApiService/onefuzzlib/Reports.cs index 2e85d5c77d..c1c4aad3be 100644 --- a/src/ApiService/ApiService/onefuzzlib/Reports.cs +++ b/src/ApiService/ApiService/onefuzzlib/Reports.cs @@ -1,7 +1,7 @@ using System.Text.Json; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service; public interface IReports { @@ -10,9 +10,9 @@ public interface IReports { } public class Reports : IReports { - private ILogTracer _log; + private ILogger _log; private IContainers _containers; - public Reports(ILogTracer log, IContainers containers) { + public Reports(ILogger log, IContainers containers) { _log = log; _containers = containers; } @@ -30,7 +30,7 @@ public Reports(ILogTracer log, IContainers containers) { var filePath = string.Join("/", new[] { container.String, fileName }); if (!fileName.EndsWith(".json", StringComparison.Ordinal) || fileName.Contains("source-coverage", StringComparison.InvariantCultureIgnoreCase)) { if (expectReports) { - _log.Error($"get_report invalid extension or filename: {filePath:Tag:FilePath}"); + _log.LogError("get_report invalid extension or filename: {FilePath}", filePath); } return null; } @@ -38,7 +38,7 @@ public Reports(ILogTracer log, IContainers containers) { var containerClient = await _containers.FindContainer(container, StorageType.Corpus); if (containerClient == null) { if (expectReports) { - _log.Error($"get_report invalid container: {filePath:Tag:FilePath}"); + _log.LogError("get_report invalid container: {FilePath}", filePath); } return null; } @@ -49,7 +49,7 @@ public Reports(ILogTracer log, IContainers containers) { if (blob == null) { if (expectReports) { - _log.Error($"get_report invalid blob: {filePath:Tag:FilePath}"); + _log.LogError("get_report invalid blob: {FilePath}", filePath); } return null; } @@ -57,7 +57,7 @@ public Reports(ILogTracer log, IContainers containers) { var reportOrRegression = ParseReportOrRegression(blob.ToString(), reportUrl); if (reportOrRegression is UnknownReportType && expectReports) { - _log.Error($"unable to parse report ({filePath:Tag:FilePath}) as a report or regression"); + _log.LogError("unable to parse report ({FilePath}) as a report or regression", filePath); } return reportOrRegression; diff --git a/src/ApiService/ApiService/onefuzzlib/ReproOperations.cs b/src/ApiService/ApiService/onefuzzlib/ReproOperations.cs index bd03824321..ec5c66cd93 100644 --- a/src/ApiService/ApiService/onefuzzlib/ReproOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/ReproOperations.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; using ApiService.OneFuzzLib.Orm; using Azure.ResourceManager.Compute.Models; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; public interface IReproOperations : IStatefulOrm { @@ -33,7 +33,7 @@ public interface IReproOperations : IStatefulOrm { public class ReproOperations : StatefulOrm, IReproOperations { const string DEFAULT_SKU = "Standard_DS1_v2"; - public ReproOperations(ILogTracer log, IOnefuzzContext context) + public ReproOperations(ILogger log, IOnefuzzContext context) : base(log, context) { } @@ -86,15 +86,16 @@ public async Async.Task Stopping(Repro repro) { var vm = await GetVm(repro, config); var vmOperations = _context.VmOperations; if (!await vmOperations.IsDeleted(vm)) { - _logTracer.Info($"vm stopping: {repro.VmId:Tag:VmId} {vm.Name:Tag:VmName}"); + _logTracer.LogInformation("vm stopping: {VmId} {VmName}", repro.VmId, vm.Name); var rr = await vmOperations.Delete(vm); if (rr) { - _logTracer.Info($"repro vm fully deleted {repro.VmId:Tag:VmId} {vm.Name:Tag:VmName}"); + _logTracer.LogInformation("repro vm fully deleted {VmId} {VmName}", repro.VmId, vm.Name); } repro = repro with { State = VmState.Stopping }; var r = await Replace(repro); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to replace repro {repro.VmId:Tag:VmId} {vm.Name:Tag:VmName} marked Stopping"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to replace repro {VmId} {VmName} marked Stopping", repro.VmId, vm.Name); } return repro; } else { @@ -103,12 +104,13 @@ public async Async.Task Stopping(Repro repro) { } public async Async.Task Stopped(Repro repro) { - _logTracer.Info($"vm stopped: {repro.VmId:Tag:VmId}"); + _logTracer.LogInformation("vm stopped: {VmId}", repro.VmId); // BUG?: why are we updating repro and then deleting it and returning a new value repro = repro with { State = VmState.Stopped }; var r = await Delete(repro); if (!r.IsOk && r.ErrorV.Status != HttpStatusCode.NotFound) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to delete repro {repro.VmId:Tag:VmId} marked as stopped"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to delete repro {VmId} marked as stopped", repro.VmId); } return repro; @@ -164,7 +166,8 @@ public async Async.Task Init(Repro repro) { var r = await Replace(repro); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to replace init repro: {repro.VmId:Tag:VmId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to replace init repro: {VmId}", repro.VmId); } return repro; } @@ -295,13 +298,16 @@ await _context.Containers.SaveBlob( ); } - _logTracer.Info($"saved repro script {repro.VmId:Tag:VmId}"); + _logTracer.LogInformation("saved repro script {VmId}", repro.VmId); return OneFuzzResultVoid.Ok; } public async Async.Task SetError(Repro repro, Error result) { - _logTracer.Info( - $"repro failed: {repro.VmId:Tag:VmId} - {repro.TaskId:Tag:TaskId} {result:Tag:Error}" + _logTracer.LogInformation( + "repro failed: {VmId} - {TaskId} {Error}", + repro.VmId, + repro.TaskId, + result ); repro = repro with { @@ -311,7 +317,8 @@ public async Async.Task SetError(Repro repro, Error result) { var r = await Replace(repro); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to replace repro record for {repro.VmId:Tag:VmId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to replace repro record for {VmId}", repro.VmId); } return repro; } @@ -348,7 +355,8 @@ public async Task> Create(ReproConfig config, UserInfo user var r = await _context.ReproOperations.Insert(vm); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to insert repro record for {vm.VmId:Tag:VmId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to insert repro record for {VmId}", vm.VmId); return OneFuzzResult.Error( ErrorCode.UNABLE_TO_CREATE, new[] { "failed to insert repro record" }); diff --git a/src/ApiService/ApiService/onefuzzlib/Request.cs b/src/ApiService/ApiService/onefuzzlib/Request.cs index 12acb7278c..e503c8bad1 100644 --- a/src/ApiService/ApiService/onefuzzlib/Request.cs +++ b/src/ApiService/ApiService/onefuzzlib/Request.cs @@ -5,8 +5,8 @@ using System.Text.Json.Serialization; using Faithlife.Utility; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service; public interface IRequestHandling { @@ -56,14 +56,20 @@ public ProblemDetails(HttpStatusCode code, Error error) { } public class RequestHandling : IRequestHandling { - private readonly ILogTracer _log; - public RequestHandling(ILogTracer log) { + private readonly ILogger _log; + public RequestHandling(ILogger log) { + _log = log; + } + + public RequestHandling(ILogger log) { _log = log; } + + public async Async.Task NotOk(HttpRequestData request, Error error, string context, HttpStatusCode statusCode = HttpStatusCode.BadRequest) { var statusNum = (int)statusCode; if (statusNum >= 400 && statusNum <= 599) { - _log.Error($"request error: {context:Tag:Context} - {error:Tag:Error}"); + _log.LogError("request error: {Context} - {Error}", context, error); // emit standardized errors according to RFC7807: // https://www.rfc-editor.org/rfc/rfc7807 diff --git a/src/ApiService/ApiService/onefuzzlib/ScalesetOperations.cs b/src/ApiService/ApiService/onefuzzlib/ScalesetOperations.cs index 903514e58c..44062ca818 100644 --- a/src/ApiService/ApiService/onefuzzlib/ScalesetOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/ScalesetOperations.cs @@ -5,7 +5,7 @@ using Azure.ResourceManager.Monitor; using Azure.ResourceManager.Monitor.Models; using Microsoft.Extensions.Caching.Memory; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; public interface IScalesetOperations : IStatefulOrm { @@ -41,12 +41,11 @@ public interface IScalesetOperations : IStatefulOrm { } public class ScalesetOperations : StatefulOrm, IScalesetOperations { - private readonly ILogTracer _log; private readonly IMemoryCache _cache; - public ScalesetOperations(ILogTracer log, IMemoryCache cache, IOnefuzzContext context) - : base(log.WithTag("Component", "scalesets"), context) { - _log = base._logTracer; + public ScalesetOperations(ILogger log, IMemoryCache cache, IOnefuzzContext context) + : base(log, context) { + _logTracer.AddTag("Component", "scalesets"); _cache = cache; } @@ -67,7 +66,7 @@ public async Async.Task SyncScalesetSize(Scaleset scaleset) { var size = await _context.VmssOperations.GetVmssSize(scaleset.ScalesetId); if (size is null) { - _log.Info($"scaleset is unavailable {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("scaleset is unavailable {ScalesetId}", scaleset.ScalesetId); //#if the scaleset is missing, this is an indication the scaleset //# was manually deleted, rather than having OneFuzz delete it. As //# such, we should go thruogh the process of deleting it. @@ -78,12 +77,13 @@ public async Async.Task SyncScalesetSize(Scaleset scaleset) { if (size != scaleset.Size) { //# Azure auto-scaled us or nodes were manually added/removed //# New node state will be synced in cleanup_nodes - _log.Info($"unexpected scaleset size, resizing {scaleset.ScalesetId:Tag:ScalesetId} {scaleset.Size:Tag:ExpectedSize} {size:Tag:ActualSize}"); + _logTracer.LogInformation("unexpected scaleset size, resizing {ScalesetId} {ExpectedSize} {ActualSize}", scaleset.ScalesetId, scaleset.Size, size); scaleset = scaleset with { Size = size.Value }; var replaceResult = await Replace(scaleset); if (!replaceResult.IsOk) { - _log.WithHttpStatus(replaceResult.ErrorV).Error($"failed to update scaleset size for {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.AddHttpStatus(replaceResult.ErrorV); + _logTracer.LogError("failed to update scaleset size for {ScalesetId}", scaleset.ScalesetId); } } @@ -94,7 +94,7 @@ public async Async.Task SyncAutoscaleSettings(Scaleset scales if (scaleset.State != ScalesetState.Running) return OneFuzzResultVoid.Ok; - _log.Info($"syncing auto-scale settings for scaleset {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("syncing auto-scale settings for scaleset {ScalesetId}", scaleset.ScalesetId); var autoscaleProfile = await _context.AutoScaleOperations.GetAutoScaleProfile(scaleset.ScalesetId); if (!autoscaleProfile.IsOk) { @@ -116,14 +116,14 @@ public async Async.Task SyncAutoscaleSettings(Scaleset scales if (scaleAction.Direction == ScaleDirection.Increase) { scaleOutAmount = Int32.Parse(scaleAction.Value); - _logTracer.Info($"Scaleout cooldown in seconds. {scaleOutCooldown:Tag:Before}"); + _logTracer.LogInformation("Scaleout cooldown in seconds. {Before}", scaleOutCooldown); scaleOutCooldown = (long)scaleAction.Cooldown.TotalMinutes; - _logTracer.Info($"Scaleout cooldown in seconds. {scaleOutCooldown:Tag:After}"); + _logTracer.LogInformation("Scaleout cooldown in seconds. {After}", scaleOutCooldown); } else if (scaleAction.Direction == ScaleDirection.Decrease) { scaleInAmount = Int32.Parse(scaleAction.Value); - _logTracer.Info($"Scalin cooldown in seconds. {scaleInCooldown:Tag:Before}"); + _logTracer.LogInformation("Scalin cooldown in seconds. {Before}", scaleInCooldown); scaleInCooldown = (long)scaleAction.Cooldown.TotalMinutes; - _logTracer.Info($"Scalein cooldown in seconds. {scaleInCooldown:Tag:After}"); + _logTracer.LogInformation("Scalein cooldown in seconds. {After}", scaleInCooldown); } else { continue; } @@ -134,7 +134,7 @@ public async Async.Task SyncAutoscaleSettings(Scaleset scales return poolResult.ErrorV; } - _logTracer.Info($"Updating auto-scale entry for scaleset: {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("Updating auto-scale entry for scaleset: {ScalesetId}", scaleset.ScalesetId); _ = await _context.AutoScaleOperations.Update( scalesetId: scaleset.ScalesetId, minAmount: minAmount, @@ -154,9 +154,9 @@ public async Async.Task Resize(Scaleset scaleset) { return scaleset; } - _log.Info($"scaleset resize: {scaleset.ScalesetId:Tag:ScalesetId} - {scaleset.Size:Tag:Size}"); + _logTracer.LogInformation("scaleset resize: {ScalesetId} - {Size}", scaleset.ScalesetId, scaleset.Size); - var shrinkQueue = new ShrinkQueue(scaleset.ScalesetId, _context.Queue, _log); + var shrinkQueue = new ShrinkQueue(scaleset.ScalesetId, _context.Queue, _logTracer); // # reset the node delete queue await shrinkQueue.Clear(); @@ -166,7 +166,7 @@ public async Async.Task Resize(Scaleset scaleset) { // # Treat Azure knowledge of the size of the scaleset as "ground truth" var vmssSize = await _context.VmssOperations.GetVmssSize(scaleset.ScalesetId); if (vmssSize is null) { - _log.Info($"scaleset is unavailable {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("scaleset is unavailable {ScalesetId}", scaleset.ScalesetId); //#if the scaleset is missing, this is an indication the scaleset //# was manually deleted, rather than having OneFuzz delete it. As @@ -192,11 +192,19 @@ public async Async.Task SetState(Scaleset scaleset, ScalesetState stat return scaleset; } - _log.WithTag("Pool", scaleset.PoolName.ToString()).Event($"SetState Scaleset {scaleset.ScalesetId:Tag:ScalesetId} {scaleset.State:Tag:From} - {state:Tag:To}"); + _logTracer.AddTags(new Dictionary() { + { "ScalesetId", scaleset.ScalesetId.ToString()}, + { "From", scaleset.State.ToString()}, + { "To", state.ToString()} + }); + + _logTracer.AddTag("Pool", scaleset.PoolName.ToString()); + _logTracer.LogEvent("SetState Scaleset"); var updatedScaleSet = scaleset with { State = state }; var r = await Replace(updatedScaleSet); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"Failed to update scaleset {updatedScaleSet.ScalesetId:Tag:ScalesetId} when updating {updatedScaleSet.State:Tag:StateFrom} - {state:Tag:StateTo}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("Failed to update scaleset when updating state"); // TODO: this should really return OneFuzzResult but then that propagates up the call stack throw new Exception($"Failed to update scaleset {updatedScaleSet.ScalesetId} when updating state from {updatedScaleSet.State} to {state}"); } @@ -228,20 +236,20 @@ async Async.Task SetFailed(Scaleset scaleset, Error error) { public async Async.Task UpdateConfigs(Scaleset scaleSet) { if (scaleSet.State == ScalesetState.Halt) { - _log.Info($"not updating configs, scalest is set to be deleted {scaleSet.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("not updating configs, scalest is set to be deleted {ScalesetId}", scaleSet.ScalesetId); return scaleSet; } if (!scaleSet.NeedsConfigUpdate) { - _log.Verbose($"config update no needed {scaleSet.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogDebug("config update no needed {ScalesetId}", scaleSet.ScalesetId); return scaleSet; } - _log.Info($"updating scalset configs {scaleSet.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("updating scalset configs {ScalesetId}", scaleSet.ScalesetId); var pool = await _context.PoolOperations.GetByName(scaleSet.PoolName); if (!pool.IsOk) { - _log.Error($"unable to find pool during config update {scaleSet.PoolName:Tag:PoolName} - {scaleSet.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogError("unable to find pool during config update {PoolName} - {ScalesetId}", scaleSet.PoolName, scaleSet.ScalesetId); scaleSet = await SetFailed(scaleSet, pool.ErrorV); return scaleSet; } @@ -249,7 +257,7 @@ public async Async.Task UpdateConfigs(Scaleset scaleSet) { var extensions = await _context.Extensions.FuzzExtensions(pool.OkV, scaleSet); var res = await _context.VmssOperations.UpdateExtensions(scaleSet.ScalesetId, extensions); if (!res.IsOk) { - _log.Info($"unable to update configs {string.Join(',', res.ErrorV.Errors!)}"); + _logTracer.LogInformation("unable to update configs {erorrs}", string.Join(',', res.ErrorV.Errors!)); return scaleSet; } @@ -257,7 +265,7 @@ public async Async.Task UpdateConfigs(Scaleset scaleSet) { scaleSet = scaleSet with { NeedsConfigUpdate = false }; var updateResult = await Update(scaleSet); if (!updateResult.IsOk) { - _log.Info($"unable to set NeedsConfigUpdate to false - will try again"); + _logTracer.LogInformation("unable to set NeedsConfigUpdate to false - will try again"); } return scaleSet; @@ -269,12 +277,12 @@ public Async.Task SetShutdown(Scaleset scaleset, bool now) public async Async.Task Setup(Scaleset scaleset) { //# TODO: How do we pass in SSH configs for Windows? Previously //# This was done as part of the generated per-task setup script. - _logTracer.Info($"setup {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("setup {ScalesetId}", scaleset.ScalesetId); var network = await Network.Init(scaleset.Region, _context); var networkId = await network.GetId(); if (networkId is null) { - _logTracer.Info($"creating network {scaleset.Region:Tag:Region} - {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("creating network {Region} - {ScalesetId}", scaleset.Region, scaleset.ScalesetId); var result = await network.Create(); if (!result.IsOk) { return await SetFailed(scaleset, result.ErrorV); @@ -283,20 +291,20 @@ public async Async.Task Setup(Scaleset scaleset) { //TODO : why are we saving scaleset here ? var r = await Update(scaleset); if (!r.IsOk) { - _logTracer.Error($"Failed to save scaleset {scaleset.ScalesetId:Tag:ScalesetId} due to {r.ErrorV:Tag:Error}"); + _logTracer.LogError("Failed to save scaleset {ScalesetId} due to {Error}", scaleset.ScalesetId, r.ErrorV); } return scaleset; } if (scaleset.Auth is null) { - _logTracer.Error($"Scaleset Auth is missing for scaleset {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogError("Scaleset Auth is missing for scaleset {ScalesetId}", scaleset.ScalesetId); return await SetFailed(scaleset, Error.Create(ErrorCode.UNABLE_TO_CREATE, "missing required auth")); } var auth = await _context.SecretsOperations.GetSecretValue(scaleset.Auth); if (auth is null) { - _logTracer.Error($"Scaleset Auth is missing for scaleset {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogError("Scaleset Auth is missing for scaleset {ScalesetId}", scaleset.ScalesetId); return await SetFailed(scaleset, Error.Create(ErrorCode.UNABLE_TO_CREATE, "missing required auth")); } @@ -306,11 +314,11 @@ public async Async.Task Setup(Scaleset scaleset) { if (vmss is null) { var pool = await _context.PoolOperations.GetByName(scaleset.PoolName); if (!pool.IsOk) { - _logTracer.Error($"failed to get pool by name {scaleset.PoolName:Tag:PoolName} for scaleset: {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogError("failed to get pool by name {PoolName} for scaleset: {ScalesetId}", scaleset.PoolName, scaleset.ScalesetId); return await SetFailed(scaleset, pool.ErrorV); } - _logTracer.Info($"creating scaleset {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("creating scaleset {ScalesetId}", scaleset.ScalesetId); var extensions = await _context.Extensions.FuzzExtensions(pool.OkV, scaleset); var result = await _context.VmssOperations.CreateVmss( scaleset.Region, @@ -327,32 +335,32 @@ public async Async.Task Setup(Scaleset scaleset) { scaleset.Tags); if (!result.IsOk) { - _logTracer.Error($"Failed to create scaleset {scaleset.ScalesetId:Tag:ScalesetId} due to {result.ErrorV:Tag:Error}"); + _logTracer.LogError("Failed to create scaleset {ScalesetId} due to {Error}", scaleset.ScalesetId, result.ErrorV); return await SetFailed(scaleset, result.ErrorV); } else { // TODO: Link up auto scale resource with diagnostics - _logTracer.Info($"creating scaleset: {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("creating scaleset: {ScalesetId}", scaleset.ScalesetId); } } else if (vmss.ProvisioningState == "Creating") { var result = TrySetIdentity(scaleset, vmss); if (!result.IsOk) { - _logTracer.Warning($"Could not set identity due to: {result.ErrorV:Tag:Error} for {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogWarning("Could not set identity due to: {Error} for {ScalesetId}", result.ErrorV, scaleset.ScalesetId); } else { scaleset = result.OkV; } } else { - _logTracer.Info($"scaleset {scaleset.ScalesetId:Tag:ScalesetId} is in {vmss.ProvisioningState:Tag:ScalesetState}"); + _logTracer.LogInformation("scaleset {ScalesetId} is in {ScalesetState}", scaleset.ScalesetId, vmss.ProvisioningState); var autoScaling = await TryEnableAutoScaling(scaleset); if (!autoScaling.IsOk) { - _logTracer.Error($"failed to set auto-scaling for {scaleset.ScalesetId:Tag:ScalesetId} due to {autoScaling.ErrorV:Tag:Error}"); + _logTracer.LogError("failed to set auto-scaling for {ScalesetId} due to {Error}", scaleset.ScalesetId, autoScaling.ErrorV); return await SetFailed(scaleset, autoScaling.ErrorV); } var result = TrySetIdentity(scaleset, vmss); if (!result.IsOk) { - _logTracer.Error($"failed to set identity for scaleset {scaleset.ScalesetId:Tag:ScalesetId} due to: {result.ErrorV:Tag:Error}"); + _logTracer.LogError("failed to set identity for scaleset {ScalesetId} due to: {Error}", scaleset.ScalesetId, result.ErrorV); return await SetFailed(scaleset, result.ErrorV); } else { scaleset = await SetState(scaleset, ScalesetState.Running); @@ -361,7 +369,8 @@ public async Async.Task Setup(Scaleset scaleset) { var rr = await Replace(scaleset); if (!rr.IsOk) { - _logTracer.WithHttpStatus(rr.ErrorV).Error($"Failed to save scale data for scale set: {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.AddHttpStatus(rr.ErrorV); + _logTracer.LogError("Failed to save scale data for scale set: {ScalesetId}", scaleset.ScalesetId); } return scaleset; @@ -388,11 +397,11 @@ static OneFuzzResult TrySetIdentity(Scaleset scaleset, VirtualMachineS } async Async.Task TryEnableAutoScaling(Scaleset scaleset) { - _logTracer.Info($"Trying to add auto scaling for scaleset {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("Trying to add auto scaling for scaleset {ScalesetId}", scaleset.ScalesetId); var r = await _context.PoolOperations.GetByName(scaleset.PoolName); if (!r.IsOk) { - _logTracer.Error($"Failed to get pool by name: {scaleset.PoolName:Tag:PoolName} - {r.ErrorV:Tag:Error}"); + _logTracer.LogError("Failed to get pool by name: {PoolName} - {Error}", scaleset.PoolName, r.ErrorV); return r.ErrorV; } var pool = r.OkV; @@ -403,7 +412,7 @@ async Async.Task TryEnableAutoScaling(Scaleset scaleset) { if (!capacity.HasValue) { var capacityFailed = OneFuzzResultVoid.Error(ErrorCode.UNABLE_TO_FIND, $"Failed to get capacity for scaleset {scaleset.ScalesetId}"); - _logTracer.Error($"Failed to get capacity for scaleset {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogError("Failed to get capacity for scaleset {ScalesetId}", scaleset.ScalesetId); return capacityFailed; } @@ -411,7 +420,7 @@ async Async.Task TryEnableAutoScaling(Scaleset scaleset) { if (poolQueueUri is null) { var failedToFindQueueUri = OneFuzzResultVoid.Error(ErrorCode.UNABLE_TO_FIND, $"Failed to get pool queue uri for scaleset {scaleset.ScalesetId}"); - _logTracer.Error($"Failed to get pool queue uri for scaleset {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogError("Failed to get pool queue uri for scaleset {ScalesetId}", scaleset.ScalesetId); return failedToFindQueueUri; } @@ -419,7 +428,7 @@ async Async.Task TryEnableAutoScaling(Scaleset scaleset) { if (autoScaleConfig is null) { autoScaleProfile = _context.AutoScaleOperations.DefaultAutoScaleProfile(poolQueueUri!, capacity.Value); } else { - _logTracer.Info($"Using existing auto scale settings from database for scaleset {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("Using existing auto scale settings from database for scaleset {ScalesetId}", scaleset.ScalesetId); autoScaleProfile = _context.AutoScaleOperations.CreateAutoScaleProfile( queueUri: poolQueueUri!, minAmount: autoScaleConfig.Min, @@ -433,13 +442,13 @@ async Async.Task TryEnableAutoScaling(Scaleset scaleset) { } - _logTracer.Info($"Added auto scale resource to scaleset: {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("Added auto scale resource to scaleset: {ScalesetId}", scaleset.ScalesetId); return await _context.AutoScaleOperations.AddAutoScaleToVmss(scaleset.ScalesetId, autoScaleProfile); } public async Async.Task Init(Scaleset scaleset) { - _logTracer.Info($"init {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("init {ScalesetId}", scaleset.ScalesetId); var shrinkQueue = new ShrinkQueue(scaleset.ScalesetId, _context.Queue, _logTracer); await shrinkQueue.Create(); // Handle the race condition between a pool being deleted and a @@ -447,21 +456,21 @@ public async Async.Task Init(Scaleset scaleset) { var poolResult = await _context.PoolOperations.GetByName(scaleset.PoolName); if (!poolResult.IsOk) { - _logTracer.Error($"failed to get pool by name {scaleset.PoolName:Tag:PoolName} for scaleset: {scaleset.ScalesetId:Tag:ScalesetId} due to {poolResult.ErrorV:Tag:Error}"); + _logTracer.LogError("failed to get pool by name {PoolName} for scaleset: {ScalesetId} due to {Error}", scaleset.PoolName, scaleset.ScalesetId, poolResult.ErrorV); return await SetFailed(scaleset, poolResult.ErrorV); } var pool = poolResult.OkV; if (pool.State == PoolState.Init) { - _logTracer.Info($"waiting for pool {scaleset.PoolName:Tag:PoolName} - {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("waiting for pool {PoolName} - {ScalesetId}", scaleset.PoolName, scaleset.ScalesetId); } else if (pool.State == PoolState.Running) { var imageOsResult = await scaleset.Image.GetOs(_cache, _context.Creds.ArmClient, scaleset.Region); if (!imageOsResult.IsOk) { - _logTracer.Error($"failed to get OS with region: {scaleset.Region:Tag:Region} {scaleset.Image:Tag:Image} for scaleset: {scaleset.ScalesetId:Tag:ScalesetId} due to {imageOsResult.ErrorV:Tag:Error}"); + _logTracer.LogError("failed to get OS with region: {Region} {Image} for scaleset: {ScalesetId} due to {Error}", scaleset.Region, scaleset.Image, scaleset.ScalesetId, imageOsResult.ErrorV); return await SetFailed(scaleset, imageOsResult.ErrorV); } else if (imageOsResult.OkV != pool.Os) { - _logTracer.Error($"got invalid OS: {imageOsResult.OkV:Tag:ActualOs} for scaleset: {scaleset.ScalesetId:Tag:ScalesetId} expected OS {pool.Os:Tag:ExpectedOs}"); + _logTracer.LogError("got invalid OS: {ActualOs} for scaleset: {ScalesetId} expected OS {ExpectedOs}", imageOsResult.OkV, scaleset.ScalesetId, pool.Os); return await SetFailed(scaleset, Error.Create(ErrorCode.INVALID_REQUEST, $"invalid os (got: {imageOsResult.OkV} needed: {pool.Os})")); } else { return await SetState(scaleset, ScalesetState.Setup); @@ -474,25 +483,27 @@ public async Async.Task Init(Scaleset scaleset) { } public async Async.Task Halt(Scaleset scaleset) { - var shrinkQueue = new ShrinkQueue(scaleset.ScalesetId, _context.Queue, _log); + var shrinkQueue = new ShrinkQueue(scaleset.ScalesetId, _context.Queue, _logTracer); await shrinkQueue.Delete(); await foreach (var node in _context.NodeOperations.SearchStates(scalesetId: scaleset.ScalesetId)) { - _log.Info($"deleting node {scaleset.ScalesetId:Tag:ScalesetId} - {node.MachineId:Tag:MachineId}"); + _logTracer.LogInformation("deleting node {ScalesetId} - {MachineId}", scaleset.ScalesetId, node.MachineId); await _context.NodeOperations.Delete(node, "scaleset is being shutdown"); } - _log.Info($"scaleset delete starting - {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("scaleset delete starting - {ScalesetId}", scaleset.ScalesetId); if (await _context.VmssOperations.DeleteVmss(scaleset.ScalesetId)) { - _log.Info($"scaleset deleted: {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("scaleset deleted: {ScalesetId}", scaleset.ScalesetId); var r = await Delete(scaleset); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"Failed to delete scaleset record {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("Failed to delete scaleset record {ScalesetId}", scaleset.ScalesetId); } } else { var r = await Update(scaleset); if (!r.IsOk) { - _log.WithHttpStatus(r.ErrorV).Error($"Failed to save scaleset record {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("Failed to save scaleset record {ScalesetId}", scaleset.ScalesetId); } } @@ -505,17 +516,17 @@ public async Async.Task Halt(Scaleset scaleset) { /// /// true if scaleset got modified public async Async.Task<(bool, Scaleset)> CleanupNodes(Scaleset scaleSet) { - _log.Info($"cleaning up nodes {scaleSet.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("cleaning up nodes {ScalesetId}", scaleSet.ScalesetId); if (scaleSet.State == ScalesetState.Halt) { - _log.Info($"halting scaleset {scaleSet.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("halting scaleset {ScalesetId}", scaleSet.ScalesetId); scaleSet = await Halt(scaleSet); return (true, scaleSet); } var pool = await _context.PoolOperations.GetByName(scaleSet.PoolName); if (!pool.IsOk) { - _log.Error($"unable to find pool during cleanup {scaleSet.ScalesetId:Tag:ScalesetId} - {scaleSet.PoolName:Tag:PoolName}"); + _logTracer.LogError("unable to find pool during cleanup {ScalesetId} - {PoolName}", scaleSet.ScalesetId, scaleSet.PoolName); scaleSet = await SetFailed(scaleSet, pool.ErrorV!); return (true, scaleSet); } @@ -534,7 +545,7 @@ public async Async.Task Halt(Scaleset scaleset) { //# Nodes do not exists in scalesets but in table due to unknown failure await foreach (var node in nodes) { if (!azureNodes.ContainsKey(node.MachineId)) { - _log.Info($"{node.MachineId:Tag:MachineId} no longer in scaleset {scaleSet.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("{MachineId} no longer in scaleset {ScalesetId}", node.MachineId, scaleSet.ScalesetId); await _context.NodeOperations.Delete(node, "node is being cleaned up because it is no longer in the scaleset"); } } @@ -556,7 +567,7 @@ public async Async.Task Halt(Scaleset scaleset) { continue; } - _log.Info($"adding missing azure node {machineId:Tag:MachineId} {scaleSet.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("adding missing azure node {MachineId} {ScalesetId}", machineId, scaleSet.ScalesetId); // Note, using isNew:True makes it such that if a node already has // checked in, this won't overwrite it. @@ -589,12 +600,12 @@ where x.State.ReadyForReset() if (node.DeleteRequested) { toDelete[node.MachineId] = node; } else { - if (await new ShrinkQueue(scaleSet.ScalesetId, _context.Queue, _log).ShouldShrink()) { + if (await new ShrinkQueue(scaleSet.ScalesetId, _context.Queue, _logTracer).ShouldShrink()) { toDelete[node.MachineId] = await _context.NodeOperations.SetHalt(node); - } else if (await new ShrinkQueue(pool.OkV.PoolId, _context.Queue, _log).ShouldShrink()) { + } else if (await new ShrinkQueue(pool.OkV.PoolId, _context.Queue, _logTracer).ShouldShrink()) { toDelete[node.MachineId] = await _context.NodeOperations.SetHalt(node); } else { - _logTracer.Info($"Node ready to reimage {node.MachineId:Tag:MachineId} {node.ScalesetId:Tag:ScalesetId} {node.State:Tag:State}"); + _logTracer.LogInformation("Node ready to reimage {MachineId} {ScalesetId} {State}", node.MachineId, node.ScalesetId, node.State); toReimage[node.MachineId] = node; } } @@ -610,7 +621,7 @@ where x.State.ReadyForReset() errorMessage = "node reimaged due to never receiving heartbeat"; } - _log.Info($"{errorMessage} {deadNode.MachineId:Tag:MachineId} {deadNode.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("{errorMessage} {MachineId} {ScalesetId}", errorMessage, deadNode.MachineId, deadNode.ScalesetId); var error = Error.Create(ErrorCode.TASK_FAILED, $"{errorMessage} scaleset_id {deadNode.ScalesetId} last heartbeat:{deadNode.Heartbeat}"); await _context.NodeOperations.MarkTasksStoppedEarly(deadNode, error); @@ -622,12 +633,12 @@ where x.State.ReadyForReset() var reimageNodes = await ReimageNodes(scaleSet, toReimage.Values, strategy); if (!reimageNodes.IsOk) { - _log.Warning(reimageNodes.ErrorV); + _logTracer.LogWarning("{error}", reimageNodes.ErrorV); return (false, scaleSet); } var deleteNodes = await DeleteNodes(scaleSet, toDelete.Values, "Node was ReadyForReset"); if (!deleteNodes.IsOk) { - _log.Warning(deleteNodes.ErrorV); + _logTracer.LogWarning("{error}", deleteNodes.ErrorV); return (toReimage.Count > 0, scaleSet); } @@ -637,17 +648,17 @@ where x.State.ReadyForReset() public async Async.Task ReimageNodes(Scaleset scaleset, IEnumerable nodes, NodeDisposalStrategy disposalStrategy) { if (nodes is null || !nodes.Any()) { - _log.Info($"no nodes to reimage: {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("no nodes to reimage: {ScalesetId}", scaleset.ScalesetId); return OneFuzzResultVoid.Ok; } if (scaleset.State == ScalesetState.Shutdown) { - _log.Info($"scaleset shutting down, deleting rather than reimaging nodes {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("scaleset shutting down, deleting rather than reimaging nodes {ScalesetId}", scaleset.ScalesetId); return await DeleteNodes(scaleset, nodes, "scaleset is shutting down"); } if (scaleset.State == ScalesetState.Halt) { - _log.Info($"scaleset halting, ignoring node reimage {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("scaleset halting, ignoring node reimage {ScalesetId}", scaleset.ScalesetId); return OneFuzzResultVoid.Ok; } @@ -658,20 +669,20 @@ public async Async.Task ReimageNodes(Scaleset scaleset, IEnum } if (node.DebugKeepNode) { - _log.Warning($"not reimaging manually overridden node {node.MachineId:Tag:MachineId} in scaleset {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogWarning("not reimaging manually overridden node {MachineId} in scaleset {ScalesetId}", node.MachineId, scaleset.ScalesetId); } else { nodesToReimage.Add(node); } } if (!nodesToReimage.Any()) { - _log.Info($"no nodes to reimage {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("no nodes to reimage {ScalesetId}", scaleset.ScalesetId); return OneFuzzResultVoid.Ok; } switch (disposalStrategy) { case NodeDisposalStrategy.Decommission: - _log.Info($"Skipping reimage of nodes in scaleset: {scaleset.ScalesetId:Tag:ScalesetId}, deleting nodes: {string.Join(", ", nodesToReimage.Select(n => n.MachineId)):Tag:MachineIds} {string.Join(", ", nodesToReimage.Select(n => n.InstanceId)):Tag:InstanceIds}"); + _logTracer.LogInformation("Skipping reimage of nodes in scaleset: {ScalesetId}, deleting nodes: {MachineIds} {InstanceIds}", scaleset.ScalesetId, string.Join(", ", nodesToReimage.Select(n => n.MachineId)), string.Join(", ", nodesToReimage.Select(n => n.InstanceId))); var deleteNodes = await _context.VmssOperations.DeleteNodes(scaleset.ScalesetId, nodesToReimage); if (!deleteNodes.IsOk) { return deleteNodes; @@ -704,7 +715,7 @@ await Async.Task.WhenAll(nodesToReimage public async Async.Task DeleteNodes(Scaleset scaleset, IEnumerable nodes, string reason) { if (nodes is null || !nodes.Any()) { - _log.Info($"no nodes to delete: scaleset_id: {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("no nodes to delete: scaleset_id: {ScalesetId}", scaleset.ScalesetId); return OneFuzzResultVoid.Ok; } @@ -712,20 +723,20 @@ public async Async.Task DeleteNodes(Scaleset scaleset, IEnume nodes = await Async.Task.WhenAll(nodes.Select(node => _context.NodeOperations.SetHalt(node))); if (scaleset.State == ScalesetState.Halt) { - _log.Info($"scaleset halting, ignoring deletion {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("scaleset halting, ignoring deletion {ScalesetId}", scaleset.ScalesetId); return OneFuzzResultVoid.Ok; } var nodesToDelete = new List(); foreach (var node in nodes) { if (node.DebugKeepNode) { - _log.Warning($"not deleting manually overridden node {node.MachineId:Tag:MachineId} in scaleset {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogWarning("not deleting manually overridden node {MachineId} in scaleset {ScalesetId}", node.MachineId, scaleset.ScalesetId); } else { nodesToDelete.Add(node); } } - _log.Info($"deleting nodes {scaleset.ScalesetId:Tag:ScalesetId} {string.Join(", ", nodesToDelete.Select(n => n.MachineId)):Tag:MachineIds}"); + _logTracer.LogInformation("deleting nodes {ScalesetId} {MachineIds}", scaleset.ScalesetId, string.Join(", ", nodesToDelete.Select(n => n.MachineId))); var deleteNodes = await _context.VmssOperations.DeleteNodes(scaleset.ScalesetId, nodesToDelete); if (!deleteNodes.IsOk) { return deleteNodes; @@ -769,10 +780,10 @@ private async Async.Task ResizeEqual(Scaleset scaleset) { var nodeCount = await _context.NodeOperations.SearchStates(scalesetId: scaleset.ScalesetId).CountAsync(); if (nodeCount == scaleset.Size) { - _log.Info($"resize finished {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("resize finished {ScalesetId}", scaleset.ScalesetId); return await SetState(scaleset, ScalesetState.Running); } else { - _log.Info($"resize finished, waiting for nodes to check in {scaleset.ScalesetId:Tag:ScalesetId} ({nodeCount:Tag:NodeCount} of {scaleset.Size:Tag:Size} checked in)"); + _logTracer.LogInformation("resize finished, waiting for nodes to check in {ScalesetId} ({NodeCount} of {Size} checked in)", scaleset.ScalesetId, nodeCount, scaleset.Size); return scaleset; } } @@ -780,18 +791,18 @@ private async Async.Task ResizeEqual(Scaleset scaleset) { private async Async.Task ResizeGrow(Scaleset scaleset) { var resizeResult = await _context.VmssOperations.ResizeVmss(scaleset.ScalesetId, scaleset.Size); if (resizeResult.IsOk == false) { - _log.Info($"scaleset is mid-operation already {scaleset.ScalesetId:Tag:ScalesetId} {resizeResult.ErrorV:Tag:Error}"); + _logTracer.LogInformation("scaleset is mid-operation already {ScalesetId} {Error}", scaleset.ScalesetId, resizeResult.ErrorV); } return scaleset; } private async Async.Task ResizeShrink(Scaleset scaleset, long? toRemove) { - _log.Info($"shrinking scaleset {scaleset.ScalesetId:Tag:ScalesetId} {toRemove:Tag:ToRemove}"); + _logTracer.LogInformation("shrinking scaleset {ScalesetId} {ToRemove}", scaleset.ScalesetId, toRemove); if (!toRemove.HasValue) { return scaleset; } else { - var queue = new ShrinkQueue(scaleset.ScalesetId, _context.Queue, _log); + var queue = new ShrinkQueue(scaleset.ScalesetId, _context.Queue, _logTracer); await queue.SetSize(toRemove.Value); var nodes = _context.NodeOperations.SearchStates(scalesetId: scaleset.ScalesetId); await foreach (var node in nodes) { @@ -833,18 +844,18 @@ public Async.Task SetSize(Scaleset scaleset, long size) { public async Async.Task Shutdown(Scaleset scaleset) { var size = await _context.VmssOperations.GetVmssSize(scaleset.ScalesetId); if (size == null) { - _logTracer.Info($"scale set shutdown: scaleset already deleted {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("scale set shutdown: scaleset already deleted {ScalesetId}", scaleset.ScalesetId); return await Halt(scaleset); } - _logTracer.Info($"scaleset shutdown {scaleset.ScalesetId:Tag:ScalesetId} {size:Tag:Size}"); + _logTracer.LogInformation("scaleset shutdown {ScalesetId} {Size}", scaleset.ScalesetId, size); { var nodes = _context.NodeOperations.SearchStates(scalesetId: scaleset.ScalesetId); // TODO: Parallelization opportunity await nodes.ForEachAwaitAsync(_context.NodeOperations.SetShutdown); } - _logTracer.Info($"checking for existing auto scale settings {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("checking for existing auto scale settings {ScalesetId}", scaleset.ScalesetId); var autoScalePolicy = _context.AutoScaleOperations.GetAutoscaleSettings(scaleset.ScalesetId); if (autoScalePolicy.IsOk && autoScalePolicy.OkV is AutoscaleSettingResource autoscaleSetting) { @@ -872,7 +883,7 @@ public async Async.Task Shutdown(Scaleset scaleset) { // auto scale will scale in the remaining nodes, // the scale set will have 0 instances, // and once the scale set is empty, we will delete it. - _logTracer.Info($"Getting nodes with scale in protection"); + _logTracer.LogInformation("Getting nodes with scale in protection"); try { var vmsWithProtection = await _context.VmssOperations @@ -880,23 +891,23 @@ public async Async.Task Shutdown(Scaleset scaleset) { .Where(vmResource => vmResource.Data?.ProtectionPolicy?.ProtectFromScaleIn is true) .ToListAsync(); - _logTracer.Info($"{JsonSerializer.Serialize(vmsWithProtection):Tag:VMsWithProtection}"); + _logTracer.LogInformation("{VMsWithProtection}", JsonSerializer.Serialize(vmsWithProtection)); var numVmsWithProtection = vmsWithProtection.Count; profile.Capacity.Minimum = numVmsWithProtection.ToString(); profile.Capacity.Default = numVmsWithProtection.ToString(); } catch (Exception ex) { - _logTracer.Exception(ex, $"Failed to list vmss for scaleset {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogError(ex, "Failed to list vmss for scaleset {ScalesetId}", scaleset.ScalesetId); } } var updatedAutoScale = await _context.AutoScaleOperations.UpdateAutoscale(autoscaleSetting.Data); if (!updatedAutoScale.IsOk) { - _logTracer.Error($"Failed to update auto scale {updatedAutoScale.ErrorV:Tag:Error}"); + _logTracer.LogError("Failed to update auto scale {Error}", updatedAutoScale.ErrorV); } } else if (!autoScalePolicy.IsOk) { - _logTracer.Error(autoScalePolicy.ErrorV); + _logTracer.LogError("{error}", autoScalePolicy.ErrorV); } else { - _logTracer.Info($"No existing auto scale settings found for {scaleset.ScalesetId:Tag:ScalesetId}"); + _logTracer.LogInformation("No existing auto scale settings found for {ScalesetId}", scaleset.ScalesetId); } if (size == 0) { diff --git a/src/ApiService/ApiService/onefuzzlib/Scheduler.cs b/src/ApiService/ApiService/onefuzzlib/Scheduler.cs index de9fa37e02..8da95e556f 100644 --- a/src/ApiService/ApiService/onefuzzlib/Scheduler.cs +++ b/src/ApiService/ApiService/onefuzzlib/Scheduler.cs @@ -1,5 +1,5 @@ using Azure.Storage.Sas; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; @@ -11,14 +11,14 @@ public class Scheduler : IScheduler { private readonly ITaskOperations _taskOperations; private readonly IConfig _config; private readonly IPoolOperations _poolOperations; - private readonly ILogTracer _logTracer; + private readonly ILogger _logTracer; private readonly IJobOperations _jobOperations; private readonly IContainers _containers; // TODO: eventually, this should be tied to the pool. const int MAX_TASKS_PER_SET = 10; - public Scheduler(ITaskOperations taskOperations, IConfig config, IPoolOperations poolOperations, ILogTracer logTracer, IJobOperations jobOperations, IContainers containers) { + public Scheduler(ITaskOperations taskOperations, IConfig config, IPoolOperations poolOperations, ILogger logTracer, IJobOperations jobOperations, IContainers containers) { _taskOperations = taskOperations; _config = config; _poolOperations = poolOperations; @@ -53,19 +53,19 @@ public async Async.Task ScheduleTasks() { var notReadyCount = tasks.Count - seen.Count; if (notReadyCount > 0) { - _logTracer.Info($"{notReadyCount:Tag:TasksNotReady} - {seen.Count:Tag:TasksSeen}"); + _logTracer.LogInformation("{TasksNotReady} - {TasksSeen}", notReadyCount, seen.Count); } } private async Async.Task ScheduleWorkset(WorkSet workSet, Pool pool, long count) { if (!PoolStateHelper.Available.Contains(pool.State)) { - _logTracer.Info($"pool not available {pool.Name:Tag:PoolName} - {pool.State:Tag:PoolState}"); + _logTracer.LogInformation("pool not available {PoolName} - {PoolState}", pool.Name, pool.State); return false; } for (var i = 0L; i < count; i++) { if (!await _poolOperations.ScheduleWorkset(pool, workSet)) { - _logTracer.Error($"unable to schedule workset {pool.Name:Tag:PoolName} {workSet:Tag:WorkSet}"); + _logTracer.LogError("unable to schedule workset {PoolName} {WorkSet}", pool.Name, workSet); return false; } } @@ -152,24 +152,24 @@ sealed record PoolKey( if (!poolCache.TryGetValue(poolKey, out var pool)) { var foundPool = await _taskOperations.GetPool(task); if (foundPool is null) { - _logTracer.Info($"unable to find pool for task: {task.TaskId:Tag:TaskId}"); + _logTracer.LogInformation("unable to find pool for task: {TaskId}", task.TaskId); return OneFuzzResult<(BucketConfig, WorkUnit)>.Error(ErrorCode.UNABLE_TO_FIND, $"unable to find pool for the task {task.TaskId} in job {task.JobId}"); } pool = poolCache[poolKey] = foundPool; } - _logTracer.Info($"scheduling task: {task.TaskId:Tag:TaskId}"); + _logTracer.LogInformation("scheduling task: {TaskId}", task.TaskId); var job = await _jobOperations.Get(task.JobId); if (job is null) { - _logTracer.Error($"invalid job {task.JobId:Tag:JobId} for task {task.TaskId:Tag:TaskId}"); + _logTracer.LogError("invalid job {JobId} for task {TaskId}", task.JobId, task.TaskId); return OneFuzzResult<(BucketConfig, WorkUnit)>.Error(ErrorCode.INVALID_JOB, $"invalid job_id {task.JobId} for task {task.TaskId}"); } var taskConfig = await _config.BuildTaskConfig(job, task); if (taskConfig is null) { - _logTracer.Error($"unable to build task config for task: {task.TaskId:Tag:TaskId}"); + _logTracer.LogError("unable to build task config for task: {TaskId}", task.TaskId); return OneFuzzResult<(BucketConfig, WorkUnit)>.Error(ErrorCode.INVALID_CONFIGURATION, $"unable to build task config for task: {task.TaskId} in job {task.JobId}"); } var setupContainer = task.Config.Containers?.FirstOrDefault(c => c.Type == ContainerType.Setup) ?? throw new Exception($"task missing setup container: task_type = {task.Config.Task.Type}"); diff --git a/src/ApiService/ApiService/onefuzzlib/ShrinkQueue.cs b/src/ApiService/ApiService/onefuzzlib/ShrinkQueue.cs index 4fb480cdbc..0816c6f455 100644 --- a/src/ApiService/ApiService/onefuzzlib/ShrinkQueue.cs +++ b/src/ApiService/ApiService/onefuzzlib/ShrinkQueue.cs @@ -1,21 +1,22 @@ -namespace Microsoft.OneFuzz.Service; +using Microsoft.Extensions.Logging; +namespace Microsoft.OneFuzz.Service; public record ShrinkEntry(Guid ShrinkId); public sealed class ShrinkQueue { readonly IQueue _queueOps; - readonly ILogTracer _log; + readonly ILogger _log; - public ShrinkQueue(ScalesetId baseId, IQueue queueOps, ILogTracer log) + public ShrinkQueue(ScalesetId baseId, IQueue queueOps, ILogger log) // backwards compat // scaleset ID used to be a GUID and then this class would format it with "N" format // to retain the same behaviour remove any dashes in the name : this(baseId.ToString().Replace("-", ""), queueOps, log) { } - public ShrinkQueue(Guid poolId, IQueue queueOps, ILogTracer log) + public ShrinkQueue(Guid poolId, IQueue queueOps, ILogger log) : this(poolId.ToString("N"), queueOps, log) { } - private ShrinkQueue(string baseId, IQueue queueOps, ILogTracer log) { + private ShrinkQueue(string baseId, IQueue queueOps, ILogger log) { var name = ShrinkQueueNamePrefix + baseId.ToLowerInvariant(); // queue names can be no longer than 63 characters @@ -65,7 +66,10 @@ public async Async.Task SetSize(long size) { //TODO: retry after a delay ? I guess make a decision on this //if we hit this error message... For now just log and move on to //make it behave same as Python code. - _log.Error($"failed to add entry to shrink queue"); + using (_log.BeginScope(QueueName)) { + _log.AddTag("ShrinkQueue", QueueName); + _log.LogError("failed to add entry to shrink queue"); + } i++; } } diff --git a/src/ApiService/ApiService/onefuzzlib/Storage.cs b/src/ApiService/ApiService/onefuzzlib/Storage.cs index 61e53da93e..044c71bd9a 100644 --- a/src/ApiService/ApiService/onefuzzlib/Storage.cs +++ b/src/ApiService/ApiService/onefuzzlib/Storage.cs @@ -9,7 +9,7 @@ using Azure.Storage.Queues; using Azure.Storage.Sas; using Microsoft.Extensions.Caching.Memory; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; public enum StorageType { @@ -88,12 +88,12 @@ public Uri GenerateQueueSasUri( public sealed class Storage : IStorage { private readonly ICreds _creds; private readonly ArmClient _armClient; - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly IServiceConfig _config; private readonly IMemoryCache _cache; public Storage(ICreds creds, - ILogTracer log, + ILogger log, IServiceConfig config, IMemoryCache cache) { _creds = creds; @@ -146,7 +146,7 @@ public IReadOnlyList CorpusAccounts() { results.Add(account.Id); } - _log.Info($"corpus accounts: {JsonSerializer.Serialize(results)}"); + _log.LogInformation("corpus accounts: {results}", JsonSerializer.Serialize(results)); return results; })!; // NULLABLE: only this method inserts _corpusAccountsKey so it cannot be null } diff --git a/src/ApiService/ApiService/onefuzzlib/Subnet.cs b/src/ApiService/ApiService/onefuzzlib/Subnet.cs index c0c8467664..19ac6addf6 100644 --- a/src/ApiService/ApiService/onefuzzlib/Subnet.cs +++ b/src/ApiService/ApiService/onefuzzlib/Subnet.cs @@ -2,7 +2,7 @@ using Azure; using Azure.Core; using Azure.ResourceManager.Network; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; @@ -19,18 +19,18 @@ public interface ISubnet { public class Subnet : ISubnet { private readonly ICreds _creds; - private readonly ILogTracer _logTracer; + private readonly ILogger _logTracer; private readonly IOnefuzzContext _context; - public Subnet(ICreds creds, ILogTracer logTracer, IOnefuzzContext context) { + public Subnet(ICreds creds, ILogger logTracer, IOnefuzzContext context) { _creds = creds; _logTracer = logTracer; _context = context; } public async Task CreateVirtualNetwork(string resourceGroup, string name, Region region, NetworkConfig networkConfig) { - _logTracer.Info($"creating subnet - {resourceGroup:Tag:ResourceGroup} {name:Tag:Name} {region:Tag:Region}"); + _logTracer.LogInformation("creating subnet - {ResourceGroup} {Name} {Region}", resourceGroup, name, region); var virtualNetParam = new VirtualNetworkData { Location = region, @@ -46,7 +46,7 @@ public async Task CreateVirtualNetwork(string resourceGroup, var onefuzzOwner = _context.ServiceConfiguration.OneFuzzOwner; if (!string.IsNullOrEmpty(onefuzzOwner)) { if (!virtualNetParam.Tags.TryAdd("OWNER", onefuzzOwner)) { - _logTracer.Warning($"Failed to add tag 'OWNER':{onefuzzOwner:Tag:Owner} to virtual network {resourceGroup:Tag:ResourceGroup}:{name:Tag:Name}"); + _logTracer.LogWarning("Failed to add tag 'OWNER':{Owner} to virtual network {ResourceGroup}:{Name}", onefuzzOwner, resourceGroup, name); } } @@ -56,7 +56,7 @@ public async Task CreateVirtualNetwork(string resourceGroup, name, virtualNetParam); } catch (RequestFailedException ex) { - _logTracer.Error($"network creation failed: {name:Tag:Name}:{region:Tag:Region} {ex.Message:Tag:Error}"); + _logTracer.LogError(ex, "network creation failed: {Name}:{Region} {Error}", name, region, ex.Message); return OneFuzzResultVoid.Error( ErrorCode.UNABLE_TO_CREATE_NETWORK, ex.ToString() diff --git a/src/ApiService/ApiService/onefuzzlib/TaskEventOperations.cs b/src/ApiService/ApiService/onefuzzlib/TaskEventOperations.cs index 40a74f5a0f..1d0af35921 100644 --- a/src/ApiService/ApiService/onefuzzlib/TaskEventOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/TaskEventOperations.cs @@ -1,5 +1,5 @@ using ApiService.OneFuzzLib.Orm; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; public interface ITaskEventOperations : IOrm { @@ -7,7 +7,7 @@ public interface ITaskEventOperations : IOrm { } public sealed class TaskEventOperations : Orm, ITaskEventOperations { - public TaskEventOperations(ILogTracer logTracer, IOnefuzzContext context) + public TaskEventOperations(ILogger logTracer, IOnefuzzContext context) : base(logTracer, context) { } public IAsyncEnumerable GetSummary(Guid taskId) { diff --git a/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs b/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs index 46f7c8f354..7be761e773 100644 --- a/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/TaskOperations.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using ApiService.OneFuzzLib.Orm; using Microsoft.Extensions.Caching.Memory; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; public interface ITaskOperations : IStatefulOrm { @@ -42,7 +42,7 @@ public interface ITaskOperations : IStatefulOrm { public class TaskOperations : StatefulOrm, ITaskOperations { private readonly IMemoryCache _cache; - public TaskOperations(ILogTracer log, IMemoryCache cache, IOnefuzzContext context) + public TaskOperations(ILogger log, IMemoryCache cache, IOnefuzzContext context) : base(log, context) { _cache = cache; } @@ -101,7 +101,7 @@ public IAsyncEnumerable SearchExpired() { public async Async.Task MarkStopping(Task task, string reason) { if (task.State.ShuttingDown()) { - _logTracer.Verbose($"ignoring post - task stop calls to stop {task.JobId:Tag:JobId}:{task.TaskId:Tag:TaskId}"); + _logTracer.LogDebug("ignoring post - task stop calls to stop {JobId}:{TaskId}", task.JobId, task.TaskId); return; } @@ -121,7 +121,7 @@ public async Async.Task MarkFailed(Task task, Error error, List? taskInJob return; } - _logTracer.Info($"task failed {task.JobId:Tag:JobId}:{task.TaskId:Tag:TaskId} - {error:Tag:Error}"); + _logTracer.LogInformation("task failed {JobId}:{TaskId} - {Error}", task.JobId, task.TaskId, error); task = await SetState(task with { Error = error }, TaskState.Stopping); taskInJob ??= await SearchByPartitionKeys(new[] { $"{task.JobId}" }).ToListAsync(); @@ -143,7 +143,14 @@ public async Async.Task SetState(Task task, TaskState state) { if (task.State == state) { return task; } - _logTracer.Event($"SetState Task {task.TaskId:Tag:TaskId} {task.State:Tag:From} - {state:Tag:To}"); + + _logTracer.AddTags(new Dictionary() { + { "TaskId", task.TaskId.ToString()}, + { "From", task.State.ToString()}, + { "To", state.ToString() }, + { "JobId", task.JobId.ToString()} + }); + _logTracer.LogEvent($"SetState Task"); if (task.State == TaskState.Running || task.State == TaskState.SettingUp) { task = await OnStart(task with { State = state }); } else { @@ -152,7 +159,8 @@ public async Async.Task SetState(Task task, TaskState state) { var r = await Replace(task); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"Failed to replace task for job {task.JobId:Tag:JobId} - {task.TaskId:Tag:TaskId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("Failed to replace task for job"); } var _events = _context.Events; @@ -209,11 +217,12 @@ public async Task> Create(TaskConfig config, Guid jobId, Use var r = await _context.TaskOperations.Insert(task); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to insert task {task.TaskId:Tag:TaskId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to insert task {TaskId}", task.TaskId); } await _context.Events.SendEvent(new EventTaskCreated(jobId, task.TaskId, config, userInfo)); - _logTracer.Info($"created task {jobId:Tag:JobId} {task.TaskId:Tag:TaskId} {task.Config.Task.Type:Tag:TaskType}"); + _logTracer.LogInformation("created task {JobId} {TaskId} {TaskType}", jobId, task.TaskId, task.Config.Task.Type); return OneFuzzResult.Ok(task); } @@ -243,14 +252,14 @@ private async Async.Task OnStart(Task task) { var pool = await _context.PoolOperations.GetByName(task.Config.Pool.PoolName); if (!pool.IsOk) { - _logTracer.Info($"unable to find pool from task: {task.TaskId:Tag:TaskId}"); + _logTracer.LogInformation("unable to find pool from task: {TaskId}", task.TaskId); return null; } var scaleset = await _context.ScalesetOperations.SearchByPool(task.Config.Pool.PoolName).FirstOrDefaultAsync(); if (scaleset == null) { - _logTracer.Warning($"no scalesets are defined for task: {task.JobId:Tag:JobId} - {task.TaskId:Tag:TaskId}"); + _logTracer.LogWarning("no scalesets are defined for task: {JobId} - {TaskId}", task.JobId, task.TaskId); return null; } @@ -269,7 +278,7 @@ public async Async.Task CheckPrereqTasks(Task task) { } if (t.JobId != task.JobId) { - _logTracer.Critical($"Tasks with same id {taskId:Tag:TaskId} are not from the same job {t.JobId:Tag:NewTaskJobId} - {task.JobId:Tag:CurrentTaskJobId}"); + _logTracer.LogCritical("Tasks with same id {TaskId} are not from the same job {NewTaskJobId} - {CurrentTaskJobId}", taskId, t.JobId, task.JobId); } if (!t.State.HasStarted()) { @@ -287,8 +296,11 @@ public async Async.Task CheckPrereqTasks(Task task) { if (task.Config.Pool is TaskPool p) { var pool = await _context.PoolOperations.GetByName(p.PoolName); if (!pool.IsOk) { - _logTracer.Info( - $"unable to schedule task to pool [{task.Config.Pool.PoolName:Tag:PoolName}]: {task.TaskId:Tag:TaskId} - {pool.ErrorV:Tag:Error}" + _logTracer.LogInformation( + "unable to schedule task to pool [{PoolName}]: {TaskId} - {Error}", + task.Config.Pool.PoolName, + task.TaskId, + pool.ErrorV ); return null; } @@ -301,8 +313,11 @@ public async Async.Task CheckPrereqTasks(Task task) { await foreach (var scaleset in scalesets) { var pool = await _context.PoolOperations.GetByName(scaleset.PoolName); if (!pool.IsOk) { - _logTracer.Info( - $"unable to schedule task to pool [{scaleset.PoolName:Tag:PoolName}]: {task.TaskId:Tag:TaskId} - {pool.ErrorV:Tag:Error}" + _logTracer.LogInformation( + "unable to schedule task to pool [{PoolName}]: {TaskId} - {Error}", + scaleset.PoolName, + task.TaskId, + pool.ErrorV ); return null; } @@ -311,7 +326,7 @@ public async Async.Task CheckPrereqTasks(Task task) { } } - _logTracer.Warning($"unable to find a scaleset that matches the task prereqs: {task.TaskId:Tag:TaskId}"); + _logTracer.LogWarning("unable to find a scaleset that matches the task prereqs: {TaskId}", task.TaskId); return null; } @@ -322,7 +337,7 @@ public async Async.Task Init(Task task) { public async Async.Task Stopping(Task task) { - _logTracer.Info($"stopping task : {task.JobId:Tag:JobId} - {task.TaskId:Tag:TaskId}"); + _logTracer.LogInformation("stopping task : {JobId} - {TaskId}", task.JobId, task.TaskId); await _context.NodeOperations.StopTask(task.TaskId); var anyRemainingNodes = await _context.NodeTasksOperations.GetNodesByTaskId(task.TaskId).AnyAsync(); if (!anyRemainingNodes) { diff --git a/src/ApiService/ApiService/onefuzzlib/VmOperations.cs b/src/ApiService/ApiService/onefuzzlib/VmOperations.cs index 4f7cbf7b9c..c30b540ead 100644 --- a/src/ApiService/ApiService/onefuzzlib/VmOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/VmOperations.cs @@ -5,7 +5,7 @@ using Azure.ResourceManager.Compute; using Azure.ResourceManager.Compute.Models; using Microsoft.Extensions.Caching.Memory; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; public interface IVmOperations { @@ -30,11 +30,11 @@ public interface IVmOperations { } public class VmOperations : IVmOperations { - private readonly ILogTracer _logTracer; + private readonly ILogger _logTracer; private readonly IMemoryCache _cache; private readonly IOnefuzzContext _context; - public VmOperations(ILogTracer log, IMemoryCache cache, IOnefuzzContext context) { + public VmOperations(ILogger log, IMemoryCache cache, IOnefuzzContext context) { _logTracer = log; _cache = cache; _context = context; @@ -104,16 +104,16 @@ public async Async.Task Delete(Vm vm) { public async Async.Task DeleteVmComponents(string name, Nsg? nsg) { var resourceGroup = _context.Creds.GetBaseResourceGroup(); - _logTracer.Info($"deleting vm components {resourceGroup:Tag:ResourceGroup}:{name:Tag:VmName}"); + _logTracer.LogInformation("deleting vm components {ResourceGroup}:{VmName}", resourceGroup, name); if (await GetVm(name) != null) { - _logTracer.Info($"deleting vm {resourceGroup:Tag:ResourceGroup}:{name:Tag:VmName}"); + _logTracer.LogInformation("deleting vm {ResourceGroup}:{VmName}", resourceGroup, name); await DeleteVm(name); return false; } var nic = await _context.IpOperations.GetPublicNic(resourceGroup, name); if (nic != null) { - _logTracer.Info($"deleting nic {resourceGroup:Tag:ResourceGroup}:{name:Tag:VmName}"); + _logTracer.LogInformation("deleting nic {ResourceGroup}:{VmName}", resourceGroup, name); if (nic.Data.NetworkSecurityGroup != null && nsg != null) { _ = await _context.NsgOperations.DissociateNic(nsg, nic); return false; @@ -123,7 +123,7 @@ public async Async.Task DeleteVmComponents(string name, Nsg? nsg) { } if (await _context.IpOperations.GetIp(resourceGroup, name) != null) { - _logTracer.Info($"deleting ip {resourceGroup:Tag:ResourceGroup}:{name:Tag:VmName}"); + _logTracer.LogInformation("deleting ip {ResourceGroup}:{VmName}", resourceGroup, name); await _context.IpOperations.DeleteIp(resourceGroup, name); return false; } @@ -134,7 +134,7 @@ public async Async.Task DeleteVmComponents(string name, Nsg? nsg) { if (await disks.AnyAsync()) { await foreach (var disk in disks) { - _logTracer.Info($"deleting disk {resourceGroup:Tag:ResourceGroup}:{disk?.Data.Name:Tag:DiskName}"); + _logTracer.LogInformation("deleting disk {ResourceGroup}:{DiskName}", resourceGroup, disk?.Data.Name); _ = await _context.DiskOperations.DeleteDisk(resourceGroup, disk?.Data.Name!); } return false; @@ -144,13 +144,13 @@ public async Async.Task DeleteVmComponents(string name, Nsg? nsg) { } public async System.Threading.Tasks.Task DeleteVm(string name) { - _logTracer.Info($"deleting vm: {_context.Creds.GetBaseResourceGroup():Tag:ResourceGroup} {name:Tag:VmName}"); + _logTracer.LogInformation("deleting vm: {ResourceGroup} {VmName}", _context.Creds.GetBaseResourceGroup(), name); var r = await _context.Creds.GetResourceGroupResource() .GetVirtualMachineAsync(name).Result.Value .DeleteAsync(WaitUntil.Started); if (r.GetRawResponse().IsError) { - _logTracer.Error($"failed to start deletion of vm {name:Tag:VmName} due to {r.GetRawResponse().ReasonPhrase:Tag:Error}"); + _logTracer.LogError("failed to start deletion of vm {VmName} due to {Error}", name, r.GetRawResponse().ReasonPhrase); } return; } @@ -164,8 +164,11 @@ public async Task> AddExtensions(Vm vm, Dictionary Create(Vm vm) { return OneFuzzResultVoid.Ok; } - _logTracer.Info($"vm creating: {vm.Name:Tag:VmName}"); + _logTracer.LogInformation("vm creating: {VmName}", vm.Name); var auth = await _context.SecretsOperations.GetSecretValue(vm.Auth); if (auth == null) { @@ -220,7 +223,7 @@ public async Task Create(Vm vm) { ); return (await vm.Value.GetVirtualMachineExtensionAsync(extensionName)).Value.Data; } catch (RequestFailedException ex) { - _logTracer.Info($"extension does not exist {ex.Message:Tag:Error}"); + _logTracer.LogInformation("extension does not exist {Error}", ex.Message); return null; } } @@ -232,7 +235,7 @@ private ResourceIdentifier GetVirtualMachineIdentifier(string vmName) vmName); public async Async.Task CreateExtension(string vmName, string extensionName, VirtualMachineExtensionData extension) { - _logTracer.Info($"creating extension: {_context.Creds.GetBaseResourceGroup():Tag:ResourceGroup} - {vmName:Tag:VmName} - {extensionName:Tag:ExtensionName}"); + _logTracer.LogInformation("creating extension: {ResourceGroup} - {VmName} - {ExtensionName}", _context.Creds.GetBaseResourceGroup(), vmName, extensionName); var vm = _context.Creds.ArmClient.GetVirtualMachineResource(GetVirtualMachineIdentifier(vmName)); try { @@ -243,7 +246,7 @@ public async Async.Task CreateExtension(string vmName, string extensionName, Vir } catch (RequestFailedException ex) when (ex.Status == 409 && (ex.Message.Contains("VM is marked for deletion") || ex.Message.Contains("The request failed due to conflict with a concurrent request."))) { - _logTracer.Info($"Tried to create {extensionName:Tag:ExtensionName} for {vmName:Tag:VmName} but failed due to {ex.Message:Tag:Error}"); + _logTracer.LogInformation("Tried to create {ExtensionName} for {VmName} but failed due to {Error}", extensionName, vmName, ex.Message); } return; } @@ -280,7 +283,7 @@ async Task CreateVm( IDictionary? tags ) { var resourceGroup = _context.Creds.GetBaseResourceGroup(); - _logTracer.Info($"creating vm {resourceGroup:Tag:ResourceGroup} - {location:Tag:Location} {name:Tag:VmName}"); + _logTracer.LogInformation("creating vm {ResourceGroup} - {Location} {VmName}", resourceGroup, location, name); var nic = await _context.IpOperations.GetPublicNic(resourceGroup, name); if (nic == null) { @@ -289,7 +292,7 @@ async Task CreateVm( return result; } - _logTracer.Info($"waiting on nic creation for {name:Tag:VmName}"); + _logTracer.LogInformation("waiting on nic creation for {VmName}", name); return OneFuzzResultVoid.Ok; } @@ -351,7 +354,7 @@ async Task CreateVm( tags?.ToList() .ForEach(kvp => { if (!vmParams.Tags.TryAdd(kvp.Key, kvp.Value)) { - _logTracer.Warning($"Failed to add tag {kvp.Key:Tag:Key}:{kvp.Value:Tag:Value} to vm {name:Tag:VmName}"); + _logTracer.LogWarning("Failed to add tag {Key}:{Value} to vm {VmName}", kvp.Key, kvp.Value, name); } }); } diff --git a/src/ApiService/ApiService/onefuzzlib/VmssOperations.cs b/src/ApiService/ApiService/onefuzzlib/VmssOperations.cs index feb0bca51d..9855246949 100644 --- a/src/ApiService/ApiService/onefuzzlib/VmssOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/VmssOperations.cs @@ -7,8 +7,8 @@ using Azure.ResourceManager.Compute.Models; using Azure.ResourceManager.Models; using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Logging; using Microsoft.Rest.Azure; - namespace Microsoft.OneFuzz.Service; public interface IVmssOperations { @@ -47,14 +47,15 @@ Async.Task CreateVmss( } public class VmssOperations : IVmssOperations { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly ICreds _creds; private readonly IServiceConfig _serviceConfig; private readonly IMemoryCache _cache; - public VmssOperations(ILogTracer log, IOnefuzzContext context, IMemoryCache cache) { - _log = log.WithTag("Component", "vmss-operations"); + public VmssOperations(ILogger log, IOnefuzzContext context, IMemoryCache cache) { + _log = log; + _log.AddTag("Component", "vmss-operations"); _creds = context.Creds; _serviceConfig = context.ServiceConfiguration; _cache = cache; @@ -65,7 +66,8 @@ public async Async.Task DeleteVmss(ScalesetId name, bool? forceDeletion = var result = await r.DeleteAsync(WaitUntil.Started, forceDeletion: forceDeletion); var raw = result.GetRawResponse(); if (raw.IsError) { - _log.WithHttpStatus(((HttpStatusCode)raw.Status, raw.ReasonPhrase)).Error($"Failed to delete vmss: {name:Tag:VmssName}"); + _log.AddHttpStatus(((HttpStatusCode)raw.Status, raw.ReasonPhrase)); + _log.LogError("Failed to delete vmss: {VmssName}", name); return false; } else { return true; @@ -87,11 +89,11 @@ public async Async.Task ResizeVmss(ScalesetId name, long capa var patch = new VirtualMachineScaleSetPatch(); patch.Sku.Capacity = capacity; try { - _log.Info($"updating VM count {name:Tag:VmssName} - {capacity:Tag:Count}"); + _log.LogInformation("updating VM count {VmssName} - {Count}", name, capacity); _ = await scalesetResource.UpdateAsync(WaitUntil.Started, patch); return OneFuzzResultVoid.Ok; } catch (RequestFailedException ex) { - _log.Exception(ex, $"failed to update VM counts"); + _log.LogError(ex, "failed to update VM counts"); return OneFuzzResultVoid.Error(ErrorCode.UNABLE_TO_RESIZE, "vmss resize failed"); } } else { @@ -120,7 +122,7 @@ private VirtualMachineScaleSetVmResource GetVmssVmResource(ScalesetId name, stri public async Async.Task GetVmss(ScalesetId name) { try { var res = await GetVmssResource(name).GetAsync(); - _log.Verbose($"getting vmss: {name:Tag:VmssName}"); + _log.LogDebug("getting vmss: {VmssName}", name); return res.Value.Data; } catch (RequestFailedException ex) when (ex.Status == 404) { return null; @@ -152,12 +154,12 @@ public async Async.Task UpdateExtensions(ScalesetId name, ILi patch.VirtualMachineProfile.ExtensionProfile.Extensions.Add(ext); } try { - _log.Info($"updating extensions of scaleset: {name:Tag:VmssName}"); + _log.LogInformation("updating extensions of scaleset: {VmssName}", name); _ = await res.UpdateAsync(WaitUntil.Started, patch); - _log.Info($"VM extensions updated: {name:Tag:VmssName}"); + _log.LogInformation("VM extensions updated: {VmssName}", name); return OneFuzzResultVoid.Ok; } catch (RequestFailedException ex) { - _log.Exception(ex, $"failed to update scaleset extensions"); + _log.LogError(ex, "failed to update scaleset extensions"); return OneFuzzResultVoid.Error(ErrorCode.VM_UPDATE_FAILED, "vmss patch failed"); } } else { @@ -166,7 +168,7 @@ public async Async.Task UpdateExtensions(ScalesetId name, ILi } public async Async.Task> ListInstanceIds(ScalesetId name) { - _log.Verbose($"get instance IDs for scaleset {name:Tag:VmssName}"); + _log.LogDebug("get instance IDs for scaleset {VmssName}", name); try { var results = new Dictionary(); await foreach (var instance in GetVmssResource(name).GetVirtualMachineScaleSetVms()) { @@ -174,13 +176,13 @@ public async Async.Task> ListInstanceIds(ScalesetId na if (Guid.TryParse(instance.Data.VmId, out var machineId)) { results[machineId] = instance.Data.InstanceId; } else { - _log.Error($"failed to convert vmId {instance.Data.VmId:Tag:VmId} to Guid in {name:Tag:VmssName}"); + _log.LogError("failed to convert vmId {VmId} to Guid in {VmssName}", instance.Data.VmId, name); } } } return results; } catch (RequestFailedException ex) when (ex.Status == 404) { - _log.Verbose($"scaleset does not exist {name:Tag:VmssName}"); + _log.LogDebug("scaleset does not exist {VmssName}", name); return new Dictionary(); } } @@ -215,7 +217,7 @@ private Task GetInstanceIdForVmId(ScalesetId scaleset, Guid vmId) })!; // NULLABLE: only this method inserts InstanceIdKey so it cannot be null public async Async.Task> GetInstanceVm(ScalesetId name, Guid vmId) { - _log.Info($"get instance ID for scaleset node: {name:Tag:VmssName}:{vmId:Tag:VmId}"); + _log.LogInformation("get instance ID for scaleset node: {VmssName}:{VmId}", name, vmId); var instanceId = await GetInstanceId(name, vmId); if (!instanceId.IsOk) { return instanceId.ErrorV; @@ -226,7 +228,7 @@ public async Async.Task> GetInst var response = await resource.GetAsync(); return OneFuzzResult.Ok(response.Value); } catch (Exception ex) when (ex is RequestFailedException || ex is CloudException) { - _log.Exception(ex, $"unable to find vm instance: {name:Tag:VmssName}:{vmId:Tag:VmId}"); + _log.LogError(ex, "unable to find vm instance: {VmssName}:{VmId}", name, vmId); return OneFuzzResult.Error(ErrorCode.UNABLE_TO_FIND, $"unable to find vm instance: {name}:{instanceId}"); } } @@ -257,7 +259,7 @@ public async Async.Task UpdateScaleInProtection(Scaleset scal } catch (RequestFailedException ex) when (ex.Status == 400 && ex.Message.Contains("reached its limit") && ex.Message.Contains("Upgrade the VMs to the latest model")) { return OneFuzzResultVoid.Error(ErrorCode.UNABLE_TO_UPDATE, $"VMSS has reached model limit. Could not update scaling protection for scaleset {scaleset.ScalesetId}."); } catch (Exception ex) { - _log.Exception(ex, $"unable to set protection policy on: {instanceId:Tag:InstanceId} in vmss {scaleset.ScalesetId:Tag:ScalesetId}"); + _log.LogError(ex, "unable to set protection policy on: {InstanceId} in vmss {ScalesetId}", instanceId, scaleset.ScalesetId); return OneFuzzResultVoid.Error(ErrorCode.UNABLE_TO_UPDATE, $"unable to set protection policy on: {instanceId} in vmss {scaleset.ScalesetId}"); } @@ -281,7 +283,7 @@ public async Async.Task CreateVmss( return OneFuzzResultVoid.Ok; } - _log.Info($"creating VM name: {name:Tag:VmssName} {vmSku:Tag:VmSku} {vmCount:Tag:VmCount} {image:Tag:Image} {networkId:Tag:Subnet} {spotInstance:Tag:SpotInstance}"); + _log.LogInformation("creating VM name: {VmssName} {VmSku} {VmCount} {Image} {Subnet} {SpotInstance}", name, vmSku, vmCount, image, networkId, spotInstance); var getOsResult = await image.GetOs(_cache, _creds.ArmClient, location); if (!getOsResult.IsOk) { return getOsResult.ErrorV; @@ -386,13 +388,13 @@ public async Async.Task CreateVmss( var rg = _creds.GetResourceGroupResource(); var createUpdate = await rg.GetVirtualMachineScaleSets().CreateOrUpdateAsync(WaitUntil.Started, name.ToString(), vmssData); if (createUpdate.GetRawResponse().IsError) { - _log.Error($"Failed to create new scaleset due to {createUpdate.GetRawResponse().ReasonPhrase:Tag:Error}"); + _log.LogError("Failed to create new scaleset due to {Error}", createUpdate.GetRawResponse().ReasonPhrase); return OneFuzzResultVoid.Error(ErrorCode.VM_CREATE_FAILED, new[] { $"Failed to create new scaleset due to {createUpdate.GetRawResponse().ReasonPhrase}" }); } else { return OneFuzzResultVoid.Ok; } } catch (Exception ex) { - _log.Exception(ex); + _log.LogError(ex, "CreateVm"); return OneFuzzResultVoid.Error(ErrorCode.VM_CREATE_FAILED, new[] { ex.Message }); } } @@ -454,7 +456,7 @@ private async Async.Task> ResolveInstanceIds(ScalesetId scaleset if (lookup.TryGetValue(node.MachineId, out var foundId)) { _ = instanceIds.Add(foundId); } else { - _log.Info($"unable to find instance ID for {scalesetId:Tag:ScalesetId} - {node.MachineId:Tag:VmId}"); + _log.LogInformation("unable to find instance ID for {ScalesetId} - {VmId}", scalesetId, node.MachineId); } } @@ -485,15 +487,15 @@ public async Async.Task ReimageNodes(ScalesetId scalesetId, I // The expectation is that these requests are queued and handled subsequently. // The VMSS Team confirmed this expectation and testing supports it, as well. try { - _log.Info($"upgrading VMSS nodes - name: {scalesetId:Tag:ScalesetId} ids: {string.Join(", ", instanceIds):Tag:InstanceIds}"); + _log.LogInformation("upgrading VMSS nodes - name: {ScalesetId} ids: {InstanceIds}", scalesetId, string.Join(", ", instanceIds)); var r = await vmssResource.UpdateInstancesAsync( WaitUntil.Started, new VirtualMachineScaleSetVmInstanceRequiredIds(instanceIds)); if (r.GetRawResponse().IsError) { - _log.Error($"failed to start upgrade instance for scaleset {scalesetId:Tag:ScalesetId} due to {r.GetRawResponse().ReasonPhrase:Tag:Error}"); + _log.LogError("failed to start upgrade instance for scaleset {ScalesetId} due to {Error}", scalesetId, r.GetRawResponse().ReasonPhrase); } } catch (RequestFailedException ex) { - _log.Exception(ex, $"failed to upgrade scaleset instances"); + _log.LogError(ex, "failed to upgrade scaleset instances"); } // very weird API here… @@ -502,13 +504,13 @@ public async Async.Task ReimageNodes(ScalesetId scalesetId, I reqInstanceIds.InstanceIds.Add(instanceId); } try { - _log.Info($"reimaging VMSS nodes: {scalesetId:Tag:ScalesetId} - {string.Join(", ", instanceIds):Tag:InstanceIds}"); + _log.LogInformation("reimaging VMSS nodes: {ScalesetId} - {InstanceIds}", scalesetId, string.Join(", ", instanceIds)); var r = await vmssResource.ReimageAllAsync(WaitUntil.Started, reqInstanceIds); if (r.GetRawResponse().IsError) { - _log.Error($"failed to start reimage all for scaleset {scalesetId:Tag:ScalesetId} due to {r.GetRawResponse().ReasonPhrase:Tag:Error}"); + _log.LogError("failed to start reimage all for scaleset {ScalesetId} due to {Error}", scalesetId, r.GetRawResponse().ReasonPhrase); } } catch (RequestFailedException ex) { - _log.Exception(ex, $"failed to reimage scaleset instances"); + _log.LogError(ex, "failed to reimage scaleset instances"); } return OneFuzzResultVoid.Ok; @@ -517,7 +519,7 @@ public async Async.Task ReimageNodes(ScalesetId scalesetId, I public async Async.Task DeleteNodes(ScalesetId scalesetId, IEnumerable nodes) { var result = await CheckCanUpdate(scalesetId); if (!result.IsOk) { - _log.Warning($"cannot delete nodes from scaleset {scalesetId} : {result.ErrorV}"); + _log.LogWarning("cannot delete nodes from scaleset {scalesetId} : {error}", scalesetId, result.ErrorV); return OneFuzzResultVoid.Error(result.ErrorV); } @@ -534,13 +536,13 @@ public async Async.Task DeleteNodes(ScalesetId scalesetId, IE var computeClient = _creds.ArmClient; var vmssResource = computeClient.GetVirtualMachineScaleSetResource(vmssId); - _log.Info($"deleting scaleset VMs - name: {scalesetId:Tag:ScalesetId} - {instanceIds:Tag:InstanceIds}"); + _log.LogInformation("deleting scaleset VMs - name: {ScalesetId} - {InstanceIds}", scalesetId, instanceIds); var r = await vmssResource.DeleteInstancesAsync( WaitUntil.Started, new VirtualMachineScaleSetVmInstanceRequiredIds(instanceIds)); if (r.GetRawResponse().IsError) { - _log.Error($"failed to start deletion of scaleset {scalesetId:Tag:ScalesetId} due to {r.GetRawResponse().ReasonPhrase:Tag:Error}"); + _log.LogError("failed to start deletion of scaleset {ScalesetId} due to {Error}", scalesetId, r.GetRawResponse().ReasonPhrase); } return OneFuzzResultVoid.Ok; } diff --git a/src/ApiService/ApiService/onefuzzlib/WebhookOperations.cs b/src/ApiService/ApiService/onefuzzlib/WebhookOperations.cs index 8635fb6ce9..a9619707bb 100644 --- a/src/ApiService/ApiService/onefuzzlib/WebhookOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/WebhookOperations.cs @@ -4,8 +4,8 @@ using System.Text.Json; using System.Threading.Tasks; using ApiService.OneFuzzLib.Orm; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service; public interface IWebhookOperations : IOrm { @@ -21,7 +21,7 @@ public class WebhookOperations : Orm, IWebhookOperations { private readonly IHttpClientFactory _httpFactory; - public WebhookOperations(IHttpClientFactory httpFactory, ILogTracer log, IOnefuzzContext context) + public WebhookOperations(IHttpClientFactory httpFactory, ILogger log, IOnefuzzContext context) : base(log, context) { _httpFactory = httpFactory; } @@ -51,14 +51,17 @@ private async Async.Task AddEvent(Webhook webhook, DownloadableEventMessage even var r = await _context.WebhookMessageLogOperations.Replace(message); if (!r.IsOk) { if (r.ErrorV.Reason.Contains("The entity is larger than the maximum allowed size") && eventMessage.Event is ITruncatable truncatableEvent) { - _logTracer.WithTags(tags).Warning($"The WebhookMessageLog was too long for Azure Table. Truncating event data and trying again."); + _logTracer.AddTags(tags); + _logTracer.LogWarning("The WebhookMessageLog was too long for Azure Table. Truncating event data and trying again."); message = message with { Event = truncatableEvent.Truncate(1000) }; r = await _context.WebhookMessageLogOperations.Replace(message); } if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).WithTags(tags).Error($"Failed to replace webhook message log {webhook.WebhookId:Tag:WebhookId} - {eventMessage.EventId:Tag:EventId}"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.AddTags(tags); + _logTracer.LogError("Failed to replace webhook message log {WebhookId} - {EventId}", webhook.WebhookId, eventMessage.EventId); } } @@ -79,7 +82,8 @@ public async Async.Task Send(WebhookMessageLog messageLog) { ("EventType", messageLog.EventType.ToString()) }; - _logTracer.WithTags(tags).Error($"Failed to build message for webhook."); + _logTracer.AddTags(tags); + _logTracer.LogError("Failed to build message for webhook."); return OneFuzzResultVoid.Error(messageResult.ErrorV); } @@ -93,19 +97,19 @@ public async Async.Task Send(WebhookMessageLog messageLog) { using var httpClient = _httpFactory.CreateClient(); var client = new Request(httpClient); - _logTracer.Info($"{messageLog.WebhookId:Tag:WebhookId} - {data}"); + _logTracer.LogInformation("{WebhookId} - {data}", messageLog.WebhookId, data); using var response = await client.Post(url: webhook.Url, json: data, headers: headers); if (response.IsSuccessStatusCode) { - _logTracer.Info($"Successfully sent webhook: {messageLog.WebhookId:Tag:WebhookId}"); + _logTracer.LogInformation("Successfully sent webhook: {WebhookId}", messageLog.WebhookId); return OneFuzzResultVoid.Ok; } _logTracer - .WithTags(new List<(string, string)> { + .AddTags(new List<(string, string)> { ("StatusCode", response.StatusCode.ToString()), ("Content", await response.Content.ReadAsStringAsync()) - }) - .Info($"Webhook not successful"); + }); + _logTracer.LogInformation("Webhook not successful"); return OneFuzzResultVoid.Error(ErrorCode.UNABLE_TO_SEND, $"Webhook not successful. Status Code: {response.StatusCode}"); } @@ -178,7 +182,7 @@ public class WebhookMessageLogOperations : Orm, IWebhookMessa const int MAX_TRIES = 5; - public WebhookMessageLogOperations(ILogTracer log, IOnefuzzContext context) + public WebhookMessageLogOperations(ILogger log, IOnefuzzContext context) : base(log, context) { } @@ -194,10 +198,10 @@ public async Async.Task QueueWebhook(WebhookMessageLog webhookLog) { }; if (visibilityTimeout == null) { - _logTracer.Error($"invalid WebhookMessage queue state, not queuing. {webhookLog.WebhookId:Tag:WebhookId}:{webhookLog.EventId:Tag:EventId} - {webhookLog.State:Tag:State}"); + _logTracer.LogError("invalid WebhookMessage queue state, not queuing. {WebhookId}:{EventId} - {State}", webhookLog.WebhookId, webhookLog.EventId, webhookLog.State); } else { if (!await _context.Queue.QueueObject("webhooks", obj, StorageType.Config, visibilityTimeout: visibilityTimeout)) { - _logTracer.Warning($"failed to queue object {webhookLog.WebhookId:Tag:WebhookId}:{webhookLog.EventId:Tag:EventId}"); + _logTracer.LogWarning("failed to queue object {WebhookId}:{EventId}", webhookLog.WebhookId, webhookLog.EventId); } } } @@ -206,7 +210,7 @@ public async Async.Task ProcessFromQueue(WebhookMessageQueueObj obj) { var message = await GetWebhookMessageById(obj.WebhookId, obj.EventId); if (message == null) { - _logTracer.Error($"webhook message log not found for webhookId: {obj.WebhookId:Tag:WebhookId} and eventId: {obj.EventId:Tag:EventId}"); + _logTracer.LogError("webhook message log not found for webhookId: {WebhookId} and eventId: {EventId}", obj.WebhookId, obj.EventId); } else { await Process(message); } @@ -215,54 +219,57 @@ public async Async.Task ProcessFromQueue(WebhookMessageQueueObj obj) { private async Async.Task Process(WebhookMessageLog message) { if (message.State == WebhookMessageState.Failed || message.State == WebhookMessageState.Succeeded) { - _logTracer.Error($"webhook message already handled. {message.WebhookId:Tag:WebhookId}:{message.EventId:Tag:EventId}"); + _logTracer.LogError("webhook message already handled. {WebhookId}:{EventId}", message.WebhookId, message.EventId); return; } var newMessage = message with { TryCount = message.TryCount + 1 }; - _logTracer.Info($"sending webhook: {message.WebhookId:Tag:WebhookId}:{message.EventId:Tag:EventId}"); + _logTracer.LogInformation("sending webhook: {WebhookId}:{EventId}", message.WebhookId, message.EventId); var success = await Send(newMessage); if (success) { newMessage = newMessage with { State = WebhookMessageState.Succeeded }; var r = await Replace(newMessage); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to replace webhook message with {newMessage.WebhookId:Tag:WebhookId}:{newMessage.EventId:Tag:EventId} with Succeeded"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to replace webhook message with {WebhookId}:{EventId} with Succeeded", newMessage.WebhookId, newMessage.EventId); } - _logTracer.Info($"sent webhook event {newMessage.WebhookId}:{newMessage.EventId}"); + _logTracer.LogInformation("sent webhook event {WebhookId}:{EventId}", newMessage.WebhookId, newMessage.EventId); } else if (newMessage.TryCount < MAX_TRIES) { newMessage = newMessage with { State = WebhookMessageState.Retrying }; var r = await Replace(newMessage); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to replace webhook message with {newMessage.WebhookId:Tag:WebhookId}:{newMessage.EventId:Tag:EventId} with Retrying"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to replace webhook message with {WebhookId}:{EventId} with Retrying", newMessage.WebhookId, newMessage.EventId); } await QueueWebhook(newMessage); - _logTracer.Warning($"sending webhook event failed, re-queued {newMessage.WebhookId:Tag:WebhookId}:{newMessage.EventId:Tag:EventId}"); + _logTracer.LogWarning("sending webhook event failed, re-queued {WebhookId}:{EventId}", newMessage.WebhookId, newMessage.EventId); } else { newMessage = newMessage with { State = WebhookMessageState.Failed }; var r = await Replace(newMessage); if (!r.IsOk) { - _logTracer.WithHttpStatus(r.ErrorV).Error($"failed to replace webhook message with EventId {newMessage.WebhookId:Tag:WebhookId}:{newMessage.EventId:Tag:EventId} with Failed"); + _logTracer.AddHttpStatus(r.ErrorV); + _logTracer.LogError("failed to replace webhook message with EventId {WebhookId}:{EventId} with Failed", newMessage.WebhookId, newMessage.EventId); } - _logTracer.Info($"sending webhook: {newMessage.WebhookId:Tag:WebhookId} event: {newMessage.EventId:Tag:EventId} failed {newMessage.TryCount:Tag:TryCount} times."); + _logTracer.LogInformation("sending webhook: {WebhookId} event: {EventId} failed {TryCount} times.", newMessage.WebhookId, newMessage.EventId, newMessage.TryCount); } } private async Async.Task Send(WebhookMessageLog message) { - var log = _logTracer.WithTag("WebhookId", message.WebhookId.ToString()); + _logTracer.AddTag("WebhookId", message.WebhookId.ToString()); var webhook = await _context.WebhookOperations.GetByWebhookId(message.WebhookId); if (webhook == null) { - log.Error($"webhook not found for webhookId: {message.WebhookId:Tag:WebhookId}"); + _logTracer.LogError("webhook not found for webhookId: {WebhookId}", message.WebhookId); return false; } try { var sendResult = await _context.WebhookOperations.Send(message); if (!sendResult.IsOk) { - _logTracer.Error(sendResult.ErrorV); + _logTracer.LogError("Send webhook:{error}", sendResult.ErrorV); } return sendResult.IsOk; } catch (Exception exc) { - log.Exception(exc); + _logTracer.LogError(exc, "Send Webhook"); return false; } diff --git a/src/ApiService/ApiService/onefuzzlib/notifications/Ado.cs b/src/ApiService/ApiService/onefuzzlib/notifications/Ado.cs index 5c40c57d9b..7322a5dc51 100644 --- a/src/ApiService/ApiService/onefuzzlib/notifications/Ado.cs +++ b/src/ApiService/ApiService/onefuzzlib/notifications/Ado.cs @@ -1,10 +1,10 @@ using System.Text.Json; +using Microsoft.Extensions.Logging; using Microsoft.TeamFoundation.WorkItemTracking.WebApi; using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models; using Microsoft.VisualStudio.Services.Common; using Microsoft.VisualStudio.Services.WebApi; using Microsoft.VisualStudio.Services.WebApi.Patch.Json; - namespace Microsoft.OneFuzz.Service; public interface IAdo { @@ -12,13 +12,13 @@ public interface IAdo { } public class Ado : NotificationsBase, IAdo { - public Ado(ILogTracer logTracer, IOnefuzzContext context) : base(logTracer, context) { + public Ado(ILogger logTracer, IOnefuzzContext context) : base(logTracer, context) { } public async Async.Task NotifyAdo(AdoTemplate config, Container container, IReport reportable, bool isLastRetryAttempt, Guid notificationId) { var filename = reportable.FileName(); if (reportable is RegressionReport) { - _logTracer.Info($"ado integration does not support regression report. container:{container:Tag:Container} filename:{filename:Tag:Filename}"); + _logTracer.LogInformation("ado integration does not support regression report. container:{Container} filename:{Filename}", container, filename); return OneFuzzResultVoid.Ok; } @@ -27,7 +27,8 @@ public async Async.Task NotifyAdo(AdoTemplate config, Contain (string, string)[] notificationInfo = { ("notification_id", notificationId.ToString()), ("job_id", report.JobId.ToString()), ("task_id", report.TaskId.ToString()), ("ado_project", config.Project), ("ado_url", config.BaseUrl.ToString()), ("container", container.String), ("filename", filename) }; var adoEventType = "AdoNotify"; - _logTracer.WithTags(notificationInfo).Event($"{adoEventType}"); + _logTracer.AddTags(notificationInfo); + _logTracer.LogEvent(adoEventType); try { var ado = await AdoConnector.AdoConnectorCreator(_context, container, filename, config, report, _logTracer); @@ -40,10 +41,10 @@ public async Async.Task NotifyAdo(AdoTemplate config, Contain } if (!isLastRetryAttempt && IsTransient(e)) { - _logTracer.WithTags(notificationInfo).Error($"transient ADO notification failure {report.JobId:Tag:JobId} {report.TaskId:Tag:TaskId} {container:Tag:Container} {filename:Tag:Filename}"); + _logTracer.LogError("transient ADO notification failure {JobId} {TaskId} {Container} {Filename}", report.JobId, report.TaskId, container, filename); throw; } else { - _logTracer.WithTags(notificationInfo).Exception(e, $"Failed to process ado notification"); + _logTracer.LogError(e, "Failed to process ado notification"); await LogFailedNotification(report, e, notificationId); return OneFuzzResultVoid.Error(ErrorCode.NOTIFICATION_FAILURE, $"Failed to process ado notification : exception: {e}"); @@ -126,8 +127,8 @@ sealed class AdoConnector { private readonly string _project; private readonly WorkItemTrackingHttpClient _client; private readonly Uri _instanceUrl; - private readonly ILogTracer _logTracer; - public static async Async.Task AdoConnectorCreator(IOnefuzzContext context, Container container, string filename, AdoTemplate config, Report report, ILogTracer logTracer, Renderer? renderer = null) { + private readonly ILogger _logTracer; + public static async Async.Task AdoConnectorCreator(IOnefuzzContext context, Container container, string filename, AdoTemplate config, Report report, ILogger logTracer, Renderer? renderer = null) { renderer ??= await Renderer.ConstructRenderer(context, container, filename, report, logTracer); var instanceUrl = context.Creds.GetInstanceUrl(); var project = await renderer.Render(config.Project, instanceUrl); @@ -138,7 +139,7 @@ public static async Async.Task AdoConnectorCreator(IOnefuzzContext } - public AdoConnector(AdoTemplate config, Renderer renderer, string project, WorkItemTrackingHttpClient client, Uri instanceUrl, ILogTracer logTracer) { + public AdoConnector(AdoTemplate config, Renderer renderer, string project, WorkItemTrackingHttpClient client, Uri instanceUrl, ILogger logTracer) { _config = config; _renderer = renderer; _project = project; @@ -151,7 +152,7 @@ public async Async.Task Render(string template) { try { return await _renderer.Render(template, _instanceUrl, strictRendering: true); } catch { - _logTracer.Warning($"Failed to render template in strict mode. Falling back to relaxed mode. {template:Template}"); + _logTracer.LogWarning("Failed to render template in strict mode. Falling back to relaxed mode. {Template} ", template); return await _renderer.Render(template, _instanceUrl, strictRendering: false); } } @@ -165,7 +166,8 @@ public async IAsyncEnumerable ExistingWorkItems((string, string)[] not } else if (_config.AdoFields.TryGetValue(key, out var field)) { filter = await Render(field); } else { - _logTracer.WithTags(notificationInfo).Error($"Failed to check for existing work items using the UniqueField Key: {key}. Value is not present in config field AdoFields."); + _logTracer.AddTags(notificationInfo); + _logTracer.LogError("Failed to check for existing work items using the UniqueField Key: {Key}. Value is not present in config field AdoFields.", key); continue; } @@ -211,7 +213,7 @@ public async IAsyncEnumerable ExistingWorkItems((string, string)[] not var single = "'"; parts.Add($"[{key}] {operation.OkV} '{filters[key].Replace(single, single + single)}'"); } else { - _logTracer.Warning(operation.ErrorV); + _logTracer.LogWarning("{error}", operation.ErrorV); } } @@ -241,6 +243,10 @@ public async IAsyncEnumerable ExistingWorkItems((string, string)[] not /// true if the state of the item was modified public async Async.Task UpdateExisting(WorkItem item, (string, string)[] notificationInfo) { + + _logTracer.AddTags(notificationInfo); + _logTracer.AddTag("ItemId", (item.Id.HasValue ? item.Id.Value.ToString() : "")); + if (_config.OnDuplicate.Comment != null) { var comment = await Render(_config.OnDuplicate.Comment); _ = await _client.AddCommentAsync( @@ -286,11 +292,11 @@ public async Async.Task UpdateExisting(WorkItem item, (string, string)[] n if (document.Any()) { _ = await _client.UpdateWorkItemAsync(document, _project, (int)item.Id!); var adoEventType = "AdoUpdate"; - _logTracer.WithTags(notificationInfo).Event($"{adoEventType} {item.Id:Tag:WorkItemId}"); + _logTracer.LogEvent(adoEventType); } else { var adoEventType = "AdoNoUpdate"; - _logTracer.WithTags(notificationInfo).Event($"{adoEventType} {item.Id:Tag:WorkItemId}"); + _logTracer.LogEvent(adoEventType); } return stateUpdated; @@ -346,11 +352,19 @@ public async Async.Task Process((string, string)[] notificationInfo) { await foreach (var workItem in ExistingWorkItems(notificationInfo)) { // work items are ordered by id, so the oldest one is the first one oldestWorkItem ??= workItem; - _logTracer.WithTags(new List<(string, string)> { ("MatchingWorkItemIds", $"{workItem.Id}") }).Info($"Found matching work item"); + using (_logTracer.BeginScope("Search matching work items")) { + _logTracer.AddTags(new List<(string, string)> { ("MatchingWorkItemIds", $"{workItem.Id}") }); + _logTracer.LogInformation("Found matching work item"); + } if (IsADODuplicateWorkItem(workItem)) { continue; } - _logTracer.WithTags(new List<(string, string)> { ("NonDuplicateWorkItemId", $"{workItem.Id}") }).Info($"Found matching non-duplicate work item"); + + using (_logTracer.BeginScope("Non-duplicate work item")) { + _logTracer.AddTags(new List<(string, string)> { ("NonDuplicateWorkItemId", $"{workItem.Id}") }); + _logTracer.LogInformation("Found matching non-duplicate work item"); + } + _ = await UpdateExisting(workItem, notificationInfo); updated = true; } @@ -358,8 +372,8 @@ public async Async.Task Process((string, string)[] notificationInfo) { if (!updated) { if (oldestWorkItem != null) { // We have matching work items but all are duplicates - _logTracer.WithTags(notificationInfo) - .Info($"All matching work items were duplicates, re-opening the oldest one"); + _logTracer.AddTags(notificationInfo); + _logTracer.LogInformation($"All matching work items were duplicates, re-opening the oldest one"); var stateChanged = await UpdateExisting(oldestWorkItem, notificationInfo); if (stateChanged) { // add a comment if we re-opened the bug @@ -375,7 +389,9 @@ public async Async.Task Process((string, string)[] notificationInfo) { // We never saw a work item like this before, it must be new var entry = await CreateNew(); var adoEventType = "AdoNewItem"; - _logTracer.WithTags(notificationInfo).Event($"{adoEventType} {entry.Id:Tag:WorkItemId}"); + _logTracer.AddTags(notificationInfo); + _logTracer.AddTag("WorkItemId", entry.Id.HasValue ? entry.Id.Value.ToString() : ""); + _logTracer.LogEvent(adoEventType); } } } diff --git a/src/ApiService/ApiService/onefuzzlib/notifications/GithubIssues.cs b/src/ApiService/ApiService/onefuzzlib/notifications/GithubIssues.cs index a23bfd1b33..6d4e6e04a7 100644 --- a/src/ApiService/ApiService/onefuzzlib/notifications/GithubIssues.cs +++ b/src/ApiService/ApiService/onefuzzlib/notifications/GithubIssues.cs @@ -1,5 +1,5 @@ -using Octokit; - +using Microsoft.Extensions.Logging; +using Octokit; namespace Microsoft.OneFuzz.Service; public interface IGithubIssues { @@ -8,14 +8,14 @@ public interface IGithubIssues { public class GithubIssues : NotificationsBase, IGithubIssues { - public GithubIssues(ILogTracer logTracer, IOnefuzzContext context) + public GithubIssues(ILogger logTracer, IOnefuzzContext context) : base(logTracer, context) { } public async Async.Task GithubIssue(GithubIssuesTemplate config, Container container, IReport reportable, Guid notificationId) { var filename = reportable.FileName(); if (reportable is RegressionReport) { - _logTracer.Info($"github issue integration does not support regression reports. {container:Tag:Container} - {filename:Tag:Filename}"); + _logTracer.LogInformation("github issue integration does not support regression reports. {Container} - {Filename}", container, filename); return; } @@ -73,9 +73,9 @@ sealed class GithubConnnector { private readonly GithubIssuesTemplate _config; private readonly Renderer _renderer; private readonly Uri _instanceUrl; - private readonly ILogTracer _logTracer; + private readonly ILogger _logTracer; - public static async Async.Task GithubConnnectorCreator(GithubIssuesTemplate config, Container container, string filename, Renderer renderer, Uri instanceUrl, IOnefuzzContext context, ILogTracer logTracer) { + public static async Async.Task GithubConnnectorCreator(GithubIssuesTemplate config, Container container, string filename, Renderer renderer, Uri instanceUrl, IOnefuzzContext context, ILogger logTracer) { var auth = await context.SecretsOperations.GetSecretValue(config.Auth.Secret); if (auth == null) { throw new Exception($"Failed to retrieve the auth info for {config}"); @@ -83,7 +83,7 @@ public static async Async.Task GithubConnnectorCreator(GithubI return new GithubConnnector(config, renderer, instanceUrl, auth, logTracer); } - public GithubConnnector(GithubIssuesTemplate config, Renderer renderer, Uri instanceUrl, GithubAuth auth, ILogTracer logTracer) { + public GithubConnnector(GithubIssuesTemplate config, Renderer renderer, Uri instanceUrl, GithubAuth auth, ILogger logTracer) { _config = config; _gh = GetGitHubClient(auth.User, auth.PersonalAccessToken); _renderer = renderer; @@ -104,7 +104,7 @@ private async Async.Task Render(string field) { try { return await _renderer.Render(field, _instanceUrl, strictRendering: true); } catch { - _logTracer.Warning($"Failed to render field in strict mode. Falling back to relaxed mode. {field:Field}"); + _logTracer.LogWarning("Failed to render field in strict mode. Falling back to relaxed mode. {Field}", field); return await _renderer.Render(field, _instanceUrl, strictRendering: false); } } @@ -148,7 +148,7 @@ await Render(_config.UniqueSearch.str), } private async Async.Task Update(Issue issue) { - _logTracer.Info($"updating issue: {issue}"); + _logTracer.LogInformation("updating issue: {Issue}", issue); if (_config.OnDuplicate.Comment != null) { _ = await _gh.Issue.Comment.Create(issue.Repository.Id, issue.Number, await Render(_config.OnDuplicate.Comment)); } @@ -167,7 +167,7 @@ private async Async.Task Update(Issue issue) { } private async Async.Task Create() { - _logTracer.Info($"creating issue"); + _logTracer.LogInformation("creating issue"); var assignees = await _config.Assignees.ToAsyncEnumerable() .SelectAwait(async assignee => await Render(assignee)) .ToListAsync(); diff --git a/src/ApiService/ApiService/onefuzzlib/notifications/JinjaTemplateAdapter.cs b/src/ApiService/ApiService/onefuzzlib/notifications/JinjaTemplateAdapter.cs index a145869bd2..94c9f824d6 100644 --- a/src/ApiService/ApiService/onefuzzlib/notifications/JinjaTemplateAdapter.cs +++ b/src/ApiService/ApiService/onefuzzlib/notifications/JinjaTemplateAdapter.cs @@ -1,4 +1,5 @@ -namespace Microsoft.OneFuzz.Service; +using Microsoft.Extensions.Logging; +namespace Microsoft.OneFuzz.Service; public class JinjaTemplateAdapter { public static bool IsJinjaTemplate(string jinjaTemplate) { @@ -12,7 +13,7 @@ public static string AdaptForScriban(string jinjaTemplate) { .Replace("%}", "}}"); } - public static async Async.Task IsValidScribanNotificationTemplate(IOnefuzzContext context, ILogTracer log, NotificationTemplate template) { + public static async Async.Task IsValidScribanNotificationTemplate(IOnefuzzContext context, ILogger log, NotificationTemplate template) { try { var (didModify, _) = template switch { TeamsTemplate => (false, template), @@ -26,12 +27,12 @@ public static async Async.Task IsValidScribanNotificationTemplate(IOnefuzz } return false; } catch (Exception e) { - log.Exception(e); + log.LogError(e, "IsValidScribanNotificationTemplate"); return false; } } - public static async Async.Task ValidateScribanTemplate(IOnefuzzContext context, ILogTracer log, TemplateRenderContext? renderContext, string template) { + public static async Async.Task ValidateScribanTemplate(IOnefuzzContext context, ILogger log, TemplateRenderContext? renderContext, string template) { var instanceUrl = context.ServiceConfiguration.OneFuzzInstance!; var (renderer, templateRenderContext) = await GenerateTemplateRenderContext(context, log, renderContext); @@ -44,11 +45,11 @@ public static async Async.Task ValidateScribanTempla ); } - private static async Async.Task<(NotificationsBase.Renderer, TemplateRenderContext)> GenerateTemplateRenderContext(IOnefuzzContext context, ILogTracer log, TemplateRenderContext? templateRenderContext) { + private static async Async.Task<(NotificationsBase.Renderer, TemplateRenderContext)> GenerateTemplateRenderContext(IOnefuzzContext context, ILogger log, TemplateRenderContext? templateRenderContext) { if (templateRenderContext != null) { - log.Info($"Using custom TemplateRenderContext"); + log.LogInformation("Using custom TemplateRenderContext"); } else { - log.Info($"Generating TemplateRenderContext"); + log.LogInformation("Generating TemplateRenderContext"); } var targetUrl = templateRenderContext?.TargetUrl ?? new Uri("https://example.com/targetUrl"); @@ -239,7 +240,7 @@ public static async Async.Task ValidateScribanTempla return (renderer, templateRenderContext); } - public async static Async.Task<(bool didModify, AdoTemplate template)> ConvertToScriban(AdoTemplate template, bool attemptRender = false, IOnefuzzContext? context = null, ILogTracer? log = null) { + public async static Async.Task<(bool didModify, AdoTemplate template)> ConvertToScriban(AdoTemplate template, bool attemptRender = false, IOnefuzzContext? context = null, ILogger? log = null) { if (attemptRender) { context = context.EnsureNotNull("Required to render"); log = log.EnsureNotNull("Required to render"); @@ -310,7 +311,7 @@ public static async Async.Task ValidateScribanTempla return (didModify, template); } - public async static Async.Task<(bool didModify, GithubIssuesTemplate template)> ConvertToScriban(GithubIssuesTemplate template, bool attemptRender = false, IOnefuzzContext? context = null, ILogTracer? log = null) { + public async static Async.Task<(bool didModify, GithubIssuesTemplate template)> ConvertToScriban(GithubIssuesTemplate template, bool attemptRender = false, IOnefuzzContext? context = null, ILogger? log = null) { if (attemptRender) { context = context.EnsureNotNull("Required to render"); log = log.EnsureNotNull("Required to render"); diff --git a/src/ApiService/ApiService/onefuzzlib/notifications/NotificationsBase.cs b/src/ApiService/ApiService/onefuzzlib/notifications/NotificationsBase.cs index 9ff790bda5..44a3ecad28 100644 --- a/src/ApiService/ApiService/onefuzzlib/notifications/NotificationsBase.cs +++ b/src/ApiService/ApiService/onefuzzlib/notifications/NotificationsBase.cs @@ -1,4 +1,5 @@ using System.IO; +using Microsoft.Extensions.Logging; using Scriban; using Scriban.Runtime; @@ -7,16 +8,16 @@ namespace Microsoft.OneFuzz.Service; public abstract class NotificationsBase { #pragma warning disable CA1051 // permit visible instance fields - protected readonly ILogTracer _logTracer; + protected readonly ILogger _logTracer; protected readonly IOnefuzzContext _context; #pragma warning restore CA1051 - public NotificationsBase(ILogTracer logTracer, IOnefuzzContext context) { + public NotificationsBase(ILogger logTracer, IOnefuzzContext context) { _logTracer = logTracer; _context = context; } public async Async.Task LogFailedNotification(Report report, Exception error, Guid notificationId) { - _logTracer.Error($"notification failed: notification_id:{notificationId:Tag:NotificationId} job_id:{report.JobId:Tag:JobId} task_id:{report.TaskId:Tag:TaskId} err:{error.Message:Tag:Error}"); + _logTracer.LogError("notification failed: notification_id:{NotificationId} job_id:{JobId} task_id:{TaskId} err:{Error}", notificationId, report.JobId, report.TaskId, error.Message); Error? err = Error.Create(ErrorCode.NOTIFICATION_FAILURE, $"{error}"); await _context.Events.SendEvent(new EventNotificationFailed( NotificationId: notificationId, @@ -48,7 +49,7 @@ public static async Async.Task ConstructRenderer( Container container, string filename, Report report, - ILogTracer log, + ILogger log, Task? task = null, Job? job = null, Uri? targetUrl = null, @@ -77,7 +78,7 @@ public static async Async.Task ConstructRenderer( } var scribanOnlyFeatureFlag = await context.FeatureManagerSnapshot.IsEnabledAsync(FeatureFlagConstants.RenderOnlyScribanTemplates); - log.Info($"ScribanOnlyFeatureFlag: {scribanOnlyFeatureFlag}"); + log.LogInformation("ScribanOnlyFeatureFlag: {scribanOnlyFeatureFlag}", scribanOnlyFeatureFlag); var scribanOnly = scribanOnlyOverride ?? scribanOnlyFeatureFlag; diff --git a/src/ApiService/ApiService/onefuzzlib/notifications/Teams.cs b/src/ApiService/ApiService/onefuzzlib/notifications/Teams.cs index 3cbaed796f..53e810f6d5 100644 --- a/src/ApiService/ApiService/onefuzzlib/notifications/Teams.cs +++ b/src/ApiService/ApiService/onefuzzlib/notifications/Teams.cs @@ -1,6 +1,6 @@ using System.Net.Http; using System.Text.Json; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service; public interface ITeams { @@ -8,11 +8,11 @@ public interface ITeams { } public class Teams : ITeams { - private readonly ILogTracer _logTracer; + private readonly ILogger _logTracer; private readonly IOnefuzzContext _context; private readonly IHttpClientFactory _httpFactory; - public Teams(IHttpClientFactory httpFactory, ILogTracer logTracer, IOnefuzzContext context) { + public Teams(IHttpClientFactory httpFactory, ILogger logTracer, IOnefuzzContext context) { _logTracer = logTracer; _context = context; _httpFactory = httpFactory; @@ -49,7 +49,7 @@ private async Async.Task SendTeamsWebhook(TeamsTemplate config, string title, IL var client = new Request(_httpFactory.CreateClient()); var response = await client.Post(url: new Uri(configUrl!), JsonSerializer.Serialize(message)); if (response == null || !response.IsSuccessStatusCode) { - _logTracer.Error($"webhook failed {notificationId:Tag:NotificationId} {response?.StatusCode:Tag:StatusCode} {response?.Content}"); + _logTracer.LogError("webhook failed {NotificationId} {StatusCode} {content}", notificationId, response?.StatusCode, response?.Content); } } @@ -62,7 +62,7 @@ public async Async.Task NotifyTeams(TeamsTemplate config, Container container, I if (reportOrRegression is Report report) { var task = await _context.TaskOperations.GetByJobIdAndTaskId(report.JobId, report.TaskId); if (task == null) { - _logTracer.Error($"report with invalid task {report.JobId:Tag:JobId}:{report.TaskId:Tag:TaskId}"); + _logTracer.LogError("report with invalid task {JobId}:{TaskId}", report.JobId, report.TaskId); return; } diff --git a/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs b/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs index 9aec4392ad..c5394b12d8 100644 --- a/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs +++ b/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs @@ -5,10 +5,10 @@ using Azure; using Azure.Core; using Azure.Data.Tables; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace ApiService.OneFuzzLib.Orm { public interface IOrm where T : EntityBase { Task GetTableClient(string table, ResourceIdentifier? accountId = null); @@ -38,12 +38,12 @@ public abstract class Orm : IOrm where T : EntityBase { #pragma warning disable CA1051 // permit visible instance fields protected readonly EntityConverter _entityConverter; protected readonly IOnefuzzContext _context; - protected readonly ILogTracer _logTracer; + protected readonly ILogger _logTracer; #pragma warning restore CA1051 const int MAX_TRANSACTION_SIZE = 100; - public Orm(ILogTracer logTracer, IOnefuzzContext context) { + public Orm(ILogger logTracer, IOnefuzzContext context) { _context = context; _logTracer = logTracer; _entityConverter = _context.EntityConverter; @@ -291,7 +291,7 @@ static StatefulOrm() { } - public StatefulOrm(ILogTracer logTracer, IOnefuzzContext context) : base(logTracer, context) { + public StatefulOrm(ILogger logTracer, IOnefuzzContext context) : base(logTracer, context) { } /// @@ -310,7 +310,7 @@ public async Async.Task ProcessStateUpdate(T entity) { if (func != null) { var partitionKey = _partitionKeyGetter?.Invoke(entity); var rowKey = _rowKeyGetter?.Invoke(entity); - _logTracer.Info($"processing state update: {typeof(T):Tag:Type} - {partitionKey:Tag:PartitionKey} {rowKey:Tag:RowKey} - {state:Tag:State}"); + _logTracer.LogInformation("processing state update: {Type} - {PartitionKey} {RowKey} - {State}", typeof(T), partitionKey, rowKey, state); return await func(entity); } else { throw new ArgumentException($"State function for state: '{state}' not found on type {typeof(T)}"); diff --git a/src/ApiService/ApiService/packages.lock.json b/src/ApiService/ApiService/packages.lock.json index a0bce61667..592e322ea1 100644 --- a/src/ApiService/ApiService/packages.lock.json +++ b/src/ApiService/ApiService/packages.lock.json @@ -164,25 +164,26 @@ }, "Microsoft.Azure.Functions.Worker": { "type": "Direct", - "requested": "[1.10.0, )", - "resolved": "1.10.0", - "contentHash": "LBase3J7/ZBaCrAgcTu629tCXleoO+4oft+6Q/F0HL5oc6qFqpMZ5oxMiA34kGXhb9D3A/CghJtNEwiBF1qWCA==", + "requested": "[1.14.1, )", + "resolved": "1.14.1", + "contentHash": "3CUKmg15c7Uv90i6P/96dtId5mj5dqp89btJIsui+CSrm0g8PdjdBi3wmxbqtzcfWIMrGBrqJlvocwI3rINmRg==", "dependencies": { "Azure.Core": "1.10.0", - "Microsoft.Azure.Functions.Worker.Core": "1.8.0", - "Microsoft.Azure.Functions.Worker.Grpc": "1.6.0", + "Microsoft.Azure.Functions.Worker.Core": "1.12.1", + "Microsoft.Azure.Functions.Worker.Grpc": "1.10.1", "Microsoft.Extensions.Hosting": "5.0.0", "Microsoft.Extensions.Hosting.Abstractions": "5.0.0" } }, "Microsoft.Azure.Functions.Worker.ApplicationInsights": { "type": "Direct", - "requested": "[1.0.0-preview3, )", - "resolved": "1.0.0-preview3", - "contentHash": "VCbascK8UUq5FAZF+LsdmQKCL98knfT3ZBq4K757AbrUcgu/E+bTU0GkbQIa2mVuDmo+DJ2emmkqwur7lJZRbg==", + "requested": "[1.0.0-preview4, )", + "resolved": "1.0.0-preview4", + "contentHash": "oX3LX4gOQr8kLoWVbNrXJFldDs3m0YKW2CKu7Nt96BMBThmSx8PdGTwfNX42tDmZ71G6dghoilhXH1oZGiUJfw==", "dependencies": { "Microsoft.ApplicationInsights.WorkerService": "2.21.0", - "Microsoft.Azure.Functions.Worker.Core": "1.8.0" + "Microsoft.Azure.Functions.Worker.Core": "1.11.0", + "Microsoft.Bcl.AsyncInterfaces": "5.0.0" } }, "Microsoft.Azure.Functions.Worker.Extensions.EventGrid": { @@ -235,12 +236,12 @@ }, "Microsoft.Azure.Functions.Worker.Sdk": { "type": "Direct", - "requested": "[1.7.0, )", - "resolved": "1.7.0", - "contentHash": "kJZEtB4EIB3VeXyUxfilXWE6c49rNnIZvPvPBN6tpTvNHqJQrXm7pgsjwmE3Qw2t2EwhDgVdFDckWNbQQnnS1w==", + "requested": "[1.10.0, )", + "resolved": "1.10.0", + "contentHash": "U5N4c87aUvwfhjkox6A97MxM/PfXn3MctegV3VnaMPlVva/gnVMna4e3p2oGaOp/XDvJ1UmnPTcgj50yaKiZpg==", "dependencies": { - "Microsoft.Azure.Functions.Worker.Sdk.Analyzers": "1.1.0", - "Microsoft.Azure.Functions.Worker.Sdk.Generators": "1.0.0-preview1" + "Microsoft.Azure.Functions.Worker.Sdk.Analyzers": "1.1.2", + "Microsoft.Azure.Functions.Worker.Sdk.Generators": "1.1.0-preview2" } }, "Microsoft.Azure.Management.Monitor": { @@ -267,6 +268,16 @@ "System.Net.Http": "4.3.0" } }, + "Microsoft.Extensions.Logging.ApplicationInsights": { + "type": "Direct", + "requested": "[2.21.0, )", + "resolved": "2.21.0", + "contentHash": "tjzErt5oaLs1caaThu6AbtJuHH0oIGDG/rYCXDruHVGig3m8MyCDuwDsGQwzimY7g4aFyLOKfHc3unBN2G96gw==", + "dependencies": { + "Microsoft.ApplicationInsights": "2.21.0", + "Microsoft.Extensions.Logging": "2.1.1" + } + }, "Microsoft.FeatureManagement": { "type": "Direct", "requested": "[2.5.1, )", @@ -560,13 +571,14 @@ }, "Microsoft.Azure.Functions.Worker.Core": { "type": "Transitive", - "resolved": "1.8.0", - "contentHash": "8awXnik71Og7WAKUQLhPAatm236Icf9XAu0oerNCGjfAVjIF6o5U1M7id9V368ZvCsEXN3Ejq0sGRAEzjt/t6A==", + "resolved": "1.12.1", + "contentHash": "O8xCNF2Sh8JTvA/AJ45vil8byOjw2zRTPpFp7a9m1YGJbyt2jhr8fszyQPVZYaJWkIdIRy5+cEZwigA8LoziAQ==", "dependencies": { "Azure.Core": "1.10.0", "Microsoft.Extensions.Hosting": "5.0.0", "Microsoft.Extensions.Hosting.Abstractions": "5.0.0", - "System.Collections.Immutable": "5.0.0" + "System.Collections.Immutable": "5.0.0", + "System.Diagnostics.DiagnosticSource": "7.0.0" } }, "Microsoft.Azure.Functions.Worker.Extensions.Abstractions": { @@ -592,30 +604,27 @@ }, "Microsoft.Azure.Functions.Worker.Grpc": { "type": "Transitive", - "resolved": "1.6.0", - "contentHash": "r0bAEtBNy9ropO+Ii5V82l8X6R9mbYlGrXlTQPZI09JQuPJiQ86xc36+YLledVn8t8R2EiJMw5UUOpSOXY/ADw==", + "resolved": "1.10.1", + "contentHash": "DEXi2LS57inBiYBiRlPP43PoUPePxH2IzJ16VwAOhG1FRhKDjalKNSMfg5bkg9QrAN/M9XQHuHzZ7u+9tpRwQg==", "dependencies": { "Azure.Core": "1.10.0", "Google.Protobuf": "3.21.7", "Grpc.Net.Client": "2.49.0", "Grpc.Net.ClientFactory": "2.49.0", - "Microsoft.Azure.Functions.Worker.Core": "1.8.0", + "Microsoft.Azure.Functions.Worker.Core": "1.12.1", "Microsoft.Extensions.Hosting": "5.0.0", "Microsoft.Extensions.Hosting.Abstractions": "5.0.0" } }, "Microsoft.Azure.Functions.Worker.Sdk.Analyzers": { "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "J7AZ9iv/UCd4Di0c84h1P/Sa1aQr5uqO0EBUKwE0AZeWJ11dDfKAwxMiAxYOKR+giy31DWBnuFc4GKY3BQYUjg==" + "resolved": "1.1.2", + "contentHash": "e/7MOc5Tf40eiJgOBkg3O2LVtZZlqbh07Mldf/QKtNJ3JkFHHZNq8sMy5M/Ji6JOCOemSNpOwVtfSue7rJTp6Q==" }, "Microsoft.Azure.Functions.Worker.Sdk.Generators": { "type": "Transitive", - "resolved": "1.0.0-preview1", - "contentHash": "XwJtFvfC0NlqpcNsZzcf8td9Pg4NlstU9+eKTrRxKp0kiNK5EowoixhUIeK/wseI9R0goILZdQ190tkwlojbTw==", - "dependencies": { - "Microsoft.CodeAnalysis.CSharp": "3.11.0" - } + "resolved": "1.1.0-preview2", + "contentHash": "9mbUbe5AYkj8bvx2GNl4H1CzMS01nAhE/uCsjeSvQFEJs5mREQk6FafSbpVOXAaQ7JMgEZ3aGUfmwdCI94NoOw==" }, "Microsoft.Azure.WebJobs": { "type": "Transitive", @@ -649,33 +658,6 @@ "resolved": "6.0.0", "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" }, - "Microsoft.CodeAnalysis.Analyzers": { - "type": "Transitive", - "resolved": "3.3.2", - "contentHash": "7xt6zTlIEizUgEsYAIgm37EbdkiMmr6fP6J9pDoKEpiGM4pi32BCPGr/IczmSJI9Zzp0a6HOzpr9OvpMP+2veA==" - }, - "Microsoft.CodeAnalysis.Common": { - "type": "Transitive", - "resolved": "3.11.0", - "contentHash": "FDKSkRRXnaEWMa2ONkLMo0ZAt/uiV1XIXyodwKIgP1AMIKA7JJKXx/OwFVsvkkUT4BeobLwokoxFw70fICahNg==", - "dependencies": { - "Microsoft.CodeAnalysis.Analyzers": "3.3.2", - "System.Collections.Immutable": "5.0.0", - "System.Memory": "4.5.4", - "System.Reflection.Metadata": "5.0.0", - "System.Runtime.CompilerServices.Unsafe": "5.0.0", - "System.Text.Encoding.CodePages": "4.5.1", - "System.Threading.Tasks.Extensions": "4.5.4" - } - }, - "Microsoft.CodeAnalysis.CSharp": { - "type": "Transitive", - "resolved": "3.11.0", - "contentHash": "aDRRb7y/sXoJyDqFEQ3Il9jZxyUMHkShzZeCRjQf3SS84n2J0cTEi3TbwVZE9XJvAeMJhGfVVxwOdjYBg6ljmw==", - "dependencies": { - "Microsoft.CodeAnalysis.Common": "[3.11.0]" - } - }, "Microsoft.CSharp": { "type": "Transitive", "resolved": "4.5.0", @@ -892,15 +874,6 @@ "resolved": "7.0.0", "contentHash": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==" }, - "Microsoft.Extensions.Logging.ApplicationInsights": { - "type": "Transitive", - "resolved": "2.21.0", - "contentHash": "tjzErt5oaLs1caaThu6AbtJuHH0oIGDG/rYCXDruHVGig3m8MyCDuwDsGQwzimY7g4aFyLOKfHc3unBN2G96gw==", - "dependencies": { - "Microsoft.ApplicationInsights": "2.21.0", - "Microsoft.Extensions.Logging": "2.1.1" - } - }, "Microsoft.Extensions.Logging.Configuration": { "type": "Transitive", "resolved": "5.0.0", @@ -1443,8 +1416,8 @@ }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "tCQTzPsGZh/A9LhhA6zrqCRV4hOHsK90/G7q3Khxmn6tnB1PuNU0cRaKANP2AWcF9bn0zsuOoZOSrHuJk6oNBA==" + "resolved": "7.0.0", + "contentHash": "9W0ewWDuAyDqS2PigdTxk6jDKonfgscY/hP8hm7VpxYhNHZHKvZTdRckberlFk3VnCmr3xBUyMBut12Q+T2aOw==" }, "System.Diagnostics.EventLog": { "type": "Transitive", @@ -1817,11 +1790,6 @@ "System.Runtime": "4.3.0" } }, - "System.Reflection.Metadata": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "5NecZgXktdGg34rh1OenY1rFNDCI8xSjFr+Z4OU4cU06AQHUdRnIIEeWENu3Wl4YowbzkymAIMvi3WyK9U53pQ==" - }, "System.Reflection.Primitives": { "type": "Transitive", "resolved": "4.3.0", @@ -2119,15 +2087,6 @@ "System.Runtime": "4.3.0" } }, - "System.Text.Encoding.CodePages": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "4J2JQXbftjPMppIHJ7IC+VXQ9XfEagN92vZZNoG12i+zReYlim5dMoXFC1Zzg7tsnKDM7JPo5bYfFK4Jheq44w==", - "dependencies": { - "Microsoft.NETCore.Platforms": "2.1.2", - "System.Runtime.CompilerServices.Unsafe": "4.5.2" - } - }, "System.Text.Encoding.Extensions": { "type": "Transitive", "resolved": "4.3.0", diff --git a/src/ApiService/IntegrationTests/AgentEventsTests.cs b/src/ApiService/IntegrationTests/AgentEventsTests.cs index a662b4890a..02f6a1cacf 100644 --- a/src/ApiService/IntegrationTests/AgentEventsTests.cs +++ b/src/ApiService/IntegrationTests/AgentEventsTests.cs @@ -267,7 +267,8 @@ public async Async.Task NodeStateUpdate_BecomingFree_StopsNode_IfMarkedForDeleti await Context.InsertAll( new Node(_poolName, _machineId, _poolId, _poolVersion, DeleteRequested: true)); - var func = new AgentEvents(Logger, Context); + var auth = new TestEndpointAuthorization(RequestType.Agent, Logger, Context); + var func = new AgentEvents(Logger, auth, Context); var data = new NodeStateEnvelope( MachineId: _machineId, Event: new NodeStateUpdate(NodeState.Free)); diff --git a/src/ApiService/IntegrationTests/AuthTests.cs b/src/ApiService/IntegrationTests/AuthTests.cs index 3632658fbc..5b1e1fa353 100644 --- a/src/ApiService/IntegrationTests/AuthTests.cs +++ b/src/ApiService/IntegrationTests/AuthTests.cs @@ -1,15 +1,15 @@ using FluentAssertions; -using IntegrationTests; -using Microsoft.OneFuzz.Service; +using Microsoft.Extensions.Logging; using Xunit; using Xunit.Abstractions; namespace Tests { public class AuthTests { - protected ILogTracer Logger { get; } + protected ILogger Logger { get; } public AuthTests(ITestOutputHelper output) { - Logger = new TestLogTracer(output); + var provider = new IntegrationTests.OneFuzzLoggerProvider(output); + Logger = provider.CreateLogger("Auth"); } [Fact] diff --git a/src/ApiService/IntegrationTests/ContainersTests.cs b/src/ApiService/IntegrationTests/ContainersTests.cs index 70339edf16..da3c9fea78 100644 --- a/src/ApiService/IntegrationTests/ContainersTests.cs +++ b/src/ApiService/IntegrationTests/ContainersTests.cs @@ -31,6 +31,8 @@ public abstract class ContainersTestBase : FunctionTestBase { public ContainersTestBase(ITestOutputHelper output, IStorage storage) : base(output, storage) { } + var auth = new TestEndpointAuthorization(RequestType.NoAuthorization, Logger, Context); + var func = new ContainersFunction(Logger, auth, Context); [Fact] public async Async.Task CanDelete() { var containerName = Container.Parse("test"); diff --git a/src/ApiService/IntegrationTests/Fakes/TestContainers.cs b/src/ApiService/IntegrationTests/Fakes/TestContainers.cs index d45851ff50..eb035e94fa 100644 --- a/src/ApiService/IntegrationTests/Fakes/TestContainers.cs +++ b/src/ApiService/IntegrationTests/Fakes/TestContainers.cs @@ -1,7 +1,8 @@ -using Microsoft.OneFuzz.Service; +using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service; // TestContainers class allows use of InstanceID without having to set it up in blob storage sealed class TestContainers : Containers { - public TestContainers(ILogTracer log, IStorage storage, IServiceConfig config) + public TestContainers(ILogger log, IStorage storage, IServiceConfig config) : base(log, storage, config) { } } diff --git a/src/ApiService/IntegrationTests/Fakes/TestContext.cs b/src/ApiService/IntegrationTests/Fakes/TestContext.cs index 41d2219924..c524e443a3 100644 --- a/src/ApiService/IntegrationTests/Fakes/TestContext.cs +++ b/src/ApiService/IntegrationTests/Fakes/TestContext.cs @@ -9,14 +9,13 @@ using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; using Tests; using Async = System.Threading.Tasks; - namespace IntegrationTests.Fakes; // TestContext provides a minimal IOnefuzzContext implementation to allow running // of functions as unit or integration tests. public sealed class TestContext : IOnefuzzContext { - public TestContext(IHttpClientFactory httpClientFactory, ILogTracer logTracer, IStorage storage, ICreds creds, string storagePrefix) { + public TestContext(IHttpClientFactory httpClientFactory, OneFuzzLoggerProvider provider, IStorage storage, ICreds creds, string storagePrefix) { var cache = new MemoryCache(Options.Create(new MemoryCacheOptions())); ServiceConfiguration = new TestServiceConfiguration(storagePrefix); Storage = storage; @@ -27,27 +26,27 @@ public TestContext(IHttpClientFactory httpClientFactory, ILogTracer logTracer, I // this one is faked entirely; we can’t perform these operations at test time VmssOperations = new TestVmssOperations(); - Containers = new Containers(logTracer, Storage, ServiceConfiguration); - Queue = new Queue(Storage, logTracer); - RequestHandling = new RequestHandling(logTracer); - TaskOperations = new TaskOperations(logTracer, cache, this); - NodeOperations = new NodeOperations(logTracer, this); - JobOperations = new JobOperations(logTracer, this); - NodeTasksOperations = new NodeTasksOperations(logTracer, this); - TaskEventOperations = new TaskEventOperations(logTracer, this); - NodeMessageOperations = new NodeMessageOperations(logTracer, this); - ConfigOperations = new ConfigOperations(logTracer, this, cache); - PoolOperations = new PoolOperations(logTracer, this); - ScalesetOperations = new ScalesetOperations(logTracer, cache, this); - ReproOperations = new ReproOperations(logTracer, this); - Reports = new Reports(logTracer, Containers); - NotificationOperations = new NotificationOperations(logTracer, this); + Containers = new Containers(provider.CreateLogger(), Storage, ServiceConfiguration); + Queue = new Queue(Storage, provider.CreateLogger()); + RequestHandling = new RequestHandling(provider.CreateLogger()); + TaskOperations = new TaskOperations(provider.CreateLogger(), cache, this); + NodeOperations = new NodeOperations(provider.CreateLogger(), this); + JobOperations = new JobOperations(provider.CreateLogger(), this); + NodeTasksOperations = new NodeTasksOperations(provider.CreateLogger(), this); + TaskEventOperations = new TaskEventOperations(provider.CreateLogger(), this); + NodeMessageOperations = new NodeMessageOperations(provider.CreateLogger(), this); + ConfigOperations = new ConfigOperations(provider.CreateLogger(), this, cache); + PoolOperations = new PoolOperations(provider.CreateLogger(), this); + ScalesetOperations = new ScalesetOperations(provider.CreateLogger(), cache, this); + ReproOperations = new ReproOperations(provider.CreateLogger(), this); + Reports = new Reports(provider.CreateLogger(), Containers); + NotificationOperations = new NotificationOperations(provider.CreateLogger(), this); FeatureManagerSnapshot = new TestFeatureManagerSnapshot(); - WebhookOperations = new TestWebhookOperations(httpClientFactory, logTracer, this); - Events = new TestEvents(logTracer, this); - Metrics = new TestMetrics(logTracer, this); - WebhookMessageLogOperations = new TestWebhookMessageLogOperations(logTracer, this); + WebhookOperations = new TestWebhookOperations(httpClientFactory, provider.CreateLogger(), this); + Events = new TestEvents(provider.CreateLogger(), this); + Metrics = new TestMetrics(provider.CreateLogger(), this); + WebhookMessageLogOperations = new TestWebhookMessageLogOperations(provider.CreateLogger(), this); } // convenience method for test setup diff --git a/src/ApiService/IntegrationTests/Fakes/TestEvents.cs b/src/ApiService/IntegrationTests/Fakes/TestEvents.cs index 73088d407d..f0b26312a1 100644 --- a/src/ApiService/IntegrationTests/Fakes/TestEvents.cs +++ b/src/ApiService/IntegrationTests/Fakes/TestEvents.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; - using Async = System.Threading.Tasks; namespace IntegrationTests.Fakes; @@ -10,7 +10,7 @@ public sealed class TestEvents : Events { public List Events { get; } = new(); public List SignalREvents { get; } = new(); - public TestEvents(ILogTracer log, IOnefuzzContext context) + public TestEvents(ILogger log, IOnefuzzContext context) : base(log, context) { } public override void LogEvent(BaseEvent anEvent) { diff --git a/src/ApiService/IntegrationTests/Fakes/TestMetrics.cs b/src/ApiService/IntegrationTests/Fakes/TestMetrics.cs index 53a6c9aceb..93ba8c4d58 100644 --- a/src/ApiService/IntegrationTests/Fakes/TestMetrics.cs +++ b/src/ApiService/IntegrationTests/Fakes/TestMetrics.cs @@ -1,12 +1,12 @@ using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; - namespace IntegrationTests.Fakes; public sealed class TestMetrics : Metrics { public List Metrics { get; } = new(); public List CustomMetrics { get; } = new(); - public TestMetrics(ILogTracer log, IOnefuzzContext context) + public TestMetrics(ILogger log, IOnefuzzContext context) : base(log, context) { } } diff --git a/src/ApiService/IntegrationTests/Fakes/TestWebhookMessageLogOperations.cs b/src/ApiService/IntegrationTests/Fakes/TestWebhookMessageLogOperations.cs index 525690fe46..5899360e0a 100644 --- a/src/ApiService/IntegrationTests/Fakes/TestWebhookMessageLogOperations.cs +++ b/src/ApiService/IntegrationTests/Fakes/TestWebhookMessageLogOperations.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; - namespace IntegrationTests.Fakes; public sealed class TestWebhookMessageLogOperations : WebhookMessageLogOperations { @@ -8,6 +8,6 @@ public sealed class TestWebhookMessageLogOperations : WebhookMessageLogOperation public List Events { get; } = new(); public List SignalREvents { get; } = new(); - public TestWebhookMessageLogOperations(ILogTracer log, IOnefuzzContext context) + public TestWebhookMessageLogOperations(ILogger log, IOnefuzzContext context) : base(log, context) { } } diff --git a/src/ApiService/IntegrationTests/Fakes/TestWebhookOperations.cs b/src/ApiService/IntegrationTests/Fakes/TestWebhookOperations.cs index 2f92590a29..882facf7ff 100644 --- a/src/ApiService/IntegrationTests/Fakes/TestWebhookOperations.cs +++ b/src/ApiService/IntegrationTests/Fakes/TestWebhookOperations.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Net.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; - namespace IntegrationTests.Fakes; public sealed class TestWebhookOperations : WebhookOperations { @@ -9,6 +9,6 @@ public sealed class TestWebhookOperations : WebhookOperations { public List Events { get; } = new(); public List SignalREvents { get; } = new(); - public TestWebhookOperations(IHttpClientFactory httpClientFactory, ILogTracer log, IOnefuzzContext context) + public TestWebhookOperations(IHttpClientFactory httpClientFactory, ILogger log, IOnefuzzContext context) : base(httpClientFactory, log, context) { } } diff --git a/src/ApiService/IntegrationTests/TestLogTracer.cs b/src/ApiService/IntegrationTests/TestLogTracer.cs index 59bac855eb..2f3365718b 100644 --- a/src/ApiService/IntegrationTests/TestLogTracer.cs +++ b/src/ApiService/IntegrationTests/TestLogTracer.cs @@ -1,76 +1,440 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; -using System.Net; -using Microsoft.OneFuzz.Service; +using System.Diagnostics; +using System.Globalization; +using global::Microsoft.ApplicationInsights.DataContracts; +using global::Microsoft.Extensions.Logging; using Xunit.Abstractions; namespace IntegrationTests; -sealed class TestLogTracer : ILogTracer { +/// +/// +/// +public enum Telemetry { + /// + /// + /// + Trace, + /// + /// + /// + Exception, + /// + /// + /// + Request, + /// + /// + /// + Dependency, + /// + /// + /// + PageView, + /// + /// + /// + Availability, + /// + /// + /// + Metric, + /// + /// + /// + Event +} + + +/// +/// +/// +public class OneFuzzLogger : ILogger { + private readonly ITestOutputHelper _output; - public TestLogTracer(ITestOutputHelper output) - => _output = output; + /// + /// + /// + public const string CorrelationId = "CorrelationId"; + private readonly string categoryName; + + /// + /// + /// + /// + /// + public OneFuzzLogger(string categoryName, ITestOutputHelper output) { + this.categoryName = categoryName; + this._output = output; + + } + + private const string TagsActivityName = "OneFuzzLoggerActivity"; + + /// + /// + /// + public static Activity Activity { + get { + var cur = Activity.Current; + while (cur is not null && string.Equals(cur.OperationName, TagsActivityName)) { + cur = cur.Parent; + } + + if (cur is null) { + cur = new Activity(TagsActivityName); + _ = cur.Start(); + } + return cur; + } + } + + /// + /// / + /// + /// + /// + /// + IDisposable? ILogger.BeginScope(TState state) { + var activity = new Activity(TagsActivityName); + _ = activity.Start(); + return activity; + } + + /// + /// + /// + /// + /// + bool ILogger.IsEnabled(LogLevel logLevel) { + return true; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + void ILogger.Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) { + if (formatter == null) { + throw new ArgumentNullException(nameof(formatter)); + } + + if (state is RequestTelemetry request) { + PopulateTags(request); + _output.WriteLine($"[Request] {request}"); + } else if (state is PageViewTelemetry pageView) { + PopulateTags(pageView); + _output.WriteLine($"[PageView] {pageView}"); + } else if (state is AvailabilityTelemetry availability) { + PopulateTags(availability); + _output.WriteLine($"[Availability] {availability}"); + } else if (state is DependencyTelemetry dependency) { + PopulateTags(dependency); + _output.WriteLine($"[Dependency] {dependency}"); + } else if (state is MetricTelemetry metric) { + PopulateTags(metric); + _output.WriteLine($"[Metric] {metric}"); + } else if (state is EventTelemetry evt) { + PopulateTags(evt); + _output.WriteLine($"[Event] {evt}"); + } else { + if ((this as ILogger).IsEnabled(logLevel)) { + if (exception is null) { + TraceTelemetry traceTelemetry = new TraceTelemetry( + formatter(state, exception), + OneFuzzLogger.GetSeverityLevel(logLevel)); + + + traceTelemetry.Context.Operation.Id = Activity.RootId; + traceTelemetry.Context.Operation.ParentId = Activity.SpanId.ToString(); + this.PopulateTelemetry(traceTelemetry, state, eventId); + _output.WriteLine($"[Trace] {traceTelemetry}"); + + } else { + ExceptionTelemetry exceptionTelemetry = new ExceptionTelemetry(exception) { + Message = exception.Message, + SeverityLevel = OneFuzzLogger.GetSeverityLevel(logLevel), + }; + exceptionTelemetry.Context.Operation.Id = Activity.RootId; + exceptionTelemetry.Context.Operation.ParentId = Activity.SpanId.ToString(); + + exceptionTelemetry.Properties.Add("FormattedMessage", formatter(state, exception)); + this.PopulateTelemetry(exceptionTelemetry, state, eventId); + _output.WriteLine($"[Exception] {exceptionTelemetry}"); + } + } + } + } + + + /// + /// Converts the into corresponding Application insights . + /// + /// Logging log level. + /// Application insights corresponding SeverityLevel for the LogLevel. + private static SeverityLevel GetSeverityLevel(LogLevel logLevel) { + switch (logLevel) { + case LogLevel.Critical: + return SeverityLevel.Critical; + case LogLevel.Error: + return SeverityLevel.Error; + case LogLevel.Warning: + return SeverityLevel.Warning; + case LogLevel.Information: + return SeverityLevel.Information; + case LogLevel.Debug: + case LogLevel.Trace: + default: + return SeverityLevel.Verbose; + } + } + + + /// + /// Populates the state, scope and event information for the logging event. + /// + /// State information for the current event. + /// Telemetry item. + /// Event state information. + /// Event Id information. + private void PopulateTelemetry(ISupportProperties telemetryItem, TState state, EventId eventId) { + IDictionary dict = telemetryItem.Properties; + dict["CategoryName"] = this.categoryName; + dict["Logger"] = nameof(OneFuzzLogger); + + if (eventId.Id != 0) { + dict["EventId"] = eventId.Id.ToString(CultureInfo.InvariantCulture); + } + + if (!string.IsNullOrEmpty(eventId.Name)) { + dict["EventName"] = eventId.Name; + } + if (state is IReadOnlyCollection> stateDictionary) { + foreach (KeyValuePair item in stateDictionary) { + if (string.Equals(item.Key, "{OriginalFormat}")) { + dict["OriginalFormat"] = Convert.ToString(item.Value, CultureInfo.InvariantCulture) ?? $"Faled to convert {item.Value}"; + } else { + dict[item.Key] = Convert.ToString(item.Value, CultureInfo.InvariantCulture) ?? $"Faled to convert {item.Value}"; + } + } + } + PopulateTags(telemetryItem); + } + + /// + /// + /// + /// + private static void PopulateTags(ISupportProperties telemetryItem) { + IDictionary dict = telemetryItem.Properties; + + var ourActivities = new LinkedList(); + { + var activity = Activity; + while (activity is not null && string.Equals(activity.OperationName, TagsActivityName)) { + _ = ourActivities.AddFirst(activity); + activity = activity.Parent; + } + } + + foreach (var activity in ourActivities) { + foreach (var kv in activity.Tags) { + dict[kv.Key] = Convert.ToString(kv.Value, CultureInfo.InvariantCulture) ?? $"Faled to convert {kv.Value}"; + } + } + } +} + - private readonly Dictionary _tags = new(); - public IReadOnlyDictionary Tags => _tags; +/// +/// +/// +public static class OneFuzzLoggerExt { + private static EventId EmptyEventId = new EventId(0); - public void Critical(LogStringHandler message) { - _output.WriteLine($"[Critical] {message.ToString()}"); + /// + /// + /// + /// + public static string? GetCorrelationId(this ILogger _) { + foreach (var tag in OneFuzzLogger.Activity.Tags) { + if (string.Equals(tag.Key, OneFuzzLogger.CorrelationId)) { + return tag.Value; + } + } + return null; } - public void Error(LogStringHandler message) { - _output.WriteLine($"[Error] {message.ToString()}"); + + /// + /// + /// + /// + /// + /// + public static void AddTag(this ILogger logger, string key, string value) { + _ = OneFuzzLogger.Activity.AddTag(key, value); } - public void Event(LogStringHandler evt, IReadOnlyDictionary? metrics) { - // TODO: metrics - _output.WriteLine($"[Event] [{evt}]"); + /// + /// + /// + /// /// + /// + public static void AddTags(this ILogger logger, IDictionary tags) { + var activity = OneFuzzLogger.Activity; + foreach (var kv in tags) { + _ = activity.AddTag(kv.Key, kv.Value); + } } - public void Metric(LogStringHandler metric, int value, IReadOnlyDictionary? customDimensions) { - // TODO: metrics - _output.WriteLine($"[Event] [{metric}]"); + /// + /// + /// + /// + /// + public static void AddTags(this ILogger logger, IEnumerable<(string, string)> tags) { + var activity = OneFuzzLogger.Activity; + foreach (var tag in tags) { + _ = activity.AddTag(tag.Item1, tag.Item2); + } } - public void Exception(Exception ex, LogStringHandler message = $"", IReadOnlyDictionary? metrics = null) { - // TODO: metrics - _output.WriteLine($"[Error] {message} {ex}"); + /// + /// + /// + /// + /// + /// + public static void LogEvent(this ILogger logger, string name, IDictionary? metrics = null) { + var evt = new EventTelemetry(name); + if (metrics != null) { + foreach (var m in metrics) { + evt.Metrics[m.Key] = m.Value; + } + } + logger.Log(LogLevel.Information, EmptyEventId, evt, null, (state, exception) => state.ToString() ?? $"Failed to convert event {name}"); } - public void ForceFlush() { - // nothing to do + + /// + /// + /// + /// + /// + /// + public static void LogMetric(this ILogger logger, string name, double value) { + var metric = new MetricTelemetry(name, value); + logger.Log(LogLevel.Information, EmptyEventId, metric, null, (state, exception) => state.ToString() ?? $"Failed to convert metric {name}"); } - public void Info(LogStringHandler message) { - _output.WriteLine($"[Info] {message.ToString()}"); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void LogDependency(this ILogger logger, string dependencyTypeName, string target, string dependencyName, string data, DateTimeOffset startTime, TimeSpan duration, string resultCode, bool success) { + var dependency = new DependencyTelemetry(dependencyTypeName, target, dependencyName, data, startTime, duration, resultCode, success); + logger.Log(LogLevel.Information, EmptyEventId, dependency, null, (state, exception) => state.ToString() ?? $"Failed to convert dependency {dependencyName}"); } - public void Verbose(LogStringHandler message) { - _output.WriteLine($"[Verbose] {message.ToString()}"); + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void LogAvailabilityTelemetry(this ILogger logger, string name, DateTimeOffset timeStamp, TimeSpan duration, string runLocation, bool success, string? message = null) { + var availability = new AvailabilityTelemetry(name, timeStamp, duration, runLocation, success, message); + logger.Log(LogLevel.Information, EmptyEventId, availability, null, (state, exception) => state.ToString() ?? $"Failed to convert availability {availability}"); } - public void Warning(LogStringHandler message) { - _output.WriteLine($"[Warning] {message.ToString()}"); + /// + /// + /// + /// + /// + public static void LogPageView(this ILogger logger, string pageName) { + var pageView = new PageViewTelemetry(pageName); + logger.Log(LogLevel.Information, EmptyEventId, pageView, null, (state, exception) => state.ToString() ?? $"Failed to convert pageView {pageView}"); } - public ILogTracer WithHttpStatus((HttpStatusCode Status, string Reason) result) { - return this; // TODO? + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static void LogRequest(this ILogger logger, string name, DateTimeOffset startTime, TimeSpan duration, string responseCode, bool success) { + var request = new RequestTelemetry(name, startTime, duration, responseCode, success); + logger.Log(LogLevel.Information, EmptyEventId, request, null, (state, exception) => state.ToString() ?? $"Failed to convert request {request}"); } +} + + + +/// +/// +/// +[ProviderAlias("OneFuzzLoggerProvider")] +public sealed class OneFuzzLoggerProvider : ILoggerProvider, ILoggerFactory { + private readonly ConcurrentDictionary _loggers = new(StringComparer.OrdinalIgnoreCase); + private readonly ITestOutputHelper _output; + + - public ILogTracer WithTag(string k, string v) { - return this; // TODO? + /// + /// + /// + /// + public OneFuzzLoggerProvider(ITestOutputHelper output) { + _output = output; + } + /// + /// + /// + /// + /// + public ILogger CreateLogger(string categoryName) { + return _loggers.GetOrAdd(categoryName, name => new OneFuzzLogger(name, _output)); } - public ILogTracer WithTags(IEnumerable<(string, string)>? tags) { - return this; // TODO? + public ILogger CreateLogger() { + return new Logger(this); } - public void Error(Error error) { - Error($"{error}"); + + /// + /// + /// + public void Dispose() { + _loggers.Clear(); } - public void Warning(Error error) { - Warning($"{error}"); + public void AddProvider(ILoggerProvider provider) { + } } diff --git a/src/ApiService/IntegrationTests/_FunctionTestBase.cs b/src/ApiService/IntegrationTests/_FunctionTestBase.cs index a1a8267b5b..65a664c0c3 100644 --- a/src/ApiService/IntegrationTests/_FunctionTestBase.cs +++ b/src/ApiService/IntegrationTests/_FunctionTestBase.cs @@ -8,11 +8,11 @@ using Azure.Storage.Blobs; using IntegrationTests.Fakes; using Microsoft.Azure.Functions.Worker.Http; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; using Xunit; using Xunit.Abstractions; - using Task = System.Threading.Tasks.Task; namespace IntegrationTests; @@ -38,21 +38,26 @@ public abstract class FunctionTestBase : IAsyncLifetime { private readonly string _resourceGroup = "FakeResourceGroup"; private readonly Region _region = Region.Parse("fakeregion"); - protected ILogTracer Logger { get; } + protected ILogger Logger { get; } protected TestContext Context { get; } + protected OneFuzzLoggerProvider LoggerProvider { get; } + private readonly BlobServiceClient _blobClient; protected BlobContainerClient GetContainerClient(Container container) => _blobClient.GetBlobContainerClient(_storagePrefix + container.String); public FunctionTestBase(ITestOutputHelper output, IStorage storage) { var instanceId = Guid.NewGuid().ToString(); - Logger = new TestLogTracer(output); + + LoggerProvider = new OneFuzzLoggerProvider(output); + Logger = LoggerProvider.CreateLogger("Test"); _storage = storage; + var creds = new TestCreds(_subscriptionId, _resourceGroup, _region, instanceId); - Context = new TestContext(new DefaultHttpClientFactory(), Logger, _storage, creds, _storagePrefix); + Context = new TestContext(new DefaultHttpClientFactory(), LoggerProvider, _storage, creds, _storagePrefix); // set up blob client for test purposes: // this is always sync for test purposes @@ -95,10 +100,10 @@ await blobClient .Select(async container => { try { using var _ = await blobClient.DeleteBlobContainerAsync(container.Name); - Logger.Info($"cleaned up container {container.Name:Tag:ContainerName}"); + Logger.LogInformation("cleaned up container {ContainerName}", container.Name); } catch (Exception ex) { // swallow any exceptions: this is a best-effort attempt to cleanup - Logger.Exception(ex, $"error deleting container {container.Name:Tag:ContainerName} at end of test"); + Logger.LogError(ex, "error deleting container {ContainerName} at end of test", container.Name); } }) .ToListAsync()); @@ -110,10 +115,10 @@ await tableClient .Select(async table => { try { using var _ = await tableClient.DeleteTableAsync(table.Name); - Logger.Info($"cleaned up table {table.Name:Tag:TableName}"); + Logger.LogInformation("cleaned up table {TableName}", table.Name); } catch (Exception ex) { // swallow any exceptions: this is a best-effort attempt to cleanup - Logger.Exception(ex, $"error deleting table {table.Name:Tag:TableName} at end of test"); + Logger.LogError(ex, "error deleting table {TableName} at end of test", table.Name); } }) .ToListAsync()); diff --git a/src/ApiService/IntegrationTests/packages.lock.json b/src/ApiService/IntegrationTests/packages.lock.json index e6a3977c4b..018b74a7cc 100644 --- a/src/ApiService/IntegrationTests/packages.lock.json +++ b/src/ApiService/IntegrationTests/packages.lock.json @@ -441,34 +441,36 @@ }, "Microsoft.Azure.Functions.Worker": { "type": "Transitive", - "resolved": "1.10.0", - "contentHash": "LBase3J7/ZBaCrAgcTu629tCXleoO+4oft+6Q/F0HL5oc6qFqpMZ5oxMiA34kGXhb9D3A/CghJtNEwiBF1qWCA==", + "resolved": "1.14.1", + "contentHash": "3CUKmg15c7Uv90i6P/96dtId5mj5dqp89btJIsui+CSrm0g8PdjdBi3wmxbqtzcfWIMrGBrqJlvocwI3rINmRg==", "dependencies": { "Azure.Core": "1.10.0", - "Microsoft.Azure.Functions.Worker.Core": "1.8.0", - "Microsoft.Azure.Functions.Worker.Grpc": "1.6.0", + "Microsoft.Azure.Functions.Worker.Core": "1.12.1", + "Microsoft.Azure.Functions.Worker.Grpc": "1.10.1", "Microsoft.Extensions.Hosting": "5.0.0", "Microsoft.Extensions.Hosting.Abstractions": "5.0.0" } }, "Microsoft.Azure.Functions.Worker.ApplicationInsights": { "type": "Transitive", - "resolved": "1.0.0-preview3", - "contentHash": "VCbascK8UUq5FAZF+LsdmQKCL98knfT3ZBq4K757AbrUcgu/E+bTU0GkbQIa2mVuDmo+DJ2emmkqwur7lJZRbg==", + "resolved": "1.0.0-preview4", + "contentHash": "oX3LX4gOQr8kLoWVbNrXJFldDs3m0YKW2CKu7Nt96BMBThmSx8PdGTwfNX42tDmZ71G6dghoilhXH1oZGiUJfw==", "dependencies": { "Microsoft.ApplicationInsights.WorkerService": "2.21.0", - "Microsoft.Azure.Functions.Worker.Core": "1.8.0" + "Microsoft.Azure.Functions.Worker.Core": "1.11.0", + "Microsoft.Bcl.AsyncInterfaces": "5.0.0" } }, "Microsoft.Azure.Functions.Worker.Core": { "type": "Transitive", - "resolved": "1.8.0", - "contentHash": "8awXnik71Og7WAKUQLhPAatm236Icf9XAu0oerNCGjfAVjIF6o5U1M7id9V368ZvCsEXN3Ejq0sGRAEzjt/t6A==", + "resolved": "1.12.1", + "contentHash": "O8xCNF2Sh8JTvA/AJ45vil8byOjw2zRTPpFp7a9m1YGJbyt2jhr8fszyQPVZYaJWkIdIRy5+cEZwigA8LoziAQ==", "dependencies": { "Azure.Core": "1.10.0", "Microsoft.Extensions.Hosting": "5.0.0", "Microsoft.Extensions.Hosting.Abstractions": "5.0.0", - "System.Collections.Immutable": "5.0.0" + "System.Collections.Immutable": "5.0.0", + "System.Diagnostics.DiagnosticSource": "7.0.0" } }, "Microsoft.Azure.Functions.Worker.Extensions.Abstractions": { @@ -537,39 +539,36 @@ }, "Microsoft.Azure.Functions.Worker.Grpc": { "type": "Transitive", - "resolved": "1.6.0", - "contentHash": "r0bAEtBNy9ropO+Ii5V82l8X6R9mbYlGrXlTQPZI09JQuPJiQ86xc36+YLledVn8t8R2EiJMw5UUOpSOXY/ADw==", + "resolved": "1.10.1", + "contentHash": "DEXi2LS57inBiYBiRlPP43PoUPePxH2IzJ16VwAOhG1FRhKDjalKNSMfg5bkg9QrAN/M9XQHuHzZ7u+9tpRwQg==", "dependencies": { "Azure.Core": "1.10.0", "Google.Protobuf": "3.21.7", "Grpc.Net.Client": "2.49.0", "Grpc.Net.ClientFactory": "2.49.0", - "Microsoft.Azure.Functions.Worker.Core": "1.8.0", + "Microsoft.Azure.Functions.Worker.Core": "1.12.1", "Microsoft.Extensions.Hosting": "5.0.0", "Microsoft.Extensions.Hosting.Abstractions": "5.0.0" } }, "Microsoft.Azure.Functions.Worker.Sdk": { "type": "Transitive", - "resolved": "1.7.0", - "contentHash": "kJZEtB4EIB3VeXyUxfilXWE6c49rNnIZvPvPBN6tpTvNHqJQrXm7pgsjwmE3Qw2t2EwhDgVdFDckWNbQQnnS1w==", + "resolved": "1.10.0", + "contentHash": "U5N4c87aUvwfhjkox6A97MxM/PfXn3MctegV3VnaMPlVva/gnVMna4e3p2oGaOp/XDvJ1UmnPTcgj50yaKiZpg==", "dependencies": { - "Microsoft.Azure.Functions.Worker.Sdk.Analyzers": "1.1.0", - "Microsoft.Azure.Functions.Worker.Sdk.Generators": "1.0.0-preview1" + "Microsoft.Azure.Functions.Worker.Sdk.Analyzers": "1.1.2", + "Microsoft.Azure.Functions.Worker.Sdk.Generators": "1.1.0-preview2" } }, "Microsoft.Azure.Functions.Worker.Sdk.Analyzers": { "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "J7AZ9iv/UCd4Di0c84h1P/Sa1aQr5uqO0EBUKwE0AZeWJ11dDfKAwxMiAxYOKR+giy31DWBnuFc4GKY3BQYUjg==" + "resolved": "1.1.2", + "contentHash": "e/7MOc5Tf40eiJgOBkg3O2LVtZZlqbh07Mldf/QKtNJ3JkFHHZNq8sMy5M/Ji6JOCOemSNpOwVtfSue7rJTp6Q==" }, "Microsoft.Azure.Functions.Worker.Sdk.Generators": { "type": "Transitive", - "resolved": "1.0.0-preview1", - "contentHash": "XwJtFvfC0NlqpcNsZzcf8td9Pg4NlstU9+eKTrRxKp0kiNK5EowoixhUIeK/wseI9R0goILZdQ190tkwlojbTw==", - "dependencies": { - "Microsoft.CodeAnalysis.CSharp": "3.11.0" - } + "resolved": "1.1.0-preview2", + "contentHash": "9mbUbe5AYkj8bvx2GNl4H1CzMS01nAhE/uCsjeSvQFEJs5mREQk6FafSbpVOXAaQ7JMgEZ3aGUfmwdCI94NoOw==" }, "Microsoft.Azure.Management.Monitor": { "type": "Transitive", @@ -625,33 +624,6 @@ "resolved": "6.0.0", "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" }, - "Microsoft.CodeAnalysis.Analyzers": { - "type": "Transitive", - "resolved": "3.3.2", - "contentHash": "7xt6zTlIEizUgEsYAIgm37EbdkiMmr6fP6J9pDoKEpiGM4pi32BCPGr/IczmSJI9Zzp0a6HOzpr9OvpMP+2veA==" - }, - "Microsoft.CodeAnalysis.Common": { - "type": "Transitive", - "resolved": "3.11.0", - "contentHash": "FDKSkRRXnaEWMa2ONkLMo0ZAt/uiV1XIXyodwKIgP1AMIKA7JJKXx/OwFVsvkkUT4BeobLwokoxFw70fICahNg==", - "dependencies": { - "Microsoft.CodeAnalysis.Analyzers": "3.3.2", - "System.Collections.Immutable": "5.0.0", - "System.Memory": "4.5.4", - "System.Reflection.Metadata": "5.0.0", - "System.Runtime.CompilerServices.Unsafe": "5.0.0", - "System.Text.Encoding.CodePages": "4.5.1", - "System.Threading.Tasks.Extensions": "4.5.4" - } - }, - "Microsoft.CodeAnalysis.CSharp": { - "type": "Transitive", - "resolved": "3.11.0", - "contentHash": "aDRRb7y/sXoJyDqFEQ3Il9jZxyUMHkShzZeCRjQf3SS84n2J0cTEi3TbwVZE9XJvAeMJhGfVVxwOdjYBg6ljmw==", - "dependencies": { - "Microsoft.CodeAnalysis.Common": "[3.11.0]" - } - }, "Microsoft.CodeCoverage": { "type": "Transitive", "resolved": "17.1.0", @@ -1586,8 +1558,8 @@ }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "tCQTzPsGZh/A9LhhA6zrqCRV4hOHsK90/G7q3Khxmn6tnB1PuNU0cRaKANP2AWcF9bn0zsuOoZOSrHuJk6oNBA==" + "resolved": "7.0.0", + "contentHash": "9W0ewWDuAyDqS2PigdTxk6jDKonfgscY/hP8hm7VpxYhNHZHKvZTdRckberlFk3VnCmr3xBUyMBut12Q+T2aOw==" }, "System.Diagnostics.EventLog": { "type": "Transitive", @@ -2046,8 +2018,8 @@ }, "System.Reflection.Metadata": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "5NecZgXktdGg34rh1OenY1rFNDCI8xSjFr+Z4OU4cU06AQHUdRnIIEeWENu3Wl4YowbzkymAIMvi3WyK9U53pQ==" + "resolved": "1.6.0", + "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ==" }, "System.Reflection.Primitives": { "type": "Transitive", @@ -2346,15 +2318,6 @@ "System.Runtime": "4.3.0" } }, - "System.Text.Encoding.CodePages": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "4J2JQXbftjPMppIHJ7IC+VXQ9XfEagN92vZZNoG12i+zReYlim5dMoXFC1Zzg7tsnKDM7JPo5bYfFK4Jheq44w==", - "dependencies": { - "Microsoft.NETCore.Platforms": "2.1.2", - "System.Runtime.CompilerServices.Unsafe": "4.5.2" - } - }, "System.Text.Encoding.Extensions": { "type": "Transitive", "resolved": "4.3.0", @@ -2626,16 +2589,17 @@ "Faithlife.Utility": "[0.12.2, )", "Microsoft.Azure.AppConfiguration.Functions.Worker": "[6.0.0, )", "Microsoft.Azure.Functions.Extensions": "[1.1.0, )", - "Microsoft.Azure.Functions.Worker": "[1.10.0, )", - "Microsoft.Azure.Functions.Worker.ApplicationInsights": "[1.0.0-preview3, )", + "Microsoft.Azure.Functions.Worker": "[1.14.1, )", + "Microsoft.Azure.Functions.Worker.ApplicationInsights": "[1.0.0-preview4, )", "Microsoft.Azure.Functions.Worker.Extensions.EventGrid": "[2.1.0, )", "Microsoft.Azure.Functions.Worker.Extensions.Http": "[3.0.13, )", "Microsoft.Azure.Functions.Worker.Extensions.SignalRService": "[1.7.0, )", "Microsoft.Azure.Functions.Worker.Extensions.Storage": "[5.0.1, )", "Microsoft.Azure.Functions.Worker.Extensions.Timer": "[4.1.0, )", - "Microsoft.Azure.Functions.Worker.Sdk": "[1.7.0, )", + "Microsoft.Azure.Functions.Worker.Sdk": "[1.10.0, )", "Microsoft.Azure.Management.Monitor": "[0.28.0-preview, )", "Microsoft.Azure.Management.OperationalInsights": "[0.24.0-preview, )", + "Microsoft.Extensions.Logging.ApplicationInsights": "[2.21.0, )", "Microsoft.FeatureManagement": "[2.5.1, )", "Microsoft.Graph": "[4.37.0, )", "Microsoft.Identity.Client": "[4.52.0, )", diff --git a/src/ApiService/Tests/TimerReproTests.cs b/src/ApiService/Tests/TimerReproTests.cs index 9df06e29e4..19be1fff64 100644 --- a/src/ApiService/Tests/TimerReproTests.cs +++ b/src/ApiService/Tests/TimerReproTests.cs @@ -2,15 +2,15 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; using Microsoft.OneFuzz.Service; using Microsoft.OneFuzz.Service.Functions; using Moq; using Xunit; - namespace Tests; public class TimerReproTests { - private readonly ILogTracer _log; + private readonly ILogger _log; private readonly Mock _mockCtx; private readonly Mock _mockReproOperations; @@ -24,7 +24,7 @@ public TimerReproTests() { _mockReproOperations.Setup(x => x.SearchStates(VmStateHelper.NeedsWork)) .Returns(AsyncEnumerable.Empty()); - _log = new Mock().Object; + _log = new Mock>().Object; } [Fact] diff --git a/src/ApiService/Tests/packages.lock.json b/src/ApiService/Tests/packages.lock.json index 21adaa7963..1c8fa42a54 100644 --- a/src/ApiService/Tests/packages.lock.json +++ b/src/ApiService/Tests/packages.lock.json @@ -443,34 +443,36 @@ }, "Microsoft.Azure.Functions.Worker": { "type": "Transitive", - "resolved": "1.10.0", - "contentHash": "LBase3J7/ZBaCrAgcTu629tCXleoO+4oft+6Q/F0HL5oc6qFqpMZ5oxMiA34kGXhb9D3A/CghJtNEwiBF1qWCA==", + "resolved": "1.14.1", + "contentHash": "3CUKmg15c7Uv90i6P/96dtId5mj5dqp89btJIsui+CSrm0g8PdjdBi3wmxbqtzcfWIMrGBrqJlvocwI3rINmRg==", "dependencies": { "Azure.Core": "1.10.0", - "Microsoft.Azure.Functions.Worker.Core": "1.8.0", - "Microsoft.Azure.Functions.Worker.Grpc": "1.6.0", + "Microsoft.Azure.Functions.Worker.Core": "1.12.1", + "Microsoft.Azure.Functions.Worker.Grpc": "1.10.1", "Microsoft.Extensions.Hosting": "5.0.0", "Microsoft.Extensions.Hosting.Abstractions": "5.0.0" } }, "Microsoft.Azure.Functions.Worker.ApplicationInsights": { "type": "Transitive", - "resolved": "1.0.0-preview3", - "contentHash": "VCbascK8UUq5FAZF+LsdmQKCL98knfT3ZBq4K757AbrUcgu/E+bTU0GkbQIa2mVuDmo+DJ2emmkqwur7lJZRbg==", + "resolved": "1.0.0-preview4", + "contentHash": "oX3LX4gOQr8kLoWVbNrXJFldDs3m0YKW2CKu7Nt96BMBThmSx8PdGTwfNX42tDmZ71G6dghoilhXH1oZGiUJfw==", "dependencies": { "Microsoft.ApplicationInsights.WorkerService": "2.21.0", - "Microsoft.Azure.Functions.Worker.Core": "1.8.0" + "Microsoft.Azure.Functions.Worker.Core": "1.11.0", + "Microsoft.Bcl.AsyncInterfaces": "5.0.0" } }, "Microsoft.Azure.Functions.Worker.Core": { "type": "Transitive", - "resolved": "1.8.0", - "contentHash": "8awXnik71Og7WAKUQLhPAatm236Icf9XAu0oerNCGjfAVjIF6o5U1M7id9V368ZvCsEXN3Ejq0sGRAEzjt/t6A==", + "resolved": "1.12.1", + "contentHash": "O8xCNF2Sh8JTvA/AJ45vil8byOjw2zRTPpFp7a9m1YGJbyt2jhr8fszyQPVZYaJWkIdIRy5+cEZwigA8LoziAQ==", "dependencies": { "Azure.Core": "1.10.0", "Microsoft.Extensions.Hosting": "5.0.0", "Microsoft.Extensions.Hosting.Abstractions": "5.0.0", - "System.Collections.Immutable": "5.0.0" + "System.Collections.Immutable": "5.0.0", + "System.Diagnostics.DiagnosticSource": "7.0.0" } }, "Microsoft.Azure.Functions.Worker.Extensions.Abstractions": { @@ -539,39 +541,36 @@ }, "Microsoft.Azure.Functions.Worker.Grpc": { "type": "Transitive", - "resolved": "1.6.0", - "contentHash": "r0bAEtBNy9ropO+Ii5V82l8X6R9mbYlGrXlTQPZI09JQuPJiQ86xc36+YLledVn8t8R2EiJMw5UUOpSOXY/ADw==", + "resolved": "1.10.1", + "contentHash": "DEXi2LS57inBiYBiRlPP43PoUPePxH2IzJ16VwAOhG1FRhKDjalKNSMfg5bkg9QrAN/M9XQHuHzZ7u+9tpRwQg==", "dependencies": { "Azure.Core": "1.10.0", "Google.Protobuf": "3.21.7", "Grpc.Net.Client": "2.49.0", "Grpc.Net.ClientFactory": "2.49.0", - "Microsoft.Azure.Functions.Worker.Core": "1.8.0", + "Microsoft.Azure.Functions.Worker.Core": "1.12.1", "Microsoft.Extensions.Hosting": "5.0.0", "Microsoft.Extensions.Hosting.Abstractions": "5.0.0" } }, "Microsoft.Azure.Functions.Worker.Sdk": { "type": "Transitive", - "resolved": "1.7.0", - "contentHash": "kJZEtB4EIB3VeXyUxfilXWE6c49rNnIZvPvPBN6tpTvNHqJQrXm7pgsjwmE3Qw2t2EwhDgVdFDckWNbQQnnS1w==", + "resolved": "1.10.0", + "contentHash": "U5N4c87aUvwfhjkox6A97MxM/PfXn3MctegV3VnaMPlVva/gnVMna4e3p2oGaOp/XDvJ1UmnPTcgj50yaKiZpg==", "dependencies": { - "Microsoft.Azure.Functions.Worker.Sdk.Analyzers": "1.1.0", - "Microsoft.Azure.Functions.Worker.Sdk.Generators": "1.0.0-preview1" + "Microsoft.Azure.Functions.Worker.Sdk.Analyzers": "1.1.2", + "Microsoft.Azure.Functions.Worker.Sdk.Generators": "1.1.0-preview2" } }, "Microsoft.Azure.Functions.Worker.Sdk.Analyzers": { "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "J7AZ9iv/UCd4Di0c84h1P/Sa1aQr5uqO0EBUKwE0AZeWJ11dDfKAwxMiAxYOKR+giy31DWBnuFc4GKY3BQYUjg==" + "resolved": "1.1.2", + "contentHash": "e/7MOc5Tf40eiJgOBkg3O2LVtZZlqbh07Mldf/QKtNJ3JkFHHZNq8sMy5M/Ji6JOCOemSNpOwVtfSue7rJTp6Q==" }, "Microsoft.Azure.Functions.Worker.Sdk.Generators": { "type": "Transitive", - "resolved": "1.0.0-preview1", - "contentHash": "XwJtFvfC0NlqpcNsZzcf8td9Pg4NlstU9+eKTrRxKp0kiNK5EowoixhUIeK/wseI9R0goILZdQ190tkwlojbTw==", - "dependencies": { - "Microsoft.CodeAnalysis.CSharp": "3.11.0" - } + "resolved": "1.1.0-preview2", + "contentHash": "9mbUbe5AYkj8bvx2GNl4H1CzMS01nAhE/uCsjeSvQFEJs5mREQk6FafSbpVOXAaQ7JMgEZ3aGUfmwdCI94NoOw==" }, "Microsoft.Azure.Management.Monitor": { "type": "Transitive", @@ -627,33 +626,6 @@ "resolved": "6.0.0", "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" }, - "Microsoft.CodeAnalysis.Analyzers": { - "type": "Transitive", - "resolved": "3.3.2", - "contentHash": "7xt6zTlIEizUgEsYAIgm37EbdkiMmr6fP6J9pDoKEpiGM4pi32BCPGr/IczmSJI9Zzp0a6HOzpr9OvpMP+2veA==" - }, - "Microsoft.CodeAnalysis.Common": { - "type": "Transitive", - "resolved": "3.11.0", - "contentHash": "FDKSkRRXnaEWMa2ONkLMo0ZAt/uiV1XIXyodwKIgP1AMIKA7JJKXx/OwFVsvkkUT4BeobLwokoxFw70fICahNg==", - "dependencies": { - "Microsoft.CodeAnalysis.Analyzers": "3.3.2", - "System.Collections.Immutable": "5.0.0", - "System.Memory": "4.5.4", - "System.Reflection.Metadata": "5.0.0", - "System.Runtime.CompilerServices.Unsafe": "5.0.0", - "System.Text.Encoding.CodePages": "4.5.1", - "System.Threading.Tasks.Extensions": "4.5.4" - } - }, - "Microsoft.CodeAnalysis.CSharp": { - "type": "Transitive", - "resolved": "3.11.0", - "contentHash": "aDRRb7y/sXoJyDqFEQ3Il9jZxyUMHkShzZeCRjQf3SS84n2J0cTEi3TbwVZE9XJvAeMJhGfVVxwOdjYBg6ljmw==", - "dependencies": { - "Microsoft.CodeAnalysis.Common": "[3.11.0]" - } - }, "Microsoft.CodeCoverage": { "type": "Transitive", "resolved": "17.1.0", @@ -1588,8 +1560,8 @@ }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "tCQTzPsGZh/A9LhhA6zrqCRV4hOHsK90/G7q3Khxmn6tnB1PuNU0cRaKANP2AWcF9bn0zsuOoZOSrHuJk6oNBA==" + "resolved": "7.0.0", + "contentHash": "9W0ewWDuAyDqS2PigdTxk6jDKonfgscY/hP8hm7VpxYhNHZHKvZTdRckberlFk3VnCmr3xBUyMBut12Q+T2aOw==" }, "System.Diagnostics.EventLog": { "type": "Transitive", @@ -2048,8 +2020,8 @@ }, "System.Reflection.Metadata": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "5NecZgXktdGg34rh1OenY1rFNDCI8xSjFr+Z4OU4cU06AQHUdRnIIEeWENu3Wl4YowbzkymAIMvi3WyK9U53pQ==" + "resolved": "1.6.0", + "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ==" }, "System.Reflection.Primitives": { "type": "Transitive", @@ -2348,15 +2320,6 @@ "System.Runtime": "4.3.0" } }, - "System.Text.Encoding.CodePages": { - "type": "Transitive", - "resolved": "4.5.1", - "contentHash": "4J2JQXbftjPMppIHJ7IC+VXQ9XfEagN92vZZNoG12i+zReYlim5dMoXFC1Zzg7tsnKDM7JPo5bYfFK4Jheq44w==", - "dependencies": { - "Microsoft.NETCore.Platforms": "2.1.2", - "System.Runtime.CompilerServices.Unsafe": "4.5.2" - } - }, "System.Text.Encoding.Extensions": { "type": "Transitive", "resolved": "4.3.0", @@ -2628,16 +2591,17 @@ "Faithlife.Utility": "[0.12.2, )", "Microsoft.Azure.AppConfiguration.Functions.Worker": "[6.0.0, )", "Microsoft.Azure.Functions.Extensions": "[1.1.0, )", - "Microsoft.Azure.Functions.Worker": "[1.10.0, )", - "Microsoft.Azure.Functions.Worker.ApplicationInsights": "[1.0.0-preview3, )", + "Microsoft.Azure.Functions.Worker": "[1.14.1, )", + "Microsoft.Azure.Functions.Worker.ApplicationInsights": "[1.0.0-preview4, )", "Microsoft.Azure.Functions.Worker.Extensions.EventGrid": "[2.1.0, )", "Microsoft.Azure.Functions.Worker.Extensions.Http": "[3.0.13, )", "Microsoft.Azure.Functions.Worker.Extensions.SignalRService": "[1.7.0, )", "Microsoft.Azure.Functions.Worker.Extensions.Storage": "[5.0.1, )", "Microsoft.Azure.Functions.Worker.Extensions.Timer": "[4.1.0, )", - "Microsoft.Azure.Functions.Worker.Sdk": "[1.7.0, )", + "Microsoft.Azure.Functions.Worker.Sdk": "[1.10.0, )", "Microsoft.Azure.Management.Monitor": "[0.28.0-preview, )", "Microsoft.Azure.Management.OperationalInsights": "[0.24.0-preview, )", + "Microsoft.Extensions.Logging.ApplicationInsights": "[2.21.0, )", "Microsoft.FeatureManagement": "[2.5.1, )", "Microsoft.Graph": "[4.37.0, )", "Microsoft.Identity.Client": "[4.52.0, )", From 4c4832d3b381bfbe48a797d29921dc57c21af621 Mon Sep 17 00:00:00 2001 From: stas Date: Tue, 6 Jun 2023 15:08:49 -0700 Subject: [PATCH 2/8] addressing pr comments --- src/ApiService/ApiService/Log.cs | 104 +-------------------------- src/ApiService/ApiService/Program.cs | 6 +- 2 files changed, 4 insertions(+), 106 deletions(-) diff --git a/src/ApiService/ApiService/Log.cs b/src/ApiService/ApiService/Log.cs index a3d5c8db64..5769367d33 100644 --- a/src/ApiService/ApiService/Log.cs +++ b/src/ApiService/ApiService/Log.cs @@ -7,60 +7,24 @@ namespace Microsoft.OneFuzz.Service; -/// -/// -/// public enum Telemetry { - /// - /// - /// Trace, - /// - /// - /// Exception, - /// - /// - /// Request, - /// - /// - /// Dependency, - /// - /// - /// PageView, - /// - /// - /// Availability, - /// - /// - /// Metric, - /// - /// - /// Event } -/// -/// -/// /// /// public record TelemetryConfig(TelemetryClient TelemetryClient, ISet? EnabledTelemetry = null); -/// -/// -/// public class OneFuzzLogger : ILogger { - /// - /// - /// public const string CorrelationId = "CorrelationId"; private readonly string categoryName; @@ -68,9 +32,6 @@ public class OneFuzzLogger : ILogger { private readonly IEnumerable telemetryConfig; - /// - /// - /// /// /// public OneFuzzLogger(string categoryName, IEnumerable telemetryConfig) { @@ -80,9 +41,6 @@ public OneFuzzLogger(string categoryName, IEnumerable telemetry private const string TagsActivityName = "OneFuzzLoggerActivity"; - /// - /// - /// public static Activity Activity { get { var cur = Activity.Current; @@ -95,9 +53,6 @@ public static Activity Activity { } } - /// - /// / - /// /// /// /// @@ -107,18 +62,12 @@ public static Activity Activity { return activity; } - /// - /// - /// /// /// bool ILogger.IsEnabled(LogLevel logLevel) { return logLevel != LogLevel.None && this.telemetryConfig.Any(c => c.TelemetryClient.IsEnabled()); } - /// - /// - /// /// /// /// @@ -236,9 +185,6 @@ private void PopulateTelemetry(ISupportProperties telemetryItem, TState PopulateTags(telemetryItem); } - /// - /// - /// /// private static void PopulateTags(ISupportProperties telemetryItem) { IDictionary dict = telemetryItem.Properties; @@ -261,16 +207,9 @@ private static void PopulateTags(ISupportProperties telemetryItem) { } -/// -/// -/// public static class OneFuzzLoggerExt { private static EventId EmptyEventId = new EventId(0); - /// - /// - /// - /// public static string? GetCorrelationId(this ILogger _) { foreach (var tag in OneFuzzLogger.Activity.Tags) { if (string.Equals(tag.Key, OneFuzzLogger.CorrelationId)) { @@ -281,9 +220,6 @@ public static class OneFuzzLoggerExt { } - /// - /// - /// /// /// /// @@ -291,10 +227,7 @@ public static void AddTag(this ILogger logger, string key, string value) { _ = OneFuzzLogger.Activity.AddTag(key, value); } - /// - /// - /// - /// /// + /// /// public static void AddTags(this ILogger logger, IDictionary tags) { var activity = OneFuzzLogger.Activity; @@ -303,9 +236,6 @@ public static void AddTags(this ILogger logger, IDictionary tags } } - /// - /// - /// /// /// public static void AddTags(this ILogger logger, IEnumerable<(string, string)> tags) { @@ -315,9 +245,6 @@ public static void AddTags(this ILogger logger, IEnumerable<(string, string)> ta } } - /// - /// - /// /// /// /// @@ -331,10 +258,6 @@ public static void LogEvent(this ILogger logger, string name, IDictionary state.ToString() ?? $"Failed to convert event {name}"); } - - /// - /// - /// /// /// /// @@ -343,9 +266,6 @@ public static void LogMetric(this ILogger logger, string name, double value) { logger.Log(LogLevel.Information, EmptyEventId, metric, null, (state, exception) => state.ToString() ?? $"Failed to convert metric {name}"); } - /// - /// - /// /// /// /// @@ -360,9 +280,6 @@ public static void LogDependency(this ILogger logger, string dependencyTypeName, logger.Log(LogLevel.Information, EmptyEventId, dependency, null, (state, exception) => state.ToString() ?? $"Failed to convert dependency {dependencyName}"); } - /// - /// - /// /// /// /// @@ -375,9 +292,6 @@ public static void LogAvailabilityTelemetry(this ILogger logger, string name, Da logger.Log(LogLevel.Information, EmptyEventId, availability, null, (state, exception) => state.ToString() ?? $"Failed to convert availability {availability}"); } - /// - /// - /// /// /// public static void LogPageView(this ILogger logger, string pageName) { @@ -385,9 +299,6 @@ public static void LogPageView(this ILogger logger, string pageName) { logger.Log(LogLevel.Information, EmptyEventId, pageView, null, (state, exception) => state.ToString() ?? $"Failed to convert pageView {pageView}"); } - /// - /// - /// /// /// /// @@ -401,34 +312,21 @@ public static void LogRequest(this ILogger logger, string name, DateTimeOffset s } - -/// -/// -/// [ProviderAlias("OneFuzzLoggerProvider")] public sealed class OneFuzzLoggerProvider : ILoggerProvider { private readonly ConcurrentDictionary _loggers = new(StringComparer.OrdinalIgnoreCase); private readonly IEnumerable telemetryConfigs; - /// - /// - /// /// public OneFuzzLoggerProvider(IEnumerable telemetryConfigs) { this.telemetryConfigs = telemetryConfigs; } - /// - /// - /// /// /// public ILogger CreateLogger(string categoryName) { return _loggers.GetOrAdd(categoryName, name => new OneFuzzLogger(name, telemetryConfigs)); } - /// - /// - /// public void Dispose() { _loggers.Clear(); } diff --git a/src/ApiService/ApiService/Program.cs b/src/ApiService/ApiService/Program.cs index 4f538c3a67..c33a1c53bf 100644 --- a/src/ApiService/ApiService/Program.cs +++ b/src/ApiService/ApiService/Program.cs @@ -43,9 +43,9 @@ public async Async.Task Invoke(FunctionContext context, FunctionExecutionDelegat //if header has 1f-CorrelationId then use that //otherwise check if message can be deserialized to {"correlationId": "SOME-GUID"}, then use that - if (requestData.Headers.TryGetValues("CorrelationId", out var values1f)) { + if (requestData.Headers.TryGetValues("Correlation-ID", out var values1f)) { correlationId = values1f.First(); - } else if (requestData.Headers.TryGetValues("x-correlationId", out var values)) { + } else if (requestData.Headers.TryGetValues("X-Correlation-ID", out var values)) { correlationId = values.First(); } } @@ -56,7 +56,7 @@ public async Async.Task Invoke(FunctionContext context, FunctionExecutionDelegat await next(context); - context.GetHttpResponseData()?.Headers.Add("x-correlationId", correlationId); + context.GetHttpResponseData()?.Headers.Add("X-Correlation-ID", correlationId); } } From d2ed37f3185df61d1c0836b23a20381fb9628fe3 Mon Sep 17 00:00:00 2001 From: stas Date: Tue, 6 Jun 2023 15:19:41 -0700 Subject: [PATCH 3/8] enable tracking telemetry --- src/ApiService/ApiService/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ApiService/ApiService/Program.cs b/src/ApiService/ApiService/Program.cs index c33a1c53bf..ece7d1c419 100644 --- a/src/ApiService/ApiService/Program.cs +++ b/src/ApiService/ApiService/Program.cs @@ -165,7 +165,7 @@ public static async Async.Task Main() { builder.Services.Configure(workerOptions => workerOptions.Capabilities["WorkerApplicationInsightsLoggingEnabled"] = bool.TrueString); builder.AddApplicationInsights(options => { options.DeveloperMode = false; - options.EnableDependencyTrackingTelemetryModule = false; + options.EnableDependencyTrackingTelemetryModule = true; }); builder.AddApplicationInsightsLogger(); From 71b98c22dffd7b9540243b734e4bfcbc82be7913 Mon Sep 17 00:00:00 2001 From: stas Date: Wed, 7 Jun 2023 07:34:23 -0700 Subject: [PATCH 4/8] solving merge conflicts --- .../Auth/AuthenticationMiddleware.cs | 7 +++--- .../Auth/AuthorizationMiddleware.cs | 6 ++--- .../ApiService/Functions/AgentCommands.cs | 4 ++-- .../ApiService/Functions/AgentEvents.cs | 4 ++-- .../ApiService/Functions/AgentRegistration.cs | 4 ++-- .../ApiService/Functions/Containers.cs | 4 ++-- src/ApiService/ApiService/Functions/Events.cs | 4 ++-- src/ApiService/ApiService/Functions/Jobs.cs | 4 ++-- .../Functions/Migrations/JinjaToScriban.cs | 4 ++-- src/ApiService/ApiService/Functions/Node.cs | 4 ++-- .../ApiService/Functions/NodeAddSshKey.cs | 4 +--- .../ApiService/Functions/NotificationsTest.cs | 4 ++-- src/ApiService/ApiService/Functions/Pool.cs | 6 +---- .../ApiService/Functions/ReproVmss.cs | 4 ++-- .../ApiService/Functions/Scaleset.cs | 4 ++-- .../onefuzzlib/EndpointAuthorization.cs | 1 - .../IntegrationTests/AgentCommandsTests.cs | 2 +- .../IntegrationTests/AgentEventsTests.cs | 23 +++++++++---------- .../AgentRegistrationTests.cs | 16 ++++++------- src/ApiService/IntegrationTests/AuthTests.cs | 1 + .../IntegrationTests/ContainersTests.cs | 16 ++++++------- .../IntegrationTests/EndpointAuthTests.cs | 2 +- .../IntegrationTests/EventsTests.cs | 2 +- .../JinjaToScribanMigrationTests.cs | 13 ++++++----- src/ApiService/IntegrationTests/JobsTests.cs | 14 +++++------ src/ApiService/IntegrationTests/NodeTests.cs | 14 +++++------ src/ApiService/IntegrationTests/PoolTests.cs | 6 ++--- .../IntegrationTests/ReproVmssTests.cs | 16 ++++++------- .../IntegrationTests/ScalesetTests.cs | 10 ++++---- 29 files changed, 98 insertions(+), 105 deletions(-) diff --git a/src/ApiService/ApiService/Auth/AuthenticationMiddleware.cs b/src/ApiService/ApiService/Auth/AuthenticationMiddleware.cs index 2cec43994b..f4810579a1 100644 --- a/src/ApiService/ApiService/Auth/AuthenticationMiddleware.cs +++ b/src/ApiService/ApiService/Auth/AuthenticationMiddleware.cs @@ -4,14 +4,15 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.Azure.Functions.Worker.Middleware; +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Auth; public sealed class AuthenticationMiddleware : IFunctionsWorkerMiddleware { private readonly IConfigOperations _config; - private readonly ILogTracer _log; + private readonly ILogger _log; - public AuthenticationMiddleware(IConfigOperations config, ILogTracer log) { + public AuthenticationMiddleware(IConfigOperations config, ILogger log) { _config = config; _log = log; } @@ -64,7 +65,7 @@ private async Async.ValueTask BadIssuer( IEnumerable allowedTenants) { var tenantsStr = string.Join("; ", allowedTenants); - _log.Error($"issuer not from allowed tenant. issuer: {token.Issuer:Tag:Issuer} - tenants: {tenantsStr:Tag:Tenants}"); + _log.LogError($"issuer not from allowed tenant. issuer: {token.Issuer:Tag:Issuer} - tenants: {tenantsStr:Tag:Tenants}"); var response = HttpResponseData.CreateResponse(request); var status = HttpStatusCode.BadRequest; diff --git a/src/ApiService/ApiService/Auth/AuthorizationMiddleware.cs b/src/ApiService/ApiService/Auth/AuthorizationMiddleware.cs index 34ca16ab28..cf07917fb8 100644 --- a/src/ApiService/ApiService/Auth/AuthorizationMiddleware.cs +++ b/src/ApiService/ApiService/Auth/AuthorizationMiddleware.cs @@ -5,14 +5,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.Azure.Functions.Worker.Middleware; - +using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Auth; public sealed class AuthorizationMiddleware : IFunctionsWorkerMiddleware { private readonly IEndpointAuthorization _auth; - private readonly ILogTracer _log; + private readonly ILogger _log; - public AuthorizationMiddleware(IEndpointAuthorization auth, ILogTracer log) { + public AuthorizationMiddleware(IEndpointAuthorization auth, ILogger log) { _auth = auth; _log = log; } diff --git a/src/ApiService/ApiService/Functions/AgentCommands.cs b/src/ApiService/ApiService/Functions/AgentCommands.cs index 4ce88765a7..602755f9f1 100644 --- a/src/ApiService/ApiService/Functions/AgentCommands.cs +++ b/src/ApiService/ApiService/Functions/AgentCommands.cs @@ -1,14 +1,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; namespace Microsoft.OneFuzz.Service.Functions; public class AgentCommands { private readonly ILogger _log; private readonly IOnefuzzContext _context; - public AgentCommands(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { + public AgentCommands(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } diff --git a/src/ApiService/ApiService/Functions/AgentEvents.cs b/src/ApiService/ApiService/Functions/AgentEvents.cs index da2be5dff9..8a557b5cd4 100644 --- a/src/ApiService/ApiService/Functions/AgentEvents.cs +++ b/src/ApiService/ApiService/Functions/AgentEvents.cs @@ -2,15 +2,15 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; using Microsoft.OneFuzz.Service.OneFuzzLib.Orm; - namespace Microsoft.OneFuzz.Service.Functions; public class AgentEvents { private readonly ILogger _log; private readonly IOnefuzzContext _context; - public AgentEvents(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { + public AgentEvents(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } diff --git a/src/ApiService/ApiService/Functions/AgentRegistration.cs b/src/ApiService/ApiService/Functions/AgentRegistration.cs index 42485b22d1..b22e340025 100644 --- a/src/ApiService/ApiService/Functions/AgentRegistration.cs +++ b/src/ApiService/ApiService/Functions/AgentRegistration.cs @@ -1,15 +1,15 @@ using Azure.Storage.Sas; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; namespace Microsoft.OneFuzz.Service.Functions; public class AgentRegistration { private readonly ILogger _log; private readonly IOnefuzzContext _context; - public AgentRegistration(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { + public AgentRegistration(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } diff --git a/src/ApiService/ApiService/Functions/Containers.cs b/src/ApiService/ApiService/Functions/Containers.cs index ab71388317..a379cbba78 100644 --- a/src/ApiService/ApiService/Functions/Containers.cs +++ b/src/ApiService/ApiService/Functions/Containers.cs @@ -1,15 +1,15 @@ using Azure.Storage.Sas; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; namespace Microsoft.OneFuzz.Service.Functions; public class ContainersFunction { private readonly ILogger _logger; private readonly IOnefuzzContext _context; - public ContainersFunction(ILogger logger, IEndpointAuthorization auth, IOnefuzzContext context) { + public ContainersFunction(ILogger logger, IOnefuzzContext context) { _logger = logger; _context = context; } diff --git a/src/ApiService/ApiService/Functions/Events.cs b/src/ApiService/ApiService/Functions/Events.cs index 6cf6ad5728..20d0d30521 100644 --- a/src/ApiService/ApiService/Functions/Events.cs +++ b/src/ApiService/ApiService/Functions/Events.cs @@ -1,14 +1,14 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; namespace Microsoft.OneFuzz.Service.Functions; public class EventsFunction { private readonly ILogger _log; private readonly IOnefuzzContext _context; - public EventsFunction(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { + public EventsFunction(ILogger log, IOnefuzzContext context) { _context = context; _log = log; } diff --git a/src/ApiService/ApiService/Functions/Jobs.cs b/src/ApiService/ApiService/Functions/Jobs.cs index bd1905a199..3064e550dd 100644 --- a/src/ApiService/ApiService/Functions/Jobs.cs +++ b/src/ApiService/ApiService/Functions/Jobs.cs @@ -1,15 +1,15 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; namespace Microsoft.OneFuzz.Service.Functions; public class Jobs { private readonly IOnefuzzContext _context; private readonly ILogger _logTracer; - public Jobs(IEndpointAuthorization auth, IOnefuzzContext context, ILogger logTracer) { + public Jobs(IOnefuzzContext context, ILogger logTracer) { _context = context; _logTracer = logTracer; } diff --git a/src/ApiService/ApiService/Functions/Migrations/JinjaToScriban.cs b/src/ApiService/ApiService/Functions/Migrations/JinjaToScriban.cs index ce201f66be..10f7acfe5b 100644 --- a/src/ApiService/ApiService/Functions/Migrations/JinjaToScriban.cs +++ b/src/ApiService/ApiService/Functions/Migrations/JinjaToScriban.cs @@ -1,7 +1,7 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; namespace Microsoft.OneFuzz.Service.Functions; public class JinjaToScriban { @@ -10,7 +10,7 @@ public class JinjaToScriban { private readonly IOnefuzzContext _context; - public JinjaToScriban(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { + public JinjaToScriban(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } diff --git a/src/ApiService/ApiService/Functions/Node.cs b/src/ApiService/ApiService/Functions/Node.cs index c3c7d9c09e..8d0926375b 100644 --- a/src/ApiService/ApiService/Functions/Node.cs +++ b/src/ApiService/ApiService/Functions/Node.cs @@ -1,15 +1,15 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; namespace Microsoft.OneFuzz.Service.Functions; public class Node { private readonly ILogger _log; private readonly IOnefuzzContext _context; - public Node(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { + public Node(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } diff --git a/src/ApiService/ApiService/Functions/NodeAddSshKey.cs b/src/ApiService/ApiService/Functions/NodeAddSshKey.cs index 8744ce1d45..73da435000 100644 --- a/src/ApiService/ApiService/Functions/NodeAddSshKey.cs +++ b/src/ApiService/ApiService/Functions/NodeAddSshKey.cs @@ -2,14 +2,12 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; -using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class NodeAddSshKey { - private readonly ILogTracer _log; private readonly IOnefuzzContext _context; - public NodeAddSshKey(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { + public NodeAddSshKey(IEndpointAuthorization auth, IOnefuzzContext context) { _context = context; } diff --git a/src/ApiService/ApiService/Functions/NotificationsTest.cs b/src/ApiService/ApiService/Functions/NotificationsTest.cs index 8a72fff777..268311d402 100644 --- a/src/ApiService/ApiService/Functions/NotificationsTest.cs +++ b/src/ApiService/ApiService/Functions/NotificationsTest.cs @@ -1,15 +1,15 @@ using System.Net; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; namespace Microsoft.OneFuzz.Service.Functions; public class NotificationsTest { private readonly ILogger _log; private readonly IOnefuzzContext _context; - public NotificationsTest(ILogger log log, IEndpointAuthorization auth, IOnefuzzContext context) { + public NotificationsTest(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } diff --git a/src/ApiService/ApiService/Functions/Pool.cs b/src/ApiService/ApiService/Functions/Pool.cs index 10da25db57..3411dcf66d 100644 --- a/src/ApiService/ApiService/Functions/Pool.cs +++ b/src/ApiService/ApiService/Functions/Pool.cs @@ -3,14 +3,12 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; using Microsoft.OneFuzz.Service.Auth; -using Microsoft.Extensions.Logging; namespace Microsoft.OneFuzz.Service.Functions; public class Pool { - private readonly ILogTracer _log; private readonly IOnefuzzContext _context; - public Pool(ILogger log log, IEndpointAuthorization auth, IOnefuzzContext context) { + public Pool(IOnefuzzContext context) { _context = context; } @@ -95,8 +93,6 @@ private async Task Patch(HttpRequestData req) { } else { return await _context.RequestHandling.NotOk(req, Error.Create(ErrorCode.INVALID_REQUEST, updatePool.ErrorV.Reason), "PoolUpdate"); } - - } private async Task Get(HttpRequestData req) { diff --git a/src/ApiService/ApiService/Functions/ReproVmss.cs b/src/ApiService/ApiService/Functions/ReproVmss.cs index 26146d1bff..a522e3160b 100644 --- a/src/ApiService/ApiService/Functions/ReproVmss.cs +++ b/src/ApiService/ApiService/Functions/ReproVmss.cs @@ -3,15 +3,15 @@ using System.Text; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; namespace Microsoft.OneFuzz.Service.Functions; public class ReproVmss { private readonly ILogger _log; private readonly IOnefuzzContext _context; - public ReproVmss(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { + public ReproVmss(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } diff --git a/src/ApiService/ApiService/Functions/Scaleset.cs b/src/ApiService/ApiService/Functions/Scaleset.cs index 5f20641695..d9708a5a46 100644 --- a/src/ApiService/ApiService/Functions/Scaleset.cs +++ b/src/ApiService/ApiService/Functions/Scaleset.cs @@ -1,15 +1,15 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; namespace Microsoft.OneFuzz.Service.Functions; public class Scaleset { private readonly ILogger _log; private readonly IOnefuzzContext _context; - public Scaleset(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { + public Scaleset(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } diff --git a/src/ApiService/ApiService/onefuzzlib/EndpointAuthorization.cs b/src/ApiService/ApiService/onefuzzlib/EndpointAuthorization.cs index 50d25badc2..aae7703002 100644 --- a/src/ApiService/ApiService/onefuzzlib/EndpointAuthorization.cs +++ b/src/ApiService/ApiService/onefuzzlib/EndpointAuthorization.cs @@ -25,7 +25,6 @@ public EndpointAuthorization(IOnefuzzContext context, ILogger CheckRequireAdmins(UserAuthInfo authInfo) { var config = await _context.ConfigOperations.Fetch(); if (config is null) { diff --git a/src/ApiService/IntegrationTests/AgentCommandsTests.cs b/src/ApiService/IntegrationTests/AgentCommandsTests.cs index 47b951fc15..e765179ab8 100644 --- a/src/ApiService/IntegrationTests/AgentCommandsTests.cs +++ b/src/ApiService/IntegrationTests/AgentCommandsTests.cs @@ -42,7 +42,7 @@ await Context.InsertAll(new[] { }); var commandRequest = new NodeCommandGet(machineId); - var func = new AgentCommands(Logger, Context); + var func = new AgentCommands(LoggerProvider.CreateLogger(), Context); var result = await func.Run(TestHttpRequestData.FromJson("GET", commandRequest)); Assert.Equal(HttpStatusCode.OK, result.StatusCode); diff --git a/src/ApiService/IntegrationTests/AgentEventsTests.cs b/src/ApiService/IntegrationTests/AgentEventsTests.cs index 02f6a1cacf..18c1485b96 100644 --- a/src/ApiService/IntegrationTests/AgentEventsTests.cs +++ b/src/ApiService/IntegrationTests/AgentEventsTests.cs @@ -37,7 +37,7 @@ public AgentEventsTestsBase(ITestOutputHelper output, IStorage storage) [Fact] public async Async.Task WorkerEventMustHaveDoneOrRunningSet() { - var func = new AgentEvents(Logger, Context); + var func = new AgentEvents(LoggerProvider.CreateLogger(), Context); var data = new NodeStateEnvelope( MachineId: Guid.NewGuid(), @@ -56,7 +56,7 @@ await Context.InsertAll( new Task(_jobId, _taskId, TaskState.Running, Os.Linux, new TaskConfig(_jobId, null, new TaskDetails(TaskType.Coverage, 100)))); - var func = new AgentEvents(Logger, Context); + var func = new AgentEvents(LoggerProvider.CreateLogger(), Context); var data = new NodeStateEnvelope( MachineId: _machineId, @@ -83,7 +83,7 @@ await Context.InsertAll( new Task(_jobId, _taskId, TaskState.Running, Os.Linux, new TaskConfig(_jobId, null, new TaskDetails(TaskType.Coverage, 100)))); - var func = new AgentEvents(Logger, Context); + var func = new AgentEvents(LoggerProvider.CreateLogger(), Context); var data = new NodeStateEnvelope( MachineId: _machineId, @@ -109,7 +109,7 @@ await Context.InsertAll( new Task(_jobId, _taskId, TaskState.Scheduled, Os.Linux, new TaskConfig(_jobId, null, new TaskDetails(TaskType.Coverage, 100)))); - var func = new AgentEvents(Logger, Context); + var func = new AgentEvents(LoggerProvider.CreateLogger(), Context); var data = new NodeStateEnvelope( MachineId: _machineId, @@ -134,7 +134,7 @@ public async Async.Task WorkerRunning_ForMissingTask_ReturnsError() { await Context.InsertAll( new Node(_poolName, _machineId, _poolId, _poolVersion)); - var func = new AgentEvents(Logger, Context); + var func = new AgentEvents(LoggerProvider.CreateLogger(), Context); var data = new NodeStateEnvelope( MachineId: _machineId, Event: new WorkerEvent(Running: new WorkerRunningEvent(_taskId))); @@ -150,7 +150,7 @@ await Context.InsertAll( new Task(_jobId, _taskId, TaskState.Running, Os.Linux, new TaskConfig(_jobId, null, new TaskDetails(TaskType.Coverage, 0)))); - var func = new AgentEvents(Logger, Context); + var func = new AgentEvents(LoggerProvider.CreateLogger(), Context); var data = new NodeStateEnvelope( MachineId: _machineId, Event: new WorkerEvent(Running: new WorkerRunningEvent(_taskId))); @@ -167,7 +167,7 @@ await Context.InsertAll( new Task(_jobId, _taskId, TaskState.Running, Os.Linux, new TaskConfig(_jobId, null, new TaskDetails(TaskType.Coverage, 0)))); - var func = new AgentEvents(Logger, Context); + var func = new AgentEvents(LoggerProvider.CreateLogger(), Context); var data = new NodeStateEnvelope( MachineId: _machineId, Event: new WorkerEvent(Running: new WorkerRunningEvent(_taskId))); @@ -207,7 +207,7 @@ await Async.Task.WhenAll( public async Async.Task NodeStateUpdate_ForMissingNode_IgnoresEvent() { // nothing present in storage - var func = new AgentEvents(Logger, Context); + var func = new AgentEvents(LoggerProvider.CreateLogger(), Context); var data = new NodeStateEnvelope( MachineId: _machineId, Event: new NodeStateUpdate(NodeState.Init)); @@ -222,7 +222,7 @@ public async Async.Task NodeStateUpdate_CanTransitionFromInitToReady() { await Context.InsertAll( new Node(_poolName, _machineId, _poolId, _poolVersion, State: NodeState.Init)); - var func = new AgentEvents(Logger, Context); + var func = new AgentEvents(LoggerProvider.CreateLogger(), Context); var data = new NodeStateEnvelope( MachineId: _machineId, Event: new NodeStateUpdate(NodeState.Ready)); @@ -239,7 +239,7 @@ public async Async.Task NodeStateUpdate_BecomingFree_StopsNode_IfMarkedForReimag await Context.InsertAll( new Node(_poolName, _machineId, _poolId, _poolVersion, ReimageRequested: true)); - var func = new AgentEvents(Logger, Context); + var func = new AgentEvents(LoggerProvider.CreateLogger(), Context); var data = new NodeStateEnvelope( MachineId: _machineId, Event: new NodeStateUpdate(NodeState.Free)); @@ -267,8 +267,7 @@ public async Async.Task NodeStateUpdate_BecomingFree_StopsNode_IfMarkedForDeleti await Context.InsertAll( new Node(_poolName, _machineId, _poolId, _poolVersion, DeleteRequested: true)); - var auth = new TestEndpointAuthorization(RequestType.Agent, Logger, Context); - var func = new AgentEvents(Logger, auth, Context); + var func = new AgentEvents(LoggerProvider.CreateLogger(), Context); var data = new NodeStateEnvelope( MachineId: _machineId, Event: new NodeStateUpdate(NodeState.Free)); diff --git a/src/ApiService/IntegrationTests/AgentRegistrationTests.cs b/src/ApiService/IntegrationTests/AgentRegistrationTests.cs index 202a66628b..af1efe41f8 100644 --- a/src/ApiService/IntegrationTests/AgentRegistrationTests.cs +++ b/src/ApiService/IntegrationTests/AgentRegistrationTests.cs @@ -35,7 +35,7 @@ public AgentRegistrationTestsBase(ITestOutputHelper output, IStorage storage) [Fact] public async Async.Task Get_UrlParameterRequired() { - var func = new AgentRegistration(Logger, Context); + var func = new AgentRegistration(LoggerProvider.CreateLogger(), Context); var req = TestHttpRequestData.Empty("GET"); var result = await func.Run(req); @@ -48,7 +48,7 @@ public async Async.Task Get_UrlParameterRequired() { [Fact] public async Async.Task Get_MissingNode() { - var func = new AgentRegistration(Logger, Context); + var func = new AgentRegistration(LoggerProvider.CreateLogger(), Context); var req = TestHttpRequestData.Empty("GET"); req.SetUrlParameter("machine_id", _machineId); @@ -66,7 +66,7 @@ public async Async.Task Get_MissingPool() { await Context.InsertAll( new Node(_poolName, _machineId, _poolId, "1.0.0")); - var func = new AgentRegistration(Logger, Context); + var func = new AgentRegistration(LoggerProvider.CreateLogger(), Context); var req = TestHttpRequestData.Empty("GET"); req.SetUrlParameter("machine_id", _machineId); @@ -85,7 +85,7 @@ await Context.InsertAll( new Node(_poolName, _machineId, _poolId, "1.0.0"), new Pool(_poolName, _poolId, Os.Linux, false, Architecture.x86_64, PoolState.Init, null)); - var func = new AgentRegistration(Logger, Context); + var func = new AgentRegistration(LoggerProvider.CreateLogger(), Context); var req = TestHttpRequestData.Empty("GET"); req.SetUrlParameter("machine_id", _machineId); @@ -104,7 +104,7 @@ public async Async.Task Post_SetsDefaultVersion_IfNotSupplied() { await Context.InsertAll( new Pool(_poolName, _poolId, Os.Linux, false, Architecture.x86_64, PoolState.Init, null)); - var func = new AgentRegistration(Logger, Context); + var func = new AgentRegistration(LoggerProvider.CreateLogger(), Context); var req = TestHttpRequestData.Empty("POST"); req.SetUrlParameter("machine_id", _machineId); @@ -125,7 +125,7 @@ public async Async.Task Post_SetsCorrectVersion() { await Context.InsertAll( new Pool(_poolName, _poolId, Os.Linux, false, Architecture.x86_64, PoolState.Init, null)); - var func = new AgentRegistration(Logger, Context); + var func = new AgentRegistration(LoggerProvider.CreateLogger(), Context); var req = TestHttpRequestData.Empty("POST"); req.SetUrlParameter("machine_id", _machineId); @@ -148,7 +148,7 @@ await Context.InsertAll( new Node(PoolName.Parse("another-pool"), _machineId, _poolId, "1.0.0"), new Pool(_poolName, _poolId, Os.Linux, false, Architecture.x86_64, PoolState.Init, null)); - var func = new AgentRegistration(Logger, Context); + var func = new AgentRegistration(LoggerProvider.CreateLogger(), Context); var req = TestHttpRequestData.Empty("POST"); req.SetUrlParameter("machine_id", _machineId); @@ -171,7 +171,7 @@ public async Async.Task Post_ChecksRequiredParameters(string parameterToSkip) { await Context.InsertAll( new Pool(_poolName, _poolId, Os.Linux, false, Architecture.x86_64, PoolState.Init, null)); - var func = new AgentRegistration(Logger, Context); + var func = new AgentRegistration(LoggerProvider.CreateLogger(), Context); var req = TestHttpRequestData.Empty("POST"); if (parameterToSkip != "machine_id") { diff --git a/src/ApiService/IntegrationTests/AuthTests.cs b/src/ApiService/IntegrationTests/AuthTests.cs index 5b1e1fa353..3daad33d5b 100644 --- a/src/ApiService/IntegrationTests/AuthTests.cs +++ b/src/ApiService/IntegrationTests/AuthTests.cs @@ -1,5 +1,6 @@ using FluentAssertions; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service; using Xunit; using Xunit.Abstractions; diff --git a/src/ApiService/IntegrationTests/ContainersTests.cs b/src/ApiService/IntegrationTests/ContainersTests.cs index da3c9fea78..4d8a4add4a 100644 --- a/src/ApiService/IntegrationTests/ContainersTests.cs +++ b/src/ApiService/IntegrationTests/ContainersTests.cs @@ -31,8 +31,6 @@ public abstract class ContainersTestBase : FunctionTestBase { public ContainersTestBase(ITestOutputHelper output, IStorage storage) : base(output, storage) { } - var auth = new TestEndpointAuthorization(RequestType.NoAuthorization, Logger, Context); - var func = new ContainersFunction(Logger, auth, Context); [Fact] public async Async.Task CanDelete() { var containerName = Container.Parse("test"); @@ -41,7 +39,7 @@ public async Async.Task CanDelete() { var msg = TestHttpRequestData.FromJson("DELETE", new ContainerDelete(containerName)); - var func = new ContainersFunction(Logger, Context); + var func = new ContainersFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(msg); Assert.Equal(HttpStatusCode.OK, result.StatusCode); @@ -56,7 +54,7 @@ public async Async.Task CanPost_New() { var containerName = Container.Parse("test"); var msg = TestHttpRequestData.FromJson("POST", new ContainerCreate(containerName, meta)); - var func = new ContainersFunction(Logger, Context); + var func = new ContainersFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(msg); Assert.Equal(HttpStatusCode.OK, result.StatusCode); @@ -79,7 +77,7 @@ public async Async.Task CanPost_Existing() { var metadata = new Dictionary { { "some", "value" } }; var msg = TestHttpRequestData.FromJson("POST", new ContainerCreate(containerName, metadata)); - var func = new ContainersFunction(Logger, Context); + var func = new ContainersFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(msg); Assert.Equal(HttpStatusCode.OK, result.StatusCode); @@ -102,7 +100,7 @@ public async Async.Task Get_Existing() { var msg = TestHttpRequestData.FromJson("GET", new ContainerGet(containerName)); - var func = new ContainersFunction(Logger, Context); + var func = new ContainersFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(msg); Assert.Equal(HttpStatusCode.OK, result.StatusCode); @@ -116,7 +114,7 @@ public async Async.Task Get_Missing_Fails() { var container = Container.Parse("container"); var msg = TestHttpRequestData.FromJson("GET", new ContainerGet(container)); - var func = new ContainersFunction(Logger, Context); + var func = new ContainersFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(msg); Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode); } @@ -130,7 +128,7 @@ public async Async.Task List_Existing() { var msg = TestHttpRequestData.Empty("GET"); // this means list all - var func = new ContainersFunction(Logger, Context); + var func = new ContainersFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(msg); Assert.Equal(HttpStatusCode.OK, result.StatusCode); @@ -168,7 +166,7 @@ public async Async.Task BadContainerNameProducesGoodErrorMessage() { // use anonymous type so we can send an invalid name var msg = TestHttpRequestData.FromJson("POST", new { Name = "AbCd" }); - var func = new ContainersFunction(Logger, Context); + var func = new ContainersFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(msg); Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode); diff --git a/src/ApiService/IntegrationTests/EndpointAuthTests.cs b/src/ApiService/IntegrationTests/EndpointAuthTests.cs index 6a1355362e..bdcb3d7988 100644 --- a/src/ApiService/IntegrationTests/EndpointAuthTests.cs +++ b/src/ApiService/IntegrationTests/EndpointAuthTests.cs @@ -34,7 +34,7 @@ private Task CheckUserAdmin() { new UserInfo(ApplicationId: _applicationId, ObjectId: _userObjectId, "upn"), new List()); - var auth = new EndpointAuthorization(Context, Logger, null!); + var auth = new EndpointAuthorization(Context, LoggerProvider.CreateLogger(), null!); return auth.CheckRequireAdmins(userAuthInfo); } diff --git a/src/ApiService/IntegrationTests/EventsTests.cs b/src/ApiService/IntegrationTests/EventsTests.cs index b5b4e03a87..d711f95c0c 100644 --- a/src/ApiService/IntegrationTests/EventsTests.cs +++ b/src/ApiService/IntegrationTests/EventsTests.cs @@ -46,7 +46,7 @@ public async Async.Task BlobIsCreatedAndIsAccessible() { ping.Should().NotBeNull(); var msg = TestHttpRequestData.FromJson("GET", new EventsGet(ping.PingId)); - var func = new EventsFunction(Logger, Context); + var func = new EventsFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(msg); result.StatusCode.Should().Be(HttpStatusCode.OK); diff --git a/src/ApiService/IntegrationTests/JinjaToScribanMigrationTests.cs b/src/ApiService/IntegrationTests/JinjaToScribanMigrationTests.cs index 09387877d7..f44906c971 100644 --- a/src/ApiService/IntegrationTests/JinjaToScribanMigrationTests.cs +++ b/src/ApiService/IntegrationTests/JinjaToScribanMigrationTests.cs @@ -4,6 +4,7 @@ using FluentAssertions; using IntegrationTests.Fakes; using Microsoft.OneFuzz.Service; +using Microsoft.OneFuzz.Service.Functions; using Xunit; using Xunit.Abstractions; using Async = System.Threading.Tasks; @@ -37,7 +38,7 @@ public async Async.Task Dry_Run_Does_Not_Make_Changes() { var notificationBefore = r.OkV!; var adoTemplateBefore = (notificationBefore.Config as AdoTemplate)!; - var func = new JinjaToScribanMigrationFunction(Logger, Context); + var func = new JinjaToScribanMigrationFunction(LoggerProvider.CreateLogger(), Context); var req = new JinjaToScribanMigrationPost(DryRun: true); var result = await func.Run(TestHttpRequestData.FromJson("POST", req)); @@ -72,7 +73,7 @@ public async Async.Task Migration_Happens_When_Not_Dry_run() { var notificationBefore = r.OkV!; var adoTemplateBefore = (notificationBefore.Config as AdoTemplate)!; - var func = new JinjaToScribanMigrationFunction(Logger, Context); + var func = new JinjaToScribanMigrationFunction(LoggerProvider.CreateLogger(), Context); var req = new JinjaToScribanMigrationPost(); var result = await func.Run(TestHttpRequestData.FromJson("POST", req)); @@ -151,7 +152,7 @@ public async Async.Task All_ADO_Fields_Are_Migrated() { var notificationBefore = r.OkV!; var adoTemplateBefore = (notificationBefore.Config as AdoTemplate)!; - var func = new JinjaToScribanMigrationFunction(Logger, Context); + var func = new JinjaToScribanMigrationFunction(LoggerProvider.CreateLogger(), Context); var req = new JinjaToScribanMigrationPost(); var result = await func.Run(TestHttpRequestData.FromJson("POST", req)); @@ -200,7 +201,7 @@ public async Async.Task All_Github_Fields_Are_Migrated() { var notificationBefore = r.OkV!; var githubTemplateBefore = (notificationBefore.Config as GithubIssuesTemplate)!; - var func = new JinjaToScribanMigrationFunction(Logger, Context); + var func = new JinjaToScribanMigrationFunction(LoggerProvider.CreateLogger(), Context); var req = new JinjaToScribanMigrationPost(); var result = await func.Run(TestHttpRequestData.FromJson("POST", req)); @@ -252,7 +253,7 @@ public async Async.Task Teams_Template_Not_Migrated() { var notificationBefore = r.OkV!; var teamsTemplateBefore = (notificationBefore.Config as TeamsTemplate)!; - var func = new JinjaToScribanMigrationFunction(Logger, Context); + var func = new JinjaToScribanMigrationFunction(LoggerProvider.CreateLogger(), Context); var req = new JinjaToScribanMigrationPost(); var result = await func.Run(TestHttpRequestData.FromJson("POST", req)); @@ -304,7 +305,7 @@ public async Async.Task Can_Migrate_Multiple_Notification_Configs() { var githubNotificationBefore = r.OkV!; var githubTemplateBefore = (githubNotificationBefore.Config as GithubIssuesTemplate)!; - var func = new JinjaToScribanMigrationFunction(Logger, Context); + var func = new JinjaToScribanMigrationFunction(LoggerProvider.CreateLogger(), Context); var req = new JinjaToScribanMigrationPost(); var result = await func.Run(TestHttpRequestData.FromJson("POST", req)); diff --git a/src/ApiService/IntegrationTests/JobsTests.cs b/src/ApiService/IntegrationTests/JobsTests.cs index 365df56d88..f52bccd373 100644 --- a/src/ApiService/IntegrationTests/JobsTests.cs +++ b/src/ApiService/IntegrationTests/JobsTests.cs @@ -31,7 +31,7 @@ public JobsTestBase(ITestOutputHelper output, IStorage storage) [Fact] public async Async.Task Delete_NonExistentJob_Fails() { - var func = new Jobs(Context, Logger); + var func = new Jobs(Context, LoggerProvider.CreateLogger()); var ctx = new TestFunctionContext(); var result = await func.Run(TestHttpRequestData.FromJson("DELETE", new JobGet(_jobId)), ctx); @@ -46,7 +46,7 @@ public async Async.Task Delete_ExistingJob_SetsStoppingState() { await Context.InsertAll( new Job(_jobId, JobState.Enabled, _config)); - var func = new Jobs(Context, Logger); + var func = new Jobs(Context, LoggerProvider.CreateLogger()); var ctx = new TestFunctionContext(); var result = await func.Run(TestHttpRequestData.FromJson("DELETE", new JobGet(_jobId)), ctx); @@ -65,7 +65,7 @@ public async Async.Task Delete_ExistingStoppedJob_DoesNotSetStoppingState() { await Context.InsertAll( new Job(_jobId, JobState.Stopped, _config)); - var func = new Jobs(Context, Logger); + var func = new Jobs(Context, LoggerProvider.CreateLogger()); var ctx = new TestFunctionContext(); var result = await func.Run(TestHttpRequestData.FromJson("DELETE", new JobGet(_jobId)), ctx); @@ -85,7 +85,7 @@ public async Async.Task Get_CanFindSpecificJob() { await Context.InsertAll( new Job(_jobId, JobState.Stopped, _config)); - var func = new Jobs(Context, Logger); + var func = new Jobs(Context, LoggerProvider.CreateLogger()); var ctx = new TestFunctionContext(); var result = await func.Run(TestHttpRequestData.FromJson("GET", new JobSearch(JobId: _jobId)), ctx); @@ -104,7 +104,7 @@ await Context.InsertAll( new Job(Guid.NewGuid(), JobState.Enabled, _config), new Job(Guid.NewGuid(), JobState.Stopped, _config)); - var func = new Jobs(Context, Logger); + var func = new Jobs(Context, LoggerProvider.CreateLogger()); var req = new JobSearch(State: new List { JobState.Enabled }); var ctx = new TestFunctionContext(); @@ -123,7 +123,7 @@ await Context.InsertAll( new Job(Guid.NewGuid(), JobState.Enabled, _config), new Job(Guid.NewGuid(), JobState.Stopped, _config)); - var func = new Jobs(Context, Logger); + var func = new Jobs(Context, LoggerProvider.CreateLogger()); var req = new JobSearch(State: new List { JobState.Enabled, JobState.Stopping }); var ctx = new TestFunctionContext(); @@ -138,7 +138,7 @@ await Context.InsertAll( [Fact] public async Async.Task Post_CreatesJob_AndContainer() { - var func = new Jobs(Context, Logger); + var func = new Jobs(Context, LoggerProvider.CreateLogger()); // need user credentials to put into the job object var ctx = new TestFunctionContext(); diff --git a/src/ApiService/IntegrationTests/NodeTests.cs b/src/ApiService/IntegrationTests/NodeTests.cs index 8900fb9d6f..3980966689 100644 --- a/src/ApiService/IntegrationTests/NodeTests.cs +++ b/src/ApiService/IntegrationTests/NodeTests.cs @@ -36,7 +36,7 @@ public NodeTestBase(ITestOutputHelper output, IStorage storage) [Fact] public async Async.Task Search_SpecificNode_NotFound_ReturnsNotFound() { var req = new NodeSearch(MachineId: _machineId); - var func = new NodeFunction(Logger, Context); + var func = new NodeFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(TestHttpRequestData.FromJson("GET", req)); Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode); } @@ -47,7 +47,7 @@ await Context.InsertAll( new Node(_poolName, _machineId, null, _version)); var req = new NodeSearch(MachineId: _machineId); - var func = new NodeFunction(Logger, Context); + var func = new NodeFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(TestHttpRequestData.FromJson("GET", req)); Assert.Equal(HttpStatusCode.OK, result.StatusCode); @@ -59,7 +59,7 @@ await Context.InsertAll( [Fact] public async Async.Task Search_MultipleNodes_CanFindNone() { var req = new NodeSearch(); - var func = new NodeFunction(Logger, Context); + var func = new NodeFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(TestHttpRequestData.FromJson("GET", req)); Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal("[]", BodyAsString(result)); @@ -74,7 +74,7 @@ await Context.InsertAll( var req = new NodeSearch(PoolName: _poolName); - var func = new NodeFunction(Logger, Context); + var func = new NodeFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(TestHttpRequestData.FromJson("GET", req)); Assert.Equal(HttpStatusCode.OK, result.StatusCode); @@ -92,7 +92,7 @@ await Context.InsertAll( var req = new NodeSearch(ScalesetId: _scalesetId); - var func = new NodeFunction(Logger, Context); + var func = new NodeFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(TestHttpRequestData.FromJson("GET", req)); Assert.Equal(HttpStatusCode.OK, result.StatusCode); @@ -110,7 +110,7 @@ await Context.InsertAll( var req = new NodeSearch(State: new List { NodeState.Busy }); - var func = new NodeFunction(Logger, Context); + var func = new NodeFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(TestHttpRequestData.FromJson("GET", req)); Assert.Equal(HttpStatusCode.OK, result.StatusCode); @@ -129,7 +129,7 @@ await Context.InsertAll( var req = new NodeSearch(State: new List { NodeState.Free, NodeState.Busy }); - var func = new NodeFunction(Logger, Context); + var func = new NodeFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(TestHttpRequestData.FromJson("GET", req)); Assert.Equal(HttpStatusCode.OK, result.StatusCode); diff --git a/src/ApiService/IntegrationTests/PoolTests.cs b/src/ApiService/IntegrationTests/PoolTests.cs index 437120291a..4de4a8ad1a 100644 --- a/src/ApiService/IntegrationTests/PoolTests.cs +++ b/src/ApiService/IntegrationTests/PoolTests.cs @@ -48,7 +48,7 @@ await Context.InsertAll( await Context.Queue.CreateQueue(Context.PoolOperations.GetPoolQueue(_poolId), StorageType.Corpus); // use test class to override instance ID - Context.Containers = new TestContainers(Logger, Context.Storage, Context.ServiceConfiguration); + Context.Containers = new TestContainers(LoggerProvider.CreateLogger(), Context.Storage, Context.ServiceConfiguration); var req = new PoolSearch(PoolId: _poolId); var func = new PoolFunction(Context); @@ -76,7 +76,7 @@ await Context.InsertAll( await Context.Queue.CreateQueue(Context.PoolOperations.GetPoolQueue(_poolId), StorageType.Corpus); // use test class to override instance ID - Context.Containers = new TestContainers(Logger, Context.Storage, Context.ServiceConfiguration); + Context.Containers = new TestContainers(LoggerProvider.CreateLogger(), Context.Storage, Context.ServiceConfiguration); var req = new PoolSearch(Name: _poolName); var func = new PoolFunction(Context); @@ -166,7 +166,7 @@ await Context.InsertAll( new InstanceConfig(Context.ServiceConfiguration.OneFuzzInstanceName!) { Admins = new[] { _userObjectId } }); // needed for admin check // need to override instance id - Context.Containers = new TestContainers(Logger, Context.Storage, Context.ServiceConfiguration); + Context.Containers = new TestContainers(LoggerProvider.CreateLogger(), Context.Storage, Context.ServiceConfiguration); var func = new PoolFunction(Context); var req = new PoolCreate(Name: _poolName, Os.Linux, Architecture.x86_64, true); diff --git a/src/ApiService/IntegrationTests/ReproVmssTests.cs b/src/ApiService/IntegrationTests/ReproVmssTests.cs index 83b274f4cc..dea482cc2e 100644 --- a/src/ApiService/IntegrationTests/ReproVmssTests.cs +++ b/src/ApiService/IntegrationTests/ReproVmssTests.cs @@ -30,7 +30,7 @@ public ReproVmssTestBase(ITestOutputHelper output, IStorage storage) [Fact] public async Async.Task GetMissingVmFails() { - var func = new ReproVmss(Logger, Context); + var func = new ReproVmss(LoggerProvider.CreateLogger(), Context); var req = new ReproGet(VmId: Guid.NewGuid()); var ctx = new TestFunctionContext(); var result = await func.Run(TestHttpRequestData.FromJson("GET", req), ctx); @@ -42,7 +42,7 @@ public async Async.Task GetMissingVmFails() { [Fact] public async Async.Task GetAvailableVMsCanReturnEmpty() { - var func = new ReproVmss(Logger, Context); + var func = new ReproVmss(LoggerProvider.CreateLogger(), Context); var req = new ReproGet(VmId: null); // this means "all available" var ctx = new TestFunctionContext(); var result = await func.Run(TestHttpRequestData.FromJson("GET", req), ctx); @@ -62,7 +62,7 @@ await Context.InsertAll( Auth: new SecretValue(new Authentication("", "", "")), Os: Os.Linux)); - var func = new ReproVmss(Logger, Context); + var func = new ReproVmss(LoggerProvider.CreateLogger(), Context); var req = new ReproGet(VmId: null); // this means "all available" var ctx = new TestFunctionContext(); var result = await func.Run(TestHttpRequestData.FromJson("GET", req), ctx); @@ -86,7 +86,7 @@ await Context.InsertAll( Auth: new SecretAddress(secretUri), Os: Os.Linux)); - var func = new ReproVmss(Logger, Context); + var func = new ReproVmss(LoggerProvider.CreateLogger(), Context); var req = new ReproGet(VmId: vmId); var ctx = new TestFunctionContext(); var result = await func.Run(TestHttpRequestData.FromJson("GET", req), ctx); @@ -113,7 +113,7 @@ await Context.InsertAll( Os: Os.Linux, State: VmState.Stopped)); - var func = new ReproVmss(Logger, Context); + var func = new ReproVmss(LoggerProvider.CreateLogger(), Context); var req = new ReproGet(VmId: null); // this means "all available" var ctx = new TestFunctionContext(); var result = await func.Run(TestHttpRequestData.FromJson("GET", req), ctx); @@ -127,7 +127,7 @@ public async Async.Task CannotCreateVMForMissingReport() { var ctx = new TestFunctionContext(); ctx.SetUserAuthInfo(new UserInfo(Guid.NewGuid(), Guid.NewGuid(), "upn")); - var func = new ReproVmss(Logger, Context); + var func = new ReproVmss(LoggerProvider.CreateLogger(), Context); var req = new ReproCreate(Container.Parse("abcd"), "/", 12345); var result = await func.Run(TestHttpRequestData.FromJson("POST", req), ctx); Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode); @@ -184,7 +184,7 @@ public async Async.Task CannotCreateVMForMissingTask() { var ctx = new TestFunctionContext(); ctx.SetUserAuthInfo(new UserInfo(Guid.NewGuid(), Guid.NewGuid(), "upn")); - var func = new ReproVmss(Logger, Context); + var func = new ReproVmss(LoggerProvider.CreateLogger(), Context); var req = new ReproCreate(container, filename, 12345); var result = await func.Run(TestHttpRequestData.FromJson("POST", req), ctx); Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode); @@ -214,7 +214,7 @@ await Context.InsertAll( var ctx = new TestFunctionContext(); ctx.SetUserAuthInfo(new UserInfo(Guid.NewGuid(), Guid.NewGuid(), "upn")); - var func = new ReproVmss(Logger, Context); + var func = new ReproVmss(LoggerProvider.CreateLogger(), Context); var req = new ReproCreate(container, filename, 12345); var result = await func.Run(TestHttpRequestData.FromJson("POST", req), ctx); Assert.Equal(HttpStatusCode.OK, result.StatusCode); diff --git a/src/ApiService/IntegrationTests/ScalesetTests.cs b/src/ApiService/IntegrationTests/ScalesetTests.cs index 441ed9dc8f..6761b74367 100644 --- a/src/ApiService/IntegrationTests/ScalesetTests.cs +++ b/src/ApiService/IntegrationTests/ScalesetTests.cs @@ -28,7 +28,7 @@ public ScalesetTestBase(ITestOutputHelper output, IStorage storage) [Fact] public async Async.Task Search_SpecificScaleset_ReturnsErrorIfNoneFound() { var req = new ScalesetSearch(ScalesetId: ScalesetId.Parse(Guid.NewGuid().ToString())); - var func = new ScalesetFunction(Logger, Context); + var func = new ScalesetFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(TestHttpRequestData.FromJson("GET", req)); Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode); @@ -39,7 +39,7 @@ public async Async.Task Search_SpecificScaleset_ReturnsErrorIfNoneFound() { [Fact] public async Async.Task Search_AllScalesets_ReturnsEmptyIfNoneFound() { var req = new ScalesetSearch(); - var func = new ScalesetFunction(Logger, Context); + var func = new ScalesetFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(TestHttpRequestData.FromJson("GET", req)); Assert.Equal(HttpStatusCode.OK, result.StatusCode); @@ -62,7 +62,7 @@ await Context.InsertAll( ); var req = new ScalesetSearch(ScalesetId: scalesetId); - var func = new ScalesetFunction(Logger, Context); + var func = new ScalesetFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Run(TestHttpRequestData.FromJson("GET", req)); Assert.Equal(HttpStatusCode.OK, result.StatusCode); @@ -89,7 +89,7 @@ await Context.InsertAll( SpotInstances: false, Tags: new Dictionary()); - var func = new ScalesetFunction(Logger, Context); + var func = new ScalesetFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Admin(TestHttpRequestData.FromJson("POST", req)); Assert.Equal(HttpStatusCode.OK, result.StatusCode); @@ -114,7 +114,7 @@ public async Async.Task Create_Scaleset_Under_NonExistent_Pool_Provides_Error() SpotInstances: false, Tags: new Dictionary()); - var func = new ScalesetFunction(Logger, Context); + var func = new ScalesetFunction(LoggerProvider.CreateLogger(), Context); var result = await func.Admin(TestHttpRequestData.FromJson("POST", req)); Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode); From 257e0e3e601b99940e81069a35ea3ba2f167b3de Mon Sep 17 00:00:00 2001 From: stas Date: Wed, 7 Jun 2023 09:44:44 -0700 Subject: [PATCH 5/8] if debug enable developer mode --- src/ApiService/ApiService/Program.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ApiService/ApiService/Program.cs b/src/ApiService/ApiService/Program.cs index ece7d1c419..15e7200cc6 100644 --- a/src/ApiService/ApiService/Program.cs +++ b/src/ApiService/ApiService/Program.cs @@ -164,7 +164,11 @@ public static async Async.Task Main() { //this is a must, to tell the host that worker logging is done by us builder.Services.Configure(workerOptions => workerOptions.Capabilities["WorkerApplicationInsightsLoggingEnabled"] = bool.TrueString); builder.AddApplicationInsights(options => { +#if DEBUG + options.DeveloperMode = true; +#else options.DeveloperMode = false; +#endif options.EnableDependencyTrackingTelemetryModule = true; }); builder.AddApplicationInsightsLogger(); From a2054f83d82df3160962c59edbfc408eb8267ceb Mon Sep 17 00:00:00 2001 From: stas Date: Wed, 7 Jun 2023 09:58:24 -0700 Subject: [PATCH 6/8] format --- src/ApiService/ApiService/Functions/AgentCanSchedule.cs | 2 +- src/ApiService/ApiService/Functions/InstanceConfig.cs | 2 +- src/ApiService/ApiService/Functions/Notifications.cs | 2 +- src/ApiService/ApiService/Functions/Proxy.cs | 4 ++-- src/ApiService/ApiService/Functions/ValidateScriban.cs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ApiService/ApiService/Functions/AgentCanSchedule.cs b/src/ApiService/ApiService/Functions/AgentCanSchedule.cs index 7302ea00d9..4a916dc60d 100644 --- a/src/ApiService/ApiService/Functions/AgentCanSchedule.cs +++ b/src/ApiService/ApiService/Functions/AgentCanSchedule.cs @@ -1,7 +1,7 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; namespace Microsoft.OneFuzz.Service.Functions; public class AgentCanSchedule { diff --git a/src/ApiService/ApiService/Functions/InstanceConfig.cs b/src/ApiService/ApiService/Functions/InstanceConfig.cs index 5300817e1c..1c50be14d0 100644 --- a/src/ApiService/ApiService/Functions/InstanceConfig.cs +++ b/src/ApiService/ApiService/Functions/InstanceConfig.cs @@ -2,8 +2,8 @@ using System.Threading.Tasks; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; namespace Microsoft.OneFuzz.Service.Functions; public class InstanceConfig { diff --git a/src/ApiService/ApiService/Functions/Notifications.cs b/src/ApiService/ApiService/Functions/Notifications.cs index e94dcf5a4f..235ef1a6a1 100644 --- a/src/ApiService/ApiService/Functions/Notifications.cs +++ b/src/ApiService/ApiService/Functions/Notifications.cs @@ -1,8 +1,8 @@ using System.Net; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; namespace Microsoft.OneFuzz.Service.Functions; public class Notifications { diff --git a/src/ApiService/ApiService/Functions/Proxy.cs b/src/ApiService/ApiService/Functions/Proxy.cs index 243f23bdc9..41eb56c230 100644 --- a/src/ApiService/ApiService/Functions/Proxy.cs +++ b/src/ApiService/ApiService/Functions/Proxy.cs @@ -1,8 +1,8 @@ using System.Net; using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; using VmProxy = Microsoft.OneFuzz.Service.Proxy; namespace Microsoft.OneFuzz.Service.Functions; @@ -10,7 +10,7 @@ public class Proxy { private readonly ILogger _log; private readonly IOnefuzzContext _context; - public Proxy(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { + public Proxy(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { _log = log; _context = context; } diff --git a/src/ApiService/ApiService/Functions/ValidateScriban.cs b/src/ApiService/ApiService/Functions/ValidateScriban.cs index c6e64bef8b..bf66d29fac 100644 --- a/src/ApiService/ApiService/Functions/ValidateScriban.cs +++ b/src/ApiService/ApiService/Functions/ValidateScriban.cs @@ -1,7 +1,7 @@ using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -using Microsoft.OneFuzz.Service.Auth; using Microsoft.Extensions.Logging; +using Microsoft.OneFuzz.Service.Auth; namespace Microsoft.OneFuzz.Service.Functions; public class ValidateScriban { From d89abc4d464062a123abdbc067862f06607ecfba Mon Sep 17 00:00:00 2001 From: stas Date: Wed, 7 Jun 2023 10:51:06 -0700 Subject: [PATCH 7/8] resolving more merging issues --- src/ApiService/ApiService/Functions/AgentCommands.cs | 2 +- src/ApiService/ApiService/Functions/NodeAddSshKey.cs | 2 +- src/ApiService/ApiService/Functions/NotificationsTest.cs | 2 +- src/ApiService/ApiService/Functions/Proxy.cs | 2 +- src/ApiService/ApiService/Functions/WebhookLogs.cs | 2 +- src/ApiService/ApiService/Functions/WebhookPing.cs | 2 +- src/ApiService/ApiService/Functions/Webhooks.cs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ApiService/ApiService/Functions/AgentCommands.cs b/src/ApiService/ApiService/Functions/AgentCommands.cs index 602755f9f1..db97236bd3 100644 --- a/src/ApiService/ApiService/Functions/AgentCommands.cs +++ b/src/ApiService/ApiService/Functions/AgentCommands.cs @@ -8,7 +8,7 @@ public class AgentCommands { private readonly ILogger _log; private readonly IOnefuzzContext _context; - public AgentCommands(ILogger log, IOnefuzzContext context) { + public AgentCommands(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } diff --git a/src/ApiService/ApiService/Functions/NodeAddSshKey.cs b/src/ApiService/ApiService/Functions/NodeAddSshKey.cs index 73da435000..1d7506cccb 100644 --- a/src/ApiService/ApiService/Functions/NodeAddSshKey.cs +++ b/src/ApiService/ApiService/Functions/NodeAddSshKey.cs @@ -7,7 +7,7 @@ namespace Microsoft.OneFuzz.Service.Functions; public class NodeAddSshKey { private readonly IOnefuzzContext _context; - public NodeAddSshKey(IEndpointAuthorization auth, IOnefuzzContext context) { + public NodeAddSshKey(IOnefuzzContext context) { _context = context; } diff --git a/src/ApiService/ApiService/Functions/NotificationsTest.cs b/src/ApiService/ApiService/Functions/NotificationsTest.cs index 268311d402..53287aa37a 100644 --- a/src/ApiService/ApiService/Functions/NotificationsTest.cs +++ b/src/ApiService/ApiService/Functions/NotificationsTest.cs @@ -9,7 +9,7 @@ public class NotificationsTest { private readonly ILogger _log; private readonly IOnefuzzContext _context; - public NotificationsTest(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { + public NotificationsTest(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } diff --git a/src/ApiService/ApiService/Functions/Proxy.cs b/src/ApiService/ApiService/Functions/Proxy.cs index 41eb56c230..5d1d7bcfee 100644 --- a/src/ApiService/ApiService/Functions/Proxy.cs +++ b/src/ApiService/ApiService/Functions/Proxy.cs @@ -10,7 +10,7 @@ public class Proxy { private readonly ILogger _log; private readonly IOnefuzzContext _context; - public Proxy(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { + public Proxy(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } diff --git a/src/ApiService/ApiService/Functions/WebhookLogs.cs b/src/ApiService/ApiService/Functions/WebhookLogs.cs index 9206dff3af..6d257aa097 100644 --- a/src/ApiService/ApiService/Functions/WebhookLogs.cs +++ b/src/ApiService/ApiService/Functions/WebhookLogs.cs @@ -9,7 +9,7 @@ public class WebhookLogs { private readonly ILogger _log; private readonly IOnefuzzContext _context; - public WebhookLogs(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { + public WebhookLogs(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } diff --git a/src/ApiService/ApiService/Functions/WebhookPing.cs b/src/ApiService/ApiService/Functions/WebhookPing.cs index 6828c599e1..a0c4534e8b 100644 --- a/src/ApiService/ApiService/Functions/WebhookPing.cs +++ b/src/ApiService/ApiService/Functions/WebhookPing.cs @@ -9,7 +9,7 @@ public class WebhookPing { private readonly ILogger _log; private readonly IOnefuzzContext _context; - public WebhookPing(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { + public WebhookPing(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } diff --git a/src/ApiService/ApiService/Functions/Webhooks.cs b/src/ApiService/ApiService/Functions/Webhooks.cs index 76fee6ce70..44ce85b4fc 100644 --- a/src/ApiService/ApiService/Functions/Webhooks.cs +++ b/src/ApiService/ApiService/Functions/Webhooks.cs @@ -9,7 +9,7 @@ public class Webhooks { private readonly ILogger _log; private readonly IOnefuzzContext _context; - public Webhooks(ILogger log, IEndpointAuthorization auth, IOnefuzzContext context) { + public Webhooks(ILogger log, IOnefuzzContext context) { _log = log; _context = context; } From e25e8e30bac1e69f0b471faed13a860c12f2e3de Mon Sep 17 00:00:00 2001 From: stas Date: Wed, 7 Jun 2023 10:53:36 -0700 Subject: [PATCH 8/8] add reference links to comments --- src/ApiService/ApiService/Log.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ApiService/ApiService/Log.cs b/src/ApiService/ApiService/Log.cs index 5769367d33..eefc7915ef 100644 --- a/src/ApiService/ApiService/Log.cs +++ b/src/ApiService/ApiService/Log.cs @@ -105,7 +105,7 @@ void ILogger.Log(LogLevel logLevel, EventId eventId, TState state, Excep TraceTelemetry traceTelemetry = new TraceTelemetry( formatter(state, exception), OneFuzzLogger.GetSeverityLevel(logLevel)); - + //https://github.com/microsoft/ApplicationInsights-dotnet/blob/248800626c1c31a2b4100f64a884257833b8c77f/BASE/src/Microsoft.ApplicationInsights/Extensibility/OperationCorrelationTelemetryInitializer.cs#L64 traceTelemetry.Context.Operation.Id = Activity.RootId; traceTelemetry.Context.Operation.ParentId = Activity.SpanId.ToString(); this.PopulateTelemetry(traceTelemetry, state, eventId); @@ -117,6 +117,7 @@ void ILogger.Log(LogLevel logLevel, EventId eventId, TState state, Excep Message = exception.Message, SeverityLevel = OneFuzzLogger.GetSeverityLevel(logLevel), }; + //https://github.com/microsoft/ApplicationInsights-dotnet/blob/248800626c1c31a2b4100f64a884257833b8c77f/BASE/src/Microsoft.ApplicationInsights/Extensibility/OperationCorrelationTelemetryInitializer.cs#L64 exceptionTelemetry.Context.Operation.Id = Activity.RootId; exceptionTelemetry.Context.Operation.ParentId = Activity.SpanId.ToString();