Skip to content

Commit e3caf0d

Browse files
committed
feat: add logging configuration support with console and file output options
1 parent 39582fc commit e3caf0d

File tree

10 files changed

+244
-10
lines changed

10 files changed

+244
-10
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project>
22
<!-- Metadata -->
33
<PropertyGroup>
4-
<Version>1.0.12</Version>
4+
<Version>1.0.13</Version>
55
<Copyright>Copyright (c) 2025 Qase</Copyright>
66
<Authors>Qase Team</Authors>
77
<Company>qase.io</Company>

Qase.Csharp.Commons.Tests/ConfigFactoryTests.cs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ public void LoadConfig_ShouldReturnDefaultConfig_WhenNoSourcesAvailable()
3535
config.Environment.Should().BeNull();
3636
config.RootSuite.Should().BeNull();
3737
config.Debug.Should().BeFalse();
38+
config.Logging.Should().NotBeNull();
39+
config.Logging.Console.Should().BeTrue();
40+
config.Logging.File.Should().BeFalse();
3841
}
3942

4043
[Fact]
@@ -879,5 +882,68 @@ public void LoadConfig_ShouldHandleInvalidExternalLinkTypeFromEnvironment_WhenIn
879882
// Cleanup
880883
Environment.SetEnvironmentVariable("QASE_TESTOPS_RUN_EXTERNAL_LINK", null);
881884
}
885+
886+
[Fact]
887+
public void LoadConfig_ShouldLoadLoggingConfigFromFile()
888+
{
889+
// Arrange
890+
var jsonConfig = @"{
891+
""logging"": {
892+
""console"": false,
893+
""file"": true
894+
}
895+
}";
896+
File.WriteAllText(ConfigFileName, jsonConfig);
897+
898+
// Act
899+
var config = ConfigFactory.LoadConfig();
900+
901+
// Assert
902+
config.Logging.Console.Should().BeFalse();
903+
config.Logging.File.Should().BeTrue();
904+
}
905+
906+
[Fact]
907+
public void LoadConfig_ShouldLoadLoggingConfigFromEnvironmentVariables()
908+
{
909+
// Arrange
910+
Environment.SetEnvironmentVariable("QASE_LOGGING_CONSOLE", "false");
911+
Environment.SetEnvironmentVariable("QASE_LOGGING_FILE", "true");
912+
913+
// Act
914+
var config = ConfigFactory.LoadConfig();
915+
916+
// Assert
917+
config.Logging.Console.Should().BeFalse();
918+
config.Logging.File.Should().BeTrue();
919+
920+
// Cleanup
921+
Environment.SetEnvironmentVariable("QASE_LOGGING_CONSOLE", null);
922+
Environment.SetEnvironmentVariable("QASE_LOGGING_FILE", null);
923+
}
924+
925+
[Fact]
926+
public void LoadConfig_ShouldMergeLoggingConfigFromFileAndEnvironment()
927+
{
928+
// Arrange
929+
var jsonConfig = @"{
930+
""logging"": {
931+
""console"": false,
932+
""file"": true
933+
}
934+
}";
935+
File.WriteAllText(ConfigFileName, jsonConfig);
936+
Environment.SetEnvironmentVariable("QASE_LOGGING_FILE", "false");
937+
938+
// Act
939+
var config = ConfigFactory.LoadConfig();
940+
941+
// Assert
942+
config.Logging.Console.Should().BeFalse(); // from file
943+
config.Logging.File.Should().BeFalse(); // from environment (overrides file)
944+
945+
// Cleanup
946+
Environment.SetEnvironmentVariable("QASE_LOGGING_FILE", null);
947+
}
882948
}
883949
}

Qase.Csharp.Commons.Tests/QaseConfigTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using FluentAssertions;
23
using Qase.Csharp.Commons.Config;
34
using Xunit;
45

@@ -20,6 +21,9 @@ public void Constructor_ShouldInitializeWithDefaultValues()
2021
config.Debug.Should().BeFalse();
2122
config.TestOps.Should().NotBeNull();
2223
config.Report.Should().NotBeNull();
24+
config.Logging.Should().NotBeNull();
25+
config.Logging.Console.Should().BeTrue();
26+
config.Logging.File.Should().BeFalse();
2327
}
2428

2529
[Theory]
@@ -105,5 +109,22 @@ public void Properties_ShouldBeSettable()
105109
config.Mode.Should().Be(Mode.TestOps);
106110
config.Fallback.Should().Be(Mode.Report);
107111
}
112+
113+
[Fact]
114+
public void LoggingProperties_ShouldBeSettable()
115+
{
116+
// Arrange
117+
var config = new QaseConfig();
118+
var console = false;
119+
var file = true;
120+
121+
// Act
122+
config.Logging.Console = console;
123+
config.Logging.File = file;
124+
125+
// Assert
126+
config.Logging.Console.Should().Be(console);
127+
config.Logging.File.Should().Be(file);
128+
}
108129
}
109130
}

