Skip to content

Commit 80bb2af

Browse files
authored
Add ConfigRefresher for SelfDiagnostics (#2262)
* Add MemoryMappedFileHandler for SelfDiagnostics * Rename classes and namespace. * - * Use CollectionAssert.AreEqual to compare byte[] * Add circular write logic into MemoryMappedFileHandler class * Add ConfigRefresher for SelfDiagnostics * Fix trivial compile errors * Fix trivial compile errors * Update EventSource method implementation * Update EventSource method implementation * - * Special requirement for last argument in method definition and last parameter for WriteEvent call * Add new line at end of file * Change namespace for SelfDiagnosticsInitializer * Remove redundant using namespace statement. * Remove blank line
1 parent 3bd1b42 commit 80bb2af

File tree

5 files changed

+120
-12
lines changed

5 files changed

+120
-12
lines changed

BASE/Test/Microsoft.ApplicationInsights.Test/Microsoft.ApplicationInsights.Tests/Extensibility/Implementation/Tracing/SelfDiagnostics/SelfDiagnosticsEventListenerTest.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@
99
using Microsoft.VisualStudio.TestTools.UnitTesting;
1010
using Moq;
1111

12-
// SelfDiagnosticsEventListener should be moved from SelfDiagnosticsInternals to SelfDiagnostics.
13-
// Pending on https://github.com/microsoft/ApplicationInsights-dotnet/pull/2262
14-
// Here still using this old namespace to show less changes in git diff view.
15-
using Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.SelfDiagnosticsInternals;
16-
1712
[TestClass]
1813
class SelfDiagnosticsEventListenerTest
1914
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
namespace Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.SelfDiagnostics
2+
{
3+
using System;
4+
using System.Diagnostics;
5+
using System.Diagnostics.Tracing;
6+
using System.IO;
7+
using System.Text;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
11+
/// <summary>
12+
/// SelfDiagnosticsConfigRefresher class checks a location for a configuration file
13+
/// and open a MemoryMappedFile of a configured size at the configured file path.
14+
/// The class provides a stream object with proper write position if the configuration
15+
/// file is present and valid. Otherwise, the stream object would be unavailable,
16+
/// nothing will be logged to any file.
17+
/// </summary>
18+
internal class SelfDiagnosticsConfigRefresher : IDisposable
19+
{
20+
private const int ConfigurationUpdatePeriodMilliSeconds = 10000;
21+
22+
private readonly CancellationTokenSource cancellationTokenSource;
23+
private readonly Task worker;
24+
private readonly SelfDiagnosticsConfigParser configParser;
25+
private readonly MemoryMappedFileHandler memoryMappedFileHandler;
26+
27+
private bool disposedValue;
28+
29+
// Once the configuration file is valid, an eventListener object will be created.
30+
private SelfDiagnosticsEventListener eventListener;
31+
32+
private EventLevel logEventLevel = (EventLevel)(-1);
33+
34+
public SelfDiagnosticsConfigRefresher()
35+
{
36+
this.configParser = new SelfDiagnosticsConfigParser();
37+
this.memoryMappedFileHandler = new MemoryMappedFileHandler();
38+
this.UpdateMemoryMappedFileFromConfiguration();
39+
this.cancellationTokenSource = new CancellationTokenSource();
40+
this.worker = Task.Run(() => this.Worker(this.cancellationTokenSource.Token), this.cancellationTokenSource.Token);
41+
}
42+
43+
/// <inheritdoc/>
44+
public void Dispose()
45+
{
46+
this.Dispose(true);
47+
GC.SuppressFinalize(this);
48+
}
49+
50+
private async Task Worker(CancellationToken cancellationToken)
51+
{
52+
await Task.Delay(ConfigurationUpdatePeriodMilliSeconds, cancellationToken).ConfigureAwait(false);
53+
while (!cancellationToken.IsCancellationRequested)
54+
{
55+
this.UpdateMemoryMappedFileFromConfiguration();
56+
await Task.Delay(ConfigurationUpdatePeriodMilliSeconds, cancellationToken).ConfigureAwait(false);
57+
}
58+
}
59+
60+
private void UpdateMemoryMappedFileFromConfiguration()
61+
{
62+
if (this.configParser.TryGetConfiguration(out string newLogDirectory, out int fileSizeInKB, out EventLevel newEventLevel))
63+
{
64+
int newFileSize = fileSizeInKB * 1024;
65+
if (!newLogDirectory.Equals(this.memoryMappedFileHandler.LogDirectory, StringComparison.Ordinal) || this.memoryMappedFileHandler.LogFileSize != newFileSize)
66+
{
67+
this.memoryMappedFileHandler.CloseLogFile();
68+
this.memoryMappedFileHandler.CreateLogFile(newLogDirectory, newFileSize);
69+
}
70+
71+
if (!newEventLevel.Equals(this.logEventLevel))
72+
{
73+
if (this.eventListener != null)
74+
{
75+
this.eventListener.Dispose();
76+
}
77+
78+
this.eventListener = new SelfDiagnosticsEventListener(newEventLevel, this.memoryMappedFileHandler);
79+
this.logEventLevel = newEventLevel;
80+
}
81+
}
82+
else
83+
{
84+
this.memoryMappedFileHandler.CloseLogFile();
85+
}
86+
}
87+
88+
private void Dispose(bool disposing)
89+
{
90+
if (!this.disposedValue)
91+
{
92+
if (disposing)
93+
{
94+
this.cancellationTokenSource.Cancel(false);
95+
try
96+
{
97+
this.worker.Wait();
98+
}
99+
catch (AggregateException)
100+
{
101+
}
102+
finally
103+
{
104+
this.cancellationTokenSource.Dispose();
105+
}
106+
107+
// Ensure worker thread properly finishes.
108+
// Or it might have created another MemoryMappedFile in that thread
109+
// after the Dispose() below is called.
110+
this.memoryMappedFileHandler.Dispose();
111+
}
112+
113+
this.disposedValue = true;
114+
}
115+
}
116+
}
117+
}

BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnosticsInternals/SelfDiagnosticsEventListener.cs renamed to BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnostics/SelfDiagnosticsEventListener.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.SelfDiagnosticsInternals
1+
namespace Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.SelfDiagnostics
22
{
33
using System;
44
using System.Collections.Generic;
@@ -8,11 +8,6 @@
88
using System.Text;
99
using System.Threading;
1010

11-
// SelfDiagnosticsEventListener should be moved from SelfDiagnosticsInternals to SelfDiagnostics.
12-
// Pending on https://github.com/microsoft/ApplicationInsights-dotnet/pull/2262
13-
// Here still using this old namespace to show less changes in git diff view.
14-
using Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.SelfDiagnostics;
15-
1611
/// <summary>
1712
/// SelfDiagnosticsEventListener class enables the events from OpenTelemetry event sources
1813
/// and write the events to a local file in a circular way.

BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnosticsInitializer.cs renamed to BASE/src/Microsoft.ApplicationInsights/Extensibility/Implementation/Tracing/SelfDiagnostics/SelfDiagnosticsInitializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing
1+
namespace Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.SelfDiagnostics
22
{
33
using System;
44

BASE/src/Microsoft.ApplicationInsights/Extensibility/TelemetryConfiguration.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using Microsoft.ApplicationInsights.Extensibility.Implementation.Endpoints;
1515
using Microsoft.ApplicationInsights.Extensibility.Implementation.Sampling;
1616
using Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing;
17+
using Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing.SelfDiagnostics;
1718
using Microsoft.ApplicationInsights.Metrics;
1819
using Microsoft.ApplicationInsights.Metrics.Extensibility;
1920

0 commit comments

Comments
 (0)