Skip to content
This repository was archived by the owner on Nov 1, 2023. It is now read-only.

Commit 8a230da

Browse files
author
stas
committed
make logs scoped
1 parent 3da0fd6 commit 8a230da

File tree

14 files changed

+146
-90
lines changed

14 files changed

+146
-90
lines changed

src/ApiService/ApiService/Log.cs

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -133,21 +133,31 @@ public interface ILogTracer
133133
void Info(string message);
134134
void Warning(string message);
135135

136-
ILogTracer AddTag(string k, string v);
137-
ILogTracer AddTags((string, string)[]? tags);
136+
ILogTracer WithTag(string k, string v);
137+
ILogTracer WithTags((string, string)[]? tags);
138138
}
139139

140-
public class LogTracer : ILogTracer
140+
internal interface ILogTracerInternal : ILogTracer
141+
{
142+
void ReplaceCorrelationId(Guid newCorrelationId);
143+
void AddTags((string, string)[] tags);
144+
}
145+
146+
147+
148+
public class LogTracer : ILogTracerInternal
141149
{
142150
private string? GetCaller()
143151
{
144152
return new StackTrace()?.GetFrame(2)?.GetMethod()?.DeclaringType?.FullName;
145153
}
146154

155+
private Guid _correlationId;
147156
private List<ILog> _loggers;
157+
private Dictionary<string, string> _tags;
148158

149-
public Guid CorrelationId { get; }
150-
public IReadOnlyDictionary<string, string> Tags { get; }
159+
public Guid CorrelationId => _correlationId;
160+
public IReadOnlyDictionary<string, string> Tags => _tags;
151161

152162

153163
private static List<KeyValuePair<string, string>> ConvertTags((string, string)[]? tags)
@@ -172,17 +182,35 @@ private static List<KeyValuePair<string, string>> ConvertTags((string, string)[]
172182

173183
public LogTracer(Guid correlationId, IReadOnlyDictionary<string, string> tags, List<ILog> loggers)
174184
{
175-
CorrelationId = correlationId;
176-
Tags = tags;
185+
_correlationId = correlationId;
186+
_tags = new(tags);
177187
_loggers = loggers;
178188
}
179189

180-
public ILogTracer AddTag(string k, string v)
190+
//Single threaded only
191+
public void ReplaceCorrelationId(Guid newCorrelationId)
192+
{
193+
_correlationId = newCorrelationId;
194+
}
195+
196+
//single threaded only
197+
public void AddTags((string, string)[] tags)
198+
{
199+
if (tags is not null)
200+
{
201+
foreach (var (k, v) in tags)
202+
{
203+
_tags[k] = v;
204+
}
205+
}
206+
}
207+
208+
public ILogTracer WithTag(string k, string v)
181209
{
182-
return AddTags(new[] { (k, v) });
210+
return WithTags(new[] { (k, v) });
183211
}
184212

185-
public ILogTracer AddTags((string, string)[]? tags)
213+
public ILogTracer WithTags((string, string)[]? tags)
186214
{
187215
var newTags = new Dictionary<string, string>(Tags);
188216
if (tags is not null)
@@ -260,7 +288,7 @@ public void ForceFlush()
260288

261289
public interface ILogTracerFactory
262290
{
263-
LogTracer MakeLogTracer(Guid correlationId, (string, string)[]? tags = null);
291+
LogTracer CreateLogTracer(Guid correlationId, (string, string)[]? tags = null);
264292
}
265293

266294
public class LogTracerFactory : ILogTracerFactory
@@ -272,7 +300,7 @@ public LogTracerFactory(List<ILog> loggers)
272300
_loggers = loggers;
273301
}
274302

275-
public LogTracer MakeLogTracer(Guid correlationId, (string, string)[]? tags = null)
303+
public LogTracer CreateLogTracer(Guid correlationId, (string, string)[]? tags = null)
276304
{
277305
return new(correlationId, tags, _loggers);
278306
}

src/ApiService/ApiService/OneFuzzTypes/Events.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public EventType GetEventType()
4343
this switch
4444
{
4545
EventNodeHeartbeat _ => EventType.NodeHeartbeat,
46+
EventInstanceConfigUpdated _ => EventType.InstanceConfigUpdated,
4647
_ => throw new NotImplementedException(),
4748
};
4849

src/ApiService/ApiService/OneFuzzTypes/Model.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ public record Task(
258258
{
259259
List<TaskEventSummary> Events { get; set; } = new List<TaskEventSummary>();
260260
List<NodeAssignment> Nodes { get; set; } = new List<NodeAssignment>();
261-
261+
}
262262
public record AzureSecurityExtensionConfig();
263263
public record GenevaExtensionConfig();
264264

@@ -341,7 +341,6 @@ public InstanceConfig(string instanceName) : this(
341341
null)
342342
{ }
343343

344-
345344
public List<Guid>? CheckAdmins(List<Guid>? value)
346345
{
347346
if (value is not null && value.Count == 0)
@@ -373,4 +372,4 @@ public ResultOk<List<string>> CheckInstanceConfig()
373372
return ResultOk<List<string>>.Error(errors);
374373
}
375374
}
376-
}
375+
}