Qase.Csharp.Commons/README.md

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ All configuration options are listed in the table below:
2727
| Environment | `environment` | `QASE_ENVIRONMENT` | `QASE_ENVIRONMENT` | undefined | No | Any string |
2828
| Root suite | `rootSuite` | `QASE_ROOT_SUITE` | `QASE_ROOT_SUITE` | undefined | No | Any string |
2929
| Enable debug logs | `debug` | `QASE_DEBUG` | `QASE_DEBUG` | `False` | No | `True`, `False` |
30+
| **Logging configuration** | | | | | | |
31+
| Enable console output | `logging.console` | `QASE_LOGGING_CONSOLE` | `QASE_LOGGING_CONSOLE` | `True` | No | `True`, `False` |
32+
| Enable file output | `logging.file` | `QASE_LOGGING_FILE` | `QASE_LOGGING_FILE` | `False` (True when debug=true) | No | `True`, `False` |
3033
| **Qase Report configuration** | | | | | | |
3134
| Driver used for report mode | `report.driver` | `QASE_REPORT_DRIVER` | `QASE_REPORT_DRIVER` | `local` | No | `local` |
3235
| Path to save the report | `report.connection.path` | `QASE_REPORT_CONNECTION_PATH` | `QASE_REPORT_CONNECTION_PATH` | `./build/qase-report` | | |
@@ -59,7 +62,10 @@ All configuration options are listed in the table below:
5962
"fallback": "report",
6063
"debug": false,
6164
"environment": "local",
62-
"captureLogs": false,
65+
"logging": {
66+
"console": true,
67+
"file": false
68+
},
6369
"report": {
6470
"driver": "local",
6571
"connection": {
@@ -110,3 +116,35 @@ All configuration options are listed in the table below:
110116
}
111117
}
112118
```
119+
120+
## Logging Configuration
121+
122+
Control logging output with the `logging` option:
123+
124+
### Disable console output (only log to file):
125+
```json
126+
{
127+
"debug": true,
128+
"logging": {
129+
"console": false
130+
}
131+
}
132+
```
133+
134+
### Disable all logging:
135+
```json
136+
{
137+
"logging": {
138+
"console": false,
139+
"file": false
140+
}
141+
}
142+
```
143+
144+
### Environment variables:
145+
- `QASE_LOGGING_CONSOLE` - enable/disable console output (default: true)
146+
- `QASE_LOGGING_FILE` - enable/disable file output (default: false, true when debug=true)
147+
148+
**Note:** Log level is controlled by the `debug` parameter:
149+
- `debug: true` - Debug level (detailed logs)
150+
- `debug: false` - Information level (standard logs)

Qase.Csharp.Commons/ServiceCollectionExtensions.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,28 @@ public static IServiceCollection AddQaseServices(this IServiceCollection service
3636
$"{DateTime.Now:yyyyMMdd}.log"
3737
);
3838

39-
Directory.CreateDirectory(Path.GetDirectoryName(logPath)!);
39+
if (config.Logging.File)
40+
{
41+
Directory.CreateDirectory(Path.GetDirectoryName(logPath)!);
42+
}
43+
44+
var loggerConfiguration = new LoggerConfiguration();
45+
46+
// Configure console output
47+
if (config.Logging.Console)
48+
{
49+
loggerConfiguration.WriteTo.Console(
50+
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] qase: {Message:lj}{NewLine}{Exception}");
51+
}
4052

41-
var loggerConfiguration = new LoggerConfiguration()
42-
.WriteTo.Console(
43-
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
44-
.WriteTo.File(
53+
// Configure file output
54+
if (config.Logging.File)
55+
{
56+
loggerConfiguration.WriteTo.File(
4557
logPath,
4658
rollingInterval: RollingInterval.Day,
47-
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}");
59+
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] qase: {Message:lj}{NewLine}{Exception}");
60+
}
4861

4962
if (config.Debug)
5063
{

Qase.Csharp.Commons/config/ConfigFactory.cs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ private static QaseConfig LoadFromFile(QaseConfig qaseConfig)
6565
}
6666
catch (Exception e)
6767
{
68-
Console.Error.WriteLine($"Error reading configuration file: {e.Message}");
68+
// Use direct console output for critical configuration errors
69+
// This ensures the error is always visible to the user
70+
Console.Error.WriteLine($"qase: Error reading configuration file: {e.Message}");
6971
}
7072

7173
return qaseConfig;
@@ -149,6 +151,10 @@ private static QaseConfig LoadFromEnv(QaseConfig qaseConfig)
149151

150152
qaseConfig.Report.Connection.Local.Path = GetEnv("QASE_REPORT_CONNECTION_PATH", qaseConfig.Report.Connection.Local.Path);
151153

154+
// Logging settings
155+
qaseConfig.Logging.Console = GetBooleanEnv("QASE_LOGGING_CONSOLE", qaseConfig.Logging.Console);
156+
qaseConfig.Logging.File = GetBooleanEnv("QASE_LOGGING_FILE", qaseConfig.Logging.File);
157+
152158
return qaseConfig;
153159
}
154160

@@ -178,7 +184,9 @@ private static void ValidateConfig(QaseConfig qaseConfig)
178184
if ((qaseConfig.Mode == Mode.TestOps || qaseConfig.Fallback == Mode.TestOps) &&
179185
(string.IsNullOrEmpty(qaseConfig.TestOps?.Project) || string.IsNullOrEmpty(qaseConfig.TestOps?.Api?.Token)))
180186
{
181-
Console.Error.WriteLine("Project code and API token are required for TestOps mode");
187+
// Use direct console output for critical validation errors
188+
// This ensures the error is always visible to the user
189+
Console.Error.WriteLine("qase: Project code and API token are required for TestOps mode");
182190
qaseConfig.Mode = Mode.Off;
183191
qaseConfig.Fallback = Mode.Off;
184192
}
@@ -494,6 +502,21 @@ private static void ApplyJsonConfig(QaseConfig qaseConfig, JsonElement json)
494502
}
495503
}
496504
}
505+
506+
if (json.TryGetProperty("logging", out var loggingElement))
507+
{
508+
if (loggingElement.TryGetProperty("console", out var consoleElement) &&
509+
consoleElement.ValueKind == JsonValueKind.False)
510+
{
511+
qaseConfig.Logging.Console = false;
512+
}
513+
514+
if (loggingElement.TryGetProperty("file", out var fileElement) &&
515+
fileElement.ValueKind == JsonValueKind.True)
516+
{
517+
qaseConfig.Logging.File = true;
518+
}
519+
}
497520
}
498521

499522
/// <summary>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
3+
namespace Qase.Csharp.Commons.Config
4+
{
5+
/// <summary>
6+
/// Configuration for logging settings
7+
/// </summary>
8+
public class LoggingConfig
9+
{
10+
/// <summary>
11+
/// Gets or sets whether console output is enabled
12+
/// </summary>
13+
public bool Console { get; set; } = true;
14+
15+
/// <summary>
16+
/// Gets or sets whether file output is enabled
17+
/// </summary>
18+
public bool File { get; set; } = false;
19+
20+
/// <summary>
21+
/// Initializes a new instance of the LoggingConfig class
22+
/// </summary>
23+
public LoggingConfig()
24+
{
25+
}
26+
}
27+
}

Qase.Csharp.Commons/config/QaseConfig.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,19 @@ public class QaseConfig
4848
/// </summary>
4949
public Dictionary<string, string> StatusMapping { get; set; } = new Dictionary<string, string>();
5050

51+
/// <summary>
52+
/// Gets or sets the logging configuration
53+
/// </summary>
54+
public LoggingConfig Logging { get; set; } = new LoggingConfig();
55+
5156
/// <summary>
5257
/// Initializes a new instance of the QaseConfig class
5358
/// </summary>
5459
public QaseConfig()
5560
{
5661
TestOps = new TestOpsConfig();
5762
Report = new ReportConfig();
63+
Logging = new LoggingConfig();
5864
}
5965

6066
public void SetMode(string? mode)

Qase.XUnit.Reporter/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ The Qase xUnit reporter can be configured in multiple ways:
101101
"fallback": "report",
102102
"debug": true,
103103
"environment": "local",
104+
"logging": {
105+
"console": true,
106+
"file": false
107+
},
104108
"report": {
105109
"driver": "local",
106110
"connection": {
@@ -129,6 +133,38 @@ The Qase xUnit reporter can be configured in multiple ways:
129133
}
130134
```
131135

136+
## Logging Configuration
137+
138+
Control logging output with the `logging` option:
139+
140+
### Disable console output (only log to file):
141+
```json
142+
{
143+
"debug": true,
144+
"logging": {
145+
"console": false
146+
}
147+
}
148+
```
149+
150+
### Disable all logging:
151+
```json
152+
{
153+
"logging": {
154+
"console": false,
155+
"file": false
156+
}
157+
}
158+
```
159+
160+
### Environment variables:
161+
- `QASE_LOGGING_CONSOLE` - enable/disable console output (default: true)
162+
- `QASE_LOGGING_FILE` - enable/disable file output (default: false, true when debug=true)
163+
164+
**Note:** Log level is controlled by the `debug` parameter:
165+
- `debug: true` - Debug level (detailed logs)
166+
- `debug: false` - Information level (standard logs)
167+
132168
## Requirements
133169

134170
- **xUnit**: Version 2.4.0 or higher is required.

changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## qase-scharp 1.0.13
4+
5+
- Added support for logging configuration
6+
37
## qase-scharp 1.0.12
48

59
- Added support for status mapping

0 commit comments

Comments
 (0)