Skip to content

Commit 0ff1963

Browse files
authored
gh-435 Fix CLI to read log dir path from NLog config file (#436)
* gh-435 Fix CLI to read log dir path from NLog config file * Update changelog * Add/update unit tests Signed-off-by: Victor Chang <[email protected]>
1 parent d54788e commit 0ff1963

17 files changed

+427
-52
lines changed

docs/changelog.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,44 @@
1717

1818
# Changelog
1919

20+
## 0.4.0
21+
22+
[GitHub Milestone 0.4.0](https://github.com/Project-MONAI/monai-deploy-informatics-gateway/milestone/5)
23+
24+
- gh-435 Fix CLI to read log dir path from NLog config file.
25+
26+
27+
## 0.3.21
28+
29+
[GitHub Milestone 0.3.21](https://github.com/Project-MONAI/monai-deploy-informatics-gateway/milestone/26)
30+
31+
- Remove the need to double copy files to storage service.
32+
33+
## 0.3.20
34+
35+
[GitHub Milestone 0.3.20](https://github.com/Project-MONAI/monai-deploy-informatics-gateway/milestone/25)
36+
37+
- gh-396 Spawn new thread for processing echo requests.
38+
39+
## 0.3.19
40+
41+
[GitHub Milestone 0.3.19](https://github.com/Project-MONAI/monai-deploy-informatics-gateway/milestone/24)
42+
43+
- gh-392 Fix GET /config/aetitle URL.
44+
45+
## 0.3.18
46+
47+
[GitHub Milestone 0.3.18](https://github.com/Project-MONAI/monai-deploy-informatics-gateway/milestone/23)
48+
49+
- gh-390 New API to retrieve registered source AETs.
50+
51+
## 0.3.11
52+
53+
[GitHub Milestone 0.3.17](https://github.com/Project-MONAI/monai-deploy-informatics-gateway/milestone/22)
54+
55+
- gh-385 Resets ActionBlock if faulted or cancelled in Payload assembler pipeline.
56+
57+
2058
## 0.3.16
2159

2260
[GitHub Milestone 0.3.16](https://github.com/Project-MONAI/monai-deploy-informatics-gateway/milestone/21)

src/CLI/Logging/Log.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ public static partial class Log
133133
[LoggerMessage(EventId = 30043, Level = LogLevel.Debug, Message = "Available manifest names {names}.")]
134134
public static partial void AvailableManifest(this ILogger logger, string names);
135135

136-
[LoggerMessage(EventId = 30044, Level = LogLevel.Information, Message = "Saving appsettings.json to {path}.")]
137-
public static partial void SaveAppSettings(this ILogger logger, string path);
136+
[LoggerMessage(EventId = 30044, Level = LogLevel.Information, Message = "Saving {resource} to {path}.")]
137+
public static partial void SaveAppSettings(this ILogger logger, string resource, string path);
138138

139139
[LoggerMessage(EventId = 30045, Level = LogLevel.Information, Message = "{path} updated successfully.")]
140140
public static partial void AppSettingUpdated(this ILogger logger, string path);

src/CLI/Monai.Deploy.InformaticsGateway.CLI.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151

5252
<ItemGroup>
5353
<EmbeddedResource Include="..\InformaticsGateway\appsettings.json" Link="Resources\appsettings.json" />
54+
<EmbeddedResource Include="..\InformaticsGateway\nlog.config" Link="Resources\nlog.config" />
5455
</ItemGroup>
5556

5657
<ItemGroup>

src/CLI/Options/Common.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@ public static class Common
2525
public static readonly string MigDirectory = Path.Combine(HomeDir, ".mig");
2626
public static readonly string ContainerApplicationRootPath = "/opt/monai/ig";
2727
public static readonly string MountedConfigFilePath = Path.Combine(ContainerApplicationRootPath, "appsettings.json");
28+
public static readonly string MountedNLogConfigFilePath = Path.Combine(ContainerApplicationRootPath, "nlog.config");
2829
public static readonly string MountedDatabasePath = "/database";
2930
public static readonly string MountedPlugInsPath = Path.Combine(ContainerApplicationRootPath, "plug-ins");
3031
public static readonly string ConfigFilePath = Path.Combine(MigDirectory, "appsettings.json");
32+
public static readonly string NLogConfigFilePath = Path.Combine(MigDirectory, "nlog.config");
3133
public static readonly string AppSettingsResourceName = $"{typeof(Program).Namespace}.Resources.appsettings.json";
34+
public static readonly string NLogConfigResourceName = $"{typeof(Program).Namespace}.Resources.nlog.config";
3235
}
3336
}

src/CLI/Program.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ internal static Parser BuildParser()
6363
services.AddScoped<IFileSystem, FileSystem>();
6464
services.AddScoped<IConfirmationPrompt, ConfirmationPrompt>();
6565
services.AddScoped<IConsoleRegion, ConsoleRegion>();
66+
services.AddScoped<IConfigurationOptionAccessor, ConfigurationOptionAccessor>();
67+
services.AddScoped<INLogConfigurationOptionAccessor, NLogConfigurationOptionAccessor>();
6668
services.AddHttpClient<InformaticsGatewayClient>();
6769
services.AddSingleton<IInformaticsGatewayClient>(p => p.GetRequiredService<InformaticsGatewayClient>());
6870
services.AddSingleton<IConfigurationService, ConfigurationService>();

src/CLI/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"profiles": {
33
"Monai.Deploy.InformaticsGateway.CLI": {
44
"commandName": "Project",
5-
"commandLineArgs": "aet add -a Test"
5+
"commandLineArgs": "start"
66
}
77
}
88
}

src/CLI/Services/ConfigurationOptionAccessor.cs

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021-2022 MONAI Consortium
2+
* Copyright 2021-2023 MONAI Consortium
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -76,11 +76,6 @@ public interface IConfigurationOptionAccessor
7676
/// </summary>
7777
Uri InformaticsGatewayServerUri { get; }
7878

79-
/// <summary>
80-
/// Gets the log storage path from appsettings.json.
81-
/// </summary>
82-
string LogStoragePath { get; }
83-
8479
/// <summary>
8580
/// Gets or set the type of container runner from appsettings.json.
8681
/// </summary>
@@ -99,7 +94,7 @@ public class ConfigurationOptionAccessor : IConfigurationOptionAccessor
9994

10095
public ConfigurationOptionAccessor(IFileSystem fileSystem)
10196
{
102-
_fileSystem = fileSystem;
97+
_fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
10398
}
10499

105100
public int DicomListeningPort
@@ -223,19 +218,6 @@ public Uri InformaticsGatewayServerUri
223218
}
224219
}
225220

226-
public string LogStoragePath
227-
{
228-
get
229-
{
230-
var logPath = GetValueFromJsonPath<string>("Logging.File.BasePath");
231-
if (logPath.StartsWith("/"))
232-
{
233-
return logPath;
234-
}
235-
return _fileSystem.Path.Combine(Common.ContainerApplicationRootPath, logPath);
236-
}
237-
}
238-
239221
public Runner Runner
240222
{
241223
get
@@ -255,7 +237,7 @@ public string TempStoragePath
255237
{
256238
get
257239
{
258-
return GetValueFromJsonPath<string>("InformaticsGateway.storage.temporary");
240+
return GetValueFromJsonPath<string>("InformaticsGateway.storage.localTemporaryStoragePath");
259241
}
260242
}
261243

src/CLI/Services/ConfigurationService.cs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021-2022 MONAI Consortium
2+
* Copyright 2021-2023 MONAI Consortium
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
2020
using System.Reflection;
2121
using System.Threading;
2222
using System.Threading.Tasks;
23+
using Ardalis.GuardClauses;
2324
using Microsoft.Extensions.Logging;
2425

2526
namespace Monai.Deploy.InformaticsGateway.CLI.Services
@@ -35,13 +36,20 @@ public class ConfigurationService : IConfigurationService
3536
public bool IsConfigExists => _fileSystem.File.Exists(Common.ConfigFilePath);
3637

3738
public IConfigurationOptionAccessor Configurations { get; }
39+
public INLogConfigurationOptionAccessor NLogConfigurations { get; }
3840

39-
public ConfigurationService(ILogger<ConfigurationService> logger, IFileSystem fileSystem, IEmbeddedResource embeddedResource)
41+
public ConfigurationService(
42+
ILogger<ConfigurationService> logger,
43+
IFileSystem fileSystem,
44+
IEmbeddedResource embeddedResource,
45+
IConfigurationOptionAccessor configurationOptionAccessor,
46+
INLogConfigurationOptionAccessor nLogConfigurationOptionAccessor)
4047
{
4148
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
4249
_fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
4350
_embeddedResource = embeddedResource ?? throw new ArgumentNullException(nameof(embeddedResource));
44-
Configurations = new ConfigurationOptionAccessor(fileSystem);
51+
Configurations = configurationOptionAccessor ?? throw new ArgumentNullException(nameof(configurationOptionAccessor));
52+
NLogConfigurations = nLogConfigurationOptionAccessor ?? throw new ArgumentNullException(nameof(nLogConfigurationOptionAccessor));
4553
}
4654

4755
public void CreateConfigDirectoryIfNotExist()
@@ -55,22 +63,32 @@ public void CreateConfigDirectoryIfNotExist()
5563
public async Task Initialize(CancellationToken cancellationToken)
5664
{
5765
_logger.DebugMessage("Reading default application configurations...");
58-
using var stream = _embeddedResource.GetManifestResourceStream(Common.AppSettingsResourceName);
66+
await WriteConfigFile(Common.AppSettingsResourceName, Common.ConfigFilePath, cancellationToken).ConfigureAwait(false);
67+
await WriteConfigFile(Common.NLogConfigResourceName, Common.NLogConfigFilePath, cancellationToken).ConfigureAwait(false);
68+
}
69+
70+
public async Task WriteConfigFile(string resourceName, string outputPath, CancellationToken cancellationToken)
71+
{
72+
Guard.Against.NullOrWhiteSpace(resourceName, nameof(resourceName));
73+
Guard.Against.NullOrWhiteSpace(outputPath, nameof(outputPath));
74+
75+
using var stream = _embeddedResource.GetManifestResourceStream(resourceName);
5976

6077
if (stream is null)
6178
{
6279
_logger.AvailableManifest(string.Join(",", Assembly.GetExecutingAssembly().GetManifestResourceNames()));
63-
throw new ConfigurationException($"Default configuration file could not be loaded, please reinstall the CLI.");
80+
throw new ConfigurationException($"Default configuration file: {resourceName} could not be loaded, please reinstall the CLI.");
6481
}
6582
CreateConfigDirectoryIfNotExist();
6683

67-
_logger.SaveAppSettings(Common.ConfigFilePath);
68-
using (var fileStream = _fileSystem.FileStream.Create(Common.ConfigFilePath, FileMode.Create))
84+
_logger.SaveAppSettings(resourceName, outputPath);
85+
using (var fileStream = _fileSystem.FileStream.Create(outputPath, FileMode.Create))
6986
{
7087
await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false);
7188
await fileStream.FlushAsync(cancellationToken).ConfigureAwait(false);
7289
}
73-
_logger.AppSettingUpdated(Common.ConfigFilePath);
90+
_logger.AppSettingUpdated(outputPath);
91+
7492
}
7593
}
7694
}

src/CLI/Services/DockerRunner.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021-2022 MONAI Consortium
2+
* Copyright 2021-2023 MONAI Consortium
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -114,6 +114,7 @@ public async Task<bool> StartApplication(ImageVersion imageVersion, Cancellation
114114
};
115115

116116
createContainerParams.HostConfig.PortBindings = new Dictionary<string, IList<PortBinding>>();
117+
createContainerParams.HostConfig.NetworkMode = "monaideploy";
117118

118119
_logger.DockerPrtBinding(_configurationService.Configurations.DicomListeningPort);
119120
createContainerParams.ExposedPorts.Add($"{_configurationService.Configurations.DicomListeningPort}/tcp", new EmptyStruct());
@@ -135,9 +136,9 @@ public async Task<bool> StartApplication(ImageVersion imageVersion, Cancellation
135136
_fileSystem.Directory.CreateDirectoryIfNotExists(_configurationService.Configurations.HostDatabaseStorageMount);
136137
createContainerParams.HostConfig.Mounts.Add(new Mount { Type = "bind", ReadOnly = false, Source = _configurationService.Configurations.HostDatabaseStorageMount, Target = Common.MountedDatabasePath });
137138

138-
_logger.DockerMountAppLogs(_configurationService.Configurations.HostLogsStorageMount, _configurationService.Configurations.LogStoragePath);
139+
_logger.DockerMountAppLogs(_configurationService.Configurations.HostLogsStorageMount, _configurationService.NLogConfigurations.LogStoragePath);
139140
_fileSystem.Directory.CreateDirectoryIfNotExists(_configurationService.Configurations.HostLogsStorageMount);
140-
createContainerParams.HostConfig.Mounts.Add(new Mount { Type = "bind", ReadOnly = false, Source = _configurationService.Configurations.HostLogsStorageMount, Target = _configurationService.Configurations.LogStoragePath });
141+
createContainerParams.HostConfig.Mounts.Add(new Mount { Type = "bind", ReadOnly = false, Source = _configurationService.Configurations.HostLogsStorageMount, Target = _configurationService.NLogConfigurations.LogStoragePath });
141142

142143
_logger.DockerMountPlugins(_configurationService.Configurations.HostPlugInsStorageMount, Common.MountedPlugInsPath);
143144
_fileSystem.Directory.CreateDirectoryIfNotExists(_configurationService.Configurations.HostPlugInsStorageMount);

src/CLI/Services/EmbeddedResource.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ public class EmbeddedResource : IEmbeddedResource
2929
public Stream GetManifestResourceStream(string name)
3030
{
3131
Guard.Against.NullOrWhiteSpace(name, nameof(name));
32-
return GetType().Assembly.GetManifestResourceStream(Common.AppSettingsResourceName);
32+
33+
return GetType().Assembly.GetManifestResourceStream(name);
3334
}
3435
}
3536
}

