Skip to content

Commit 1e486f8

Browse files
authored
Use .NET 6 structured logging (#67)
* gh-65 address SonarQube issues - Use structured logging in .net 6 Signed-off-by: Victor Chang <[email protected]>
1 parent 0fca397 commit 1e486f8

File tree

138 files changed

+2439
-1470
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

138 files changed

+2439
-1470
lines changed

.github/workflows/ci.yml

+28-31
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,9 @@ jobs:
8787

8888
- name: Perform CodeQL Analysis
8989
uses: github/codeql-action/analyze@v1
90-
9190

9291
unit-test:
93-
runs-on: windows-latest
92+
runs-on: ubuntu-latest
9493
steps:
9594
- name: Set up JDK 11
9695
uses: actions/setup-java@v1
@@ -112,44 +111,43 @@ jobs:
112111
- uses: actions/checkout@v2
113112
with:
114113
fetch-depth: 0
115-
116-
- name: Cache SonarCloud packages
117-
uses: actions/cache@v1
118-
with:
119-
path: ~\sonar\cache
120-
key: ${{ runner.os }}-sonar
121-
restore-keys: ${{ runner.os }}-sonar
122-
123-
- name: Cache SonarCloud scanner
124-
id: cache-sonar-scanner
125-
uses: actions/cache@v1
126-
with:
127-
path: .\.sonar\scanner
128-
key: ${{ runner.os }}-sonar-scanner
129-
restore-keys: ${{ runner.os }}-sonar-scanner
130-
114+
131115
- name: Install SonarCloud scanner
132116
if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
133-
shell: powershell
134-
run: |
135-
New-Item -Path .\.sonar\scanner -ItemType Directory
136-
dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner
117+
run: dotnet tool install --global dotnet-sonarscanner
137118

138119
- name: Restore dependencies
139120
run: dotnet restore
140121
working-directory: ./src
141-
142-
- name: Build and analyze
122+
123+
- name: Begin SonarScanner
143124
env:
144125
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
145126
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
146-
shell: powershell
147-
run: |
148-
.\.sonar\scanner\dotnet-sonarscanner begin /k:"Project-MONAI_monai-deploy-informatics-gateway" /o:"project-monai" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="src\${{ env.TEST_RESULTS }}\**\*.xml"
149-
dotnet build -c ${{ env.BUILD_CONFIG }} --nologo "src\${{ env.SOLUTION }}"
150-
dotnet test --no-build --filter FullyQualifiedName\!~Monai.Deploy.InformaticsGateway.Integration.Test -c ${{ env.BUILD_CONFIG }} -v=minimal --results-directory "src\${{ env.TEST_RESULTS }}" --collect:"XPlat Code Coverage" --settings src\coverlet.runsettings "src\${{ env.SOLUTION }}"
151-
.\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
127+
run: dotnet sonarscanner begin /k:"Project-MONAI_monai-deploy-informatics-gateway" /o:"project-monai" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="${{ env.TEST_RESULTS }}/**/*.xml"
128+
working-directory: ./src
129+
130+
- name: Build
131+
env:
132+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
133+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
134+
run: dotnet build -c ${{ env.BUILD_CONFIG }} --nologo "${{ env.SOLUTION }}"
135+
working-directory: ./src
136+
137+
- name: Test
138+
env:
139+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
140+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
141+
run: find ~+ -type f -name "*.Test.csproj" | xargs -L1 dotnet test -c ${{ env.BUILD_CONFIG }} -v=minimal -r "${{ env.TEST_RESULTS }}" --collect:"XPlat Code Coverage" --settings coverlet.runsettings
142+
working-directory: ./src
152143

144+
- name: End SonarScanner
145+
env:
146+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
147+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
148+
run: dotnet sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
149+
working-directory: ./src
150+
153151
- uses: codecov/codecov-action@v2
154152
with:
155153
token: ${{ secrets.CODECOV_TOKEN }}
@@ -298,7 +296,6 @@ jobs:
298296
tests/Integration.Test/run.log
299297
retention-days: 30
300298

301-
302299
docs:
303300
runs-on: ubuntu-latest
304301
needs: [calc-version]

src/Api/Monai.Deploy.InformaticsGateway.Api.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ SPDX-License-Identifier: Apache License 2.0
1313
</PropertyGroup>
1414

1515
<ItemGroup>
16-
<PackageReference Include="GitVersion.MsBuild" Version="5.8.2">
16+
<PackageReference Include="GitVersion.MsBuild" Version="5.9.0">
1717
<PrivateAssets>All</PrivateAssets>
1818
</PackageReference>
1919
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />

src/Api/Storage/DicomFileStorageInfo.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ protected override string GenerateStoragePath()
6363
Guard.Against.NullOrWhiteSpace(SeriesInstanceUid, nameof(SeriesInstanceUid));
6464
Guard.Against.NullOrWhiteSpace(SopInstanceUid, nameof(SopInstanceUid));
6565

66-
string filePath = System.IO.Path.Combine(StorageRootPath, StudyInstanceUid, SeriesInstanceUid, SopInstanceUid) + FileExtension;
66+
var filePath = System.IO.Path.Combine(StorageRootPath, StudyInstanceUid, SeriesInstanceUid, SopInstanceUid) + FileExtension;
6767
filePath = filePath.ToLowerInvariant();
6868
var index = 1;
6969
while (FileSystem.File.Exists(filePath))

src/Api/Storage/FhirFileStorageInfo.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ protected override string GenerateStoragePath()
4242
Guard.Against.NullOrWhiteSpace(ResourceType, nameof(ResourceType));
4343
Guard.Against.NullOrWhiteSpace(MessageId, nameof(MessageId));
4444

45-
string filePath = System.IO.Path.Combine(StorageRootPath, DirectoryPath, ResourceType, MessageId) + FileExtension;
45+
var filePath = System.IO.Path.Combine(StorageRootPath, DirectoryPath, ResourceType, MessageId) + FileExtension;
4646
filePath = filePath.ToLowerInvariant();
4747
var index = 1;
4848
while (FileSystem.File.Exists(filePath))

src/Api/Storage/FileStorageInfo.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ public void SetWorkflows(params string[] workflows)
178178
/// </summary>
179179
protected virtual string GenerateStoragePath()
180180
{
181-
string filePath = System.IO.Path.Combine(StorageRootPath, $"{CorrelationId}-{MessageId}") + FileExtension;
181+
var filePath = System.IO.Path.Combine(StorageRootPath, $"{CorrelationId}-{MessageId}") + FileExtension;
182182
filePath = filePath.ToLowerInvariant();
183183
var index = 1;
184184
while (FileSystem.File.Exists(filePath))

src/Api/Storage/Payload.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Diagnostics;
77
using Ardalis.GuardClauses;
88
using Monai.Deploy.InformaticsGateway.Common;
9+
910
namespace Monai.Deploy.InformaticsGateway.Api.Storage
1011
{
1112
public class Payload : IDisposable
@@ -86,7 +87,6 @@ public void Add(FileStorageInfo value)
8687
{
8788
foreach (var workflow in value.Workflows)
8889
{
89-
9090
Workflows.Add(workflow);
9191
}
9292
}

src/Api/Test/Monai.Deploy.InformaticsGateway.Api.Test.csproj

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,17 @@ SPDX-License-Identifier: Apache License 2.0
1212
</PropertyGroup>
1313

1414
<ItemGroup>
15+
<PackageReference Include="coverlet.collector" Version="3.1.2">
16+
<PrivateAssets>all</PrivateAssets>
17+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
18+
</PackageReference>
1519
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
1620
<PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="13.2.47" />
1721
<PackageReference Include="xunit" Version="2.4.1" />
1822
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
1923
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2024
<PrivateAssets>all</PrivateAssets>
2125
</PackageReference>
22-
<PackageReference Include="coverlet.collector" Version="3.1.2">
23-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
24-
<PrivateAssets>all</PrivateAssets>
25-
</PackageReference>
2626
</ItemGroup>
2727

2828
<ItemGroup>

src/CLI/Commands/AetCommand.cs

+16-21
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
using Ardalis.GuardClauses;
1414
using Microsoft.Extensions.DependencyInjection;
1515
using Microsoft.Extensions.Hosting;
16-
using Microsoft.Extensions.Logging;
1716
using Monai.Deploy.InformaticsGateway.Api;
1817
using Monai.Deploy.InformaticsGateway.CLI.Services;
1918
using Monai.Deploy.InformaticsGateway.Client;
@@ -109,22 +108,22 @@ private async Task<int> ListAeTitlehandlerAsync(IHost host, bool verbose, Cancel
109108
client.ConfigureServiceUris(configService.Configurations.InformaticsGatewayServerUri);
110109
LogVerbose(verbose, host, $"Connecting to {Strings.ApplicationName} at {configService.Configurations.InformaticsGatewayServerEndpoint}...");
111110
LogVerbose(verbose, host, $"Retrieving MONAI SCP AE Titles...");
112-
items = await client.MonaiScpAeTitle.List(cancellationToken);
111+
items = await client.MonaiScpAeTitle.List(cancellationToken).ConfigureAwait(false);
113112
}
114113
catch (ConfigurationException ex)
115114
{
116-
logger.Log(LogLevel.Critical, ex.Message);
115+
logger.ConfigurationException(ex.Message);
117116
return ExitCodes.Config_NotConfigured;
118117
}
119118
catch (Exception ex)
120119
{
121-
logger.Log(LogLevel.Critical, $"Error retrieving MONAI SCP AE Titles: {ex.Message}");
120+
logger.ErrorListingMonaiAeTitles(ex.Message);
122121
return ExitCodes.MonaiScp_ErrorList;
123122
}
124123

125124
if (items.IsNullOrEmpty())
126125
{
127-
logger.Log(LogLevel.Warning, "No MONAI SCP Application Entities configured.");
126+
logger.NoAeTitlesFound();
128127
}
129128
else
130129
{
@@ -166,17 +165,17 @@ private async Task<int> RemoveAeTitlehandlerAsync(string name, IHost host, bool
166165
client.ConfigureServiceUris(configService.Configurations.InformaticsGatewayServerUri);
167166
LogVerbose(verbose, host, $"Connecting to {Strings.ApplicationName} at {configService.Configurations.InformaticsGatewayServerEndpoint}...");
168167
LogVerbose(verbose, host, $"Deleting MONAI SCP AE Title {name}...");
169-
_ = await client.MonaiScpAeTitle.Delete(name, cancellationToken);
170-
logger.Log(LogLevel.Information, $"MONAI SCP AE Title '{name}' deleted.");
168+
_ = await client.MonaiScpAeTitle.Delete(name, cancellationToken).ConfigureAwait(false);
169+
logger.MonaiAeTitleDeleted(name);
171170
}
172171
catch (ConfigurationException ex)
173172
{
174-
logger.Log(LogLevel.Critical, ex.Message);
173+
logger.ConfigurationException(ex.Message);
175174
return ExitCodes.Config_NotConfigured;
176175
}
177176
catch (Exception ex)
178177
{
179-
logger.Log(LogLevel.Critical, $"Error deleting MONAI SCP AE Title {name}: {ex.Message}");
178+
logger.ErrorDeletingMonaiAeTitle(name, ex.Message);
180179
return ExitCodes.MonaiScp_ErrorDelete;
181180
}
182181
return ExitCodes.Success;
@@ -202,33 +201,29 @@ private async Task<int> AddAeTitlehandlerAsync(MonaiApplicationEntity entity, IH
202201
client.ConfigureServiceUris(configService.Configurations.InformaticsGatewayServerUri);
203202

204203
LogVerbose(verbose, host, $"Connecting to {Strings.ApplicationName} at {configService.Configurations.InformaticsGatewayServerEndpoint}...");
205-
var result = await client.MonaiScpAeTitle.Create(entity, cancellationToken);
204+
var result = await client.MonaiScpAeTitle.Create(entity, cancellationToken).ConfigureAwait(false);
206205

207-
logger.Log(LogLevel.Information, "New MONAI Deploy SCP Application Entity created:");
208-
logger.Log(LogLevel.Information, $"\tName: {result.Name}");
209-
logger.Log(LogLevel.Information, $"\tAE Title: {result.AeTitle}");
210-
logger.Log(LogLevel.Information, $"\tGrouping: {result.Grouping}");
211-
logger.Log(LogLevel.Information, $"\tTimeout: {result.Grouping}s");
206+
logger.MonaiAeTitleCreated(result.Name, result.AeTitle, result.Grouping, result.Timeout);
212207

213208
if (result.Workflows.Any())
214209
{
215-
logger.Log(LogLevel.Information, $"\tWorkflows:{string.Join(',', result.Workflows)}");
216-
logger.Log(LogLevel.Warning, "Data received by this Application Entity will bypass Data Routing Service.");
210+
logger.MonaiAeWorkflows(string.Join(',', result.Workflows));
211+
logger.WorkflowWarning();
217212
}
218213
if (result.IgnoredSopClasses.Any())
219214
{
220-
logger.Log(LogLevel.Information, $"\tIgnored SOP Classes:{string.Join(',', result.IgnoredSopClasses)}");
221-
logger.Log(LogLevel.Warning, "Instances with matching SOP class UIDs are accepted but dropped.");
215+
logger.MonaiAeIgnoredSops(string.Join(',', result.IgnoredSopClasses));
216+
logger.IgnoreSopClassesWarning();
222217
}
223218
}
224219
catch (ConfigurationException ex)
225220
{
226-
logger.Log(LogLevel.Critical, ex.Message);
221+
logger.ConfigurationException(ex.Message);
227222
return ExitCodes.Config_NotConfigured;
228223
}
229224
catch (Exception ex)
230225
{
231-
logger.Log(LogLevel.Critical, $"Error creating MONAI SCP AE Title {entity.AeTitle}: {ex.Message}");
226+
logger.MonaiAeCreateCritical(entity.AeTitle, ex.Message);
232227
return ExitCodes.MonaiScp_ErrorCreate;
233228
}
234229
return ExitCodes.Success;

src/CLI/Commands/CommandBase.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ protected static void LogVerbose(bool verbose, IHost host, string message)
4040
}
4141
else
4242
{
43-
logger.Log(LogLevel.Debug, message);
43+
logger.DebugMessage(message);
4444
}
4545
}
4646
}

src/CLI/Commands/ConfigCommand.cs

+13-15
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
using Ardalis.GuardClauses;
1010
using Microsoft.Extensions.DependencyInjection;
1111
using Microsoft.Extensions.Hosting;
12-
using Microsoft.Extensions.Logging;
1312
using Monai.Deploy.InformaticsGateway.CLI.Services;
1413

1514
namespace Monai.Deploy.InformaticsGateway.CLI
@@ -82,21 +81,19 @@ private int ShowConfigurationHandler(IHost host, bool verbose, CancellationToken
8281
try
8382
{
8483
CheckConfiguration(configService);
85-
logger.Log(LogLevel.Information, $"Informatics Gateway API: {configService.Configurations.InformaticsGatewayServerEndpoint}");
86-
logger.Log(LogLevel.Information, $"DICOM SCP Listening Port: {configService.Configurations.DicomListeningPort}");
87-
logger.Log(LogLevel.Information, $"Container Runner: {configService.Configurations.Runner}");
88-
logger.Log(LogLevel.Information, $"Host:");
89-
logger.Log(LogLevel.Information, $" Database storage mount: {configService.Configurations.HostDatabaseStorageMount}");
90-
logger.Log(LogLevel.Information, $" Data storage mount: {configService.Configurations.HostDataStorageMount}");
91-
logger.Log(LogLevel.Information, $" Logs storage mount: {configService.Configurations.HostLogsStorageMount}");
84+
logger.ConfigInformaticsGatewayApiEndpoint(configService.Configurations.InformaticsGatewayServerEndpoint);
85+
logger.ConfigDicomScpPort(configService.Configurations.DicomListeningPort);
86+
logger.ConfigContainerRunner(configService.Configurations.Runner);
87+
logger.ConfigHostInfo(configService.Configurations.HostDatabaseStorageMount, configService.Configurations.HostDataStorageMount, configService.Configurations.HostLogsStorageMount);
9288
}
93-
catch (ConfigurationException)
89+
catch (ConfigurationException ex)
9490
{
91+
logger.ConfigurationException(ex.Message);
9592
return ExitCodes.Config_NotConfigured;
9693
}
9794
catch (Exception ex)
9895
{
99-
logger.Log(LogLevel.Error, ex.Message);
96+
logger.CriticalException(ex.Message);
10097
return ExitCodes.Config_ErrorShowing;
10198
}
10299
return ExitCodes.Success;
@@ -116,15 +113,16 @@ private static int ConfigUpdateHandler(IHost host, Action<IConfigurationService>
116113
{
117114
CheckConfiguration(config);
118115
updater(config);
119-
logger.Log(LogLevel.Information, "Configuration updated successfully.");
116+
logger.ConfigurationUpdated();
120117
}
121-
catch (ConfigurationException)
118+
catch (ConfigurationException ex)
122119
{
120+
logger.ConfigurationException(ex.Message);
123121
return ExitCodes.Config_NotConfigured;
124122
}
125123
catch (Exception ex)
126124
{
127-
logger.Log(LogLevel.Error, ex.Message);
125+
logger.CriticalException(ex.Message);
128126
return ExitCodes.Config_ErrorSaving;
129127
}
130128
return ExitCodes.Success;
@@ -142,7 +140,7 @@ private async Task<int> InitHandlerAsync(IHost host, bool verbose, bool yes, Can
142140

143141
if (!yes && configService.IsConfigExists && !confirmation.ShowConfirmationPrompt($"Existing application configuration file already exists. Do you want to overwrite it?"))
144142
{
145-
logger.Log(LogLevel.Warning, "Action cancelled.");
143+
logger.ActionCancelled();
146144
return ExitCodes.Stop_Cancelled;
147145
}
148146

@@ -152,7 +150,7 @@ private async Task<int> InitHandlerAsync(IHost host, bool verbose, bool yes, Can
152150
}
153151
catch (Exception ex)
154152
{
155-
logger.Log(LogLevel.Error, ex.Message);
153+
logger.CriticalException(ex.Message);
156154
return ExitCodes.Config_ErrorInitializing;
157155
}
158156
return ExitCodes.Success;

src/CLI/Commands/ConfigurationException.cs

+8
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,18 @@ namespace Monai.Deploy.InformaticsGateway.CLI
99
[Serializable]
1010
public class ConfigurationException : Exception
1111
{
12+
private ConfigurationException()
13+
{
14+
}
15+
1216
public ConfigurationException(string message) : base(message)
1317
{
1418
}
1519

20+
public ConfigurationException(string message, Exception innerException) : base(message, innerException)
21+
{
22+
}
23+
1624
protected ConfigurationException(SerializationInfo info, StreamingContext context) : base(info, context)
1725
{
1826
}

0 commit comments

Comments
 (0)