src/ApiService/ApiService/Program.cs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,36 @@
66
using Microsoft.Extensions.Hosting;
77
using Microsoft.Extensions.DependencyInjection;
88
using ApiService.OneFuzzLib;
9-
10-
9+
using Microsoft.Azure.Functions.Worker.Middleware;
10+
using Microsoft.Azure.Functions.Worker;
1111

1212
namespace Microsoft.OneFuzz.Service;
1313

1414
public class Program
1515
{
16+
public class LoggingMiddleware : IFunctionsWorkerMiddleware
17+
{
18+
public async Async.Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
19+
{
20+
//TODO
21+
//if correlation ID is available in HTTP request
22+
//if correlation ID is available in Queue message
23+
//log.ReplaceCorrelationId
24+
25+
var log = (ILogTracerInternal?) context.InstanceServices.GetService<ILogTracer>();
26+
if (log is not null)
27+
{
28+
log.AddTags(new[] {
29+
("InvocationId", context.InvocationId.ToString())
30+
31+
});
32+
}
33+
34+
await next(context);
35+
}
36+
}
37+
38+
1639
public static List<ILog> GetLoggers()
1740
{
1841
List<ILog> loggers = new List<ILog>();
@@ -23,7 +46,7 @@ public static List<ILog> GetLoggers()
2346
{
2447
LogDestination.AppInsights => new AppInsights(),
2548
LogDestination.Console => new Console(),
26-
_ => throw new Exception(string.Format("Unhandled Log Destination type: {0}", dest)),
49+
_ => throw new Exception($"Unhandled Log Destination type: {dest}"),
2750
}
2851
);
2952
}
@@ -34,17 +57,22 @@ public static List<ILog> GetLoggers()
3457
public static void Main()
3558
{
3659
var host = new HostBuilder()
37-
.ConfigureFunctionsWorkerDefaults()
60+
.ConfigureFunctionsWorkerDefaults(
61+
builder =>
62+
{
63+
builder.UseMiddleware<LoggingMiddleware>();
64+
}
65+
)
3866
.ConfigureServices((context, services) =>
3967
services
40-
.AddSingleton<ILogTracerFactory>(_ => new LogTracerFactory(GetLoggers()))
68+
.AddScoped<ILogTracer>(_ => new LogTracerFactory(GetLoggers()).CreateLogTracer(Guid.NewGuid()))
4169
.AddSingleton<INodeOperations, NodeOperations>()
4270
.AddSingleton<IEvents, Events>()
4371
.AddSingleton<IWebhookOperations, WebhookOperations>()
4472
.AddSingleton<IWebhookMessageLogOperations, WebhookMessageLogOperations>()
4573
.AddSingleton<ITaskOperations, TaskOperations>()
4674
.AddSingleton<IQueue, Queue>()
47-
.AddSingleton<ICreds>(_ => new Creds())
75+
.AddSingleton<ICreds, Creds>()
4876
.AddSingleton<IStorage, Storage>()
4977
.AddSingleton<IProxyOperations, ProxyOperations>()
5078
.AddSingleton<IConfigOperations, ConfigOperations>()

src/ApiService/ApiService/QueueFileChanges.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ public class QueueFileChanges
1313
// https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-queue-trigger?tabs=csharp#poison-messages
1414
const int MAX_DEQUEUE_COUNT = 5;
1515

16-
private readonly ILogTracerFactory _loggerFactory;
16+
private readonly ILogTracer _log;
1717

1818
private readonly IStorage _storage;
1919

20-
public QueueFileChanges(ILogTracerFactory loggerFactory, IStorage storage)
20+
public QueueFileChanges(ILogTracer log, IStorage storage)
2121
{
22-
_loggerFactory = loggerFactory;
22+
_log = log;
2323
_storage = storage;
2424
}
2525

@@ -28,7 +28,6 @@ public Async.Task Run(
2828
[QueueTrigger("file-changes-refactored", Connection = "AzureWebJobsStorage")] string msg,
2929
int dequeueCount)
3030
{
31-
var log = _loggerFactory.MakeLogTracer(Guid.NewGuid());
3231
var fileChangeEvent = JsonSerializer.Deserialize<Dictionary<string, string>>(msg, EntityConverter.GetJsonSerializerOptions());
3332
var lastTry = dequeueCount == MAX_DEQUEUE_COUNT;
3433

@@ -44,12 +43,12 @@ public Async.Task Run(
4443

4544
const string topic = "topic";
4645
if (!fileChangeEvent.ContainsKey(topic)
47-
|| !_storage.CorpusAccounts(log).Contains(fileChangeEvent[topic]))
46+
|| !_storage.CorpusAccounts().Contains(fileChangeEvent[topic]))
4847
{
4948
return Async.Task.CompletedTask;
5049
}
5150

52-
file_added(log, fileChangeEvent, lastTry);
51+
file_added(_log, fileChangeEvent, lastTry);
5352
return Async.Task.CompletedTask;
5453
}
5554

src/ApiService/ApiService/QueueNodeHearbeat.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,32 @@ namespace Microsoft.OneFuzz.Service;
88

99
public class QueueNodeHearbeat
1010
{
11-
private readonly ILogTracerFactory _loggerFactory;
11+
private readonly ILogTracer _log;
1212

1313
private readonly IEvents _events;
1414
private readonly INodeOperations _nodes;
1515

16-
public QueueNodeHearbeat(ILogTracerFactory loggerFactory, INodeOperations nodes, IEvents events)
16+
public QueueNodeHearbeat(ILogTracer log, INodeOperations nodes, IEvents events)
1717
{
18-
_loggerFactory = loggerFactory;
18+
_log = log;
1919
_nodes = nodes;
2020
_events = events;
2121
}
2222

2323
[Function("QueueNodeHearbeat")]
2424
public async Async.Task Run([QueueTrigger("myqueue-items", Connection = "AzureWebJobsStorage")] string msg)
2525
{
26-
var log = _loggerFactory.MakeLogTracer(Guid.NewGuid());
27-
log.Info($"heartbeat: {msg}");
26+
_log.Info($"heartbeat: {msg}");
2827

2928
var hb = JsonSerializer.Deserialize<NodeHeartbeatEntry>(msg, EntityConverter.GetJsonSerializerOptions()).EnsureNotNull($"wrong data {msg}");
3029

3130
var node = await _nodes.GetByMachineId(hb.NodeId);
3231

33-
var log2 = log.AddTag("NodeId", hb.NodeId.ToString());
32+
var log = _log.WithTag("NodeId", hb.NodeId.ToString());
3433

3534
if (node == null)
3635
{
37-
log2.Warning($"invalid node id: {hb.NodeId}");
36+
log.Warning($"invalid node id: {hb.NodeId}");
3837
return;
3938
}
4039

@@ -45,7 +44,7 @@ public async Async.Task Run([QueueTrigger("myqueue-items", Connection = "AzureWe
4544
if (!r.IsOk)
4645
{
4746
var (status, reason) = r.ErrorV;
48-
log2.Error($"Failed to replace heartbeat info due to [{status}] {reason}");
47+
log.Error($"Failed to replace heartbeat info due to [{status}] {reason}");
4948
}
5049

5150
// TODO: do we still send event if we fail do update the table ?

src/ApiService/ApiService/QueueProxyHeartbeat.cs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,31 @@ namespace Microsoft.OneFuzz.Service;
77

88
public class QueueProxyHearbeat
99
{
10-
private readonly ILogTracerFactory _loggerFactory;
10+
private readonly ILogTracer _log;
1111

1212
private readonly IProxyOperations _proxy;
1313

14-
public QueueProxyHearbeat(ILogTracerFactory loggerFactory, IProxyOperations proxy)
14+
public QueueProxyHearbeat(ILogTracer log, IProxyOperations proxy)
1515
{
16-
_loggerFactory = loggerFactory;
16+
_log = log;
1717
_proxy = proxy;
1818
}
1919

2020
[Function("QueueProxyHearbeat")]
2121
public async Async.Task Run([QueueTrigger("myqueue-items", Connection = "AzureWebJobsStorage")] string msg)
2222
{
23-
var log = _loggerFactory.MakeLogTracer(Guid.NewGuid());
24-
25-
log.Info($"heartbeat: {msg}");
23+
_log.Info($"heartbeat: {msg}");
2624

2725
var hb = JsonSerializer.Deserialize<ProxyHeartbeat>(msg, EntityConverter.GetJsonSerializerOptions()).EnsureNotNull($"wrong data {msg}"); ;
2826
var newHb = hb with { TimeStamp = DateTimeOffset.UtcNow };
2927

3028
var proxy = await _proxy.GetByProxyId(newHb.ProxyId);
3129

32-
var log2 = log.AddTag("ProxyId", newHb.ProxyId.ToString());
30+
var log = _log.WithTag("ProxyId", newHb.ProxyId.ToString());
3331

3432
if (proxy == null)
3533
{
36-
log2.Warning($"invalid proxy id: {newHb.ProxyId}");
34+
log.Warning($"invalid proxy id: {newHb.ProxyId}");
3735
return;
3836
}
3937
var newProxy = proxy with { heartbeat = newHb };

src/ApiService/ApiService/TestHooks.cs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,50 +12,51 @@ public record FunctionInfo(string Name, string ResourceGroup, string? SlotName);
1212
public class TestHooks
1313
{
1414

15-
private readonly ILogTracerFactory _loggerFactory;
15+
private readonly ILogTracer _log;
1616
private readonly IConfigOperations _configOps;
17+
private readonly IEvents _events;
1718

18-
public TestHooks(ILogTracerFactory loggerFactory, IConfigOperations configOps)
19+
public TestHooks(ILogTracer log, IConfigOperations configOps, IEvents events)
1920
{
20-
_loggerFactory = loggerFactory;
21+
_log = log;
2122
_configOps = configOps;
23+
_events = events;
2224
}
2325

2426
[Function("Info")]
2527
public async Task<HttpResponseData> Info([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/info")] HttpRequestData req)
2628
{
27-
var log = _loggerFactory.MakeLogTracer(Guid.NewGuid());
28-
log.Info("Creating function info response");
29+
_log.Info("Creating function info response");
2930
var response = req.CreateResponse();
3031
FunctionInfo info = new(
3132
$"{EnvironmentVariables.OneFuzz.InstanceName}",
3233
$"{EnvironmentVariables.OneFuzz.ResourceGroup}",
3334
Environment.GetEnvironmentVariable("WEBSITE_SLOT_NAME"));
3435

35-
log.Info("Returning function info");
36+
_log.Info("Returning function info");
3637
await response.WriteAsJsonAsync(info);
37-
log.Info("Returned function info");
38+
_log.Info("Returned function info");
3839
return response;
3940
}
4041

41-
4242
[Function("InstanceConfig")]
4343
public async Task<HttpResponseData> InstanceConfig([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "testhooks/instance-config")] HttpRequestData req)
4444
{
45-
var log = _loggerFactory.MakeLogTracer(Guid.NewGuid());
46-
log.Info("Fetching instance config");
45+
_log.Info("Fetching instance config");
4746
var config = await _configOps.Fetch();
4847

4948
if (config is null)
5049
{
51-
log.Error("Instance config is null");
50+
_log.Error("Instance config is null");
5251
Error err = new(ErrorCode.INVALID_REQUEST, new[] { "Instance config is null" });
5352
var resp = req.CreateResponse(HttpStatusCode.InternalServerError);
5453
await resp.WriteAsJsonAsync(err);
5554
return resp;
5655
}
5756
else
5857
{
58+
await _events.SendEvent(new EventInstanceConfigUpdated(config));
59+
5960
var resp = req.CreateResponse(HttpStatusCode.OK);
6061
await resp.WriteAsJsonAsync(config);
6162
return resp;

0 commit comments

Comments
 (0)