src/CLI/Services/IConfigurationService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ public interface IConfigurationService
2626
/// </summary>
2727
IConfigurationOptionAccessor Configurations { get; }
2828

29+
/// <summary>
30+
/// Gets the configurations inside nlog.config
31+
/// </summary>
32+
INLogConfigurationOptionAccessor NLogConfigurations { get; }
33+
2934
/// <summary>
3035
/// Gets whether the configuration file exists or not.
3136
/// </summary>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2023 MONAI Consortium
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
using System;
18+
using System.IO.Abstractions;
19+
using System.Xml;
20+
21+
namespace Monai.Deploy.InformaticsGateway.CLI.Services
22+
{
23+
public interface INLogConfigurationOptionAccessor
24+
{
25+
/// <summary>
26+
/// Gets the logs directory path.
27+
/// </summary>
28+
string LogStoragePath { get; }
29+
}
30+
31+
public class NLogConfigurationOptionAccessor : INLogConfigurationOptionAccessor
32+
{
33+
private readonly XmlDocument _xmlDocument;
34+
private readonly XmlNamespaceManager _namespaceManager;
35+
36+
public NLogConfigurationOptionAccessor(IFileSystem fileSystem)
37+
{
38+
if (fileSystem is null)
39+
{
40+
throw new ArgumentNullException(nameof(fileSystem));
41+
}
42+
43+
var xml = fileSystem.File.ReadAllText(Common.NLogConfigFilePath);
44+
_xmlDocument = new XmlDocument();
45+
_xmlDocument.LoadXml(xml);
46+
_namespaceManager = new XmlNamespaceManager(_xmlDocument.NameTable);
47+
_namespaceManager.AddNamespace("ns", "http://www.nlog-project.org/schemas/NLog.xsd");
48+
}
49+
50+
public string LogStoragePath
51+
{
52+
get
53+
{
54+
var value = _xmlDocument.SelectSingleNode("//ns:variable[@name='logDir']/@value", _namespaceManager).InnerText;
55+
value = value.Replace("${basedir}", Common.ContainerApplicationRootPath);
56+
return value;
57+
}
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)