feat: add --log-level CLI flag (#54)
This commit is contained in:
parent
cbd0305a39
commit
55702db014
|
|
@ -32,9 +32,9 @@ Create `CWS_conf.yaml` using:
|
|||
Environment placeholders (for example `${CWS_DISCORD_WEBHOOK}`) are resolved
|
||||
from process env vars and from a `.env` file next to your config.
|
||||
|
||||
Logging level can be set with `CWS_LOG_LEVEL` (or `LOG_LEVEL`): `trace`,
|
||||
`debug`, `info`, `warning`, `error`, `fatal`. Minimal example:
|
||||
[.env.example](.env.example).
|
||||
Set logging with `--log-level trace|debug|info|warn|error` or env
|
||||
`CWS_LOG_LEVEL` / `LOG_LEVEL`. Precedence: CLI > env > default `info`.
|
||||
Minimal env example: [.env.example](.env.example).
|
||||
|
||||
Generate starter config:
|
||||
|
||||
|
|
@ -64,6 +64,8 @@ Run continuously:
|
|||
|
||||
```bash
|
||||
dart run bin/code_work_spawner.dart
|
||||
# With higher verbosity for troubleshooting:
|
||||
dart run bin/code_work_spawner.dart --log-level debug
|
||||
```
|
||||
|
||||
Override CLI paths if needed:
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ class _CodeWorkSpawnerCommandRunner extends CommandRunner<void> {
|
|||
'gosmee-command',
|
||||
help: 'Path to the gosmee executable.',
|
||||
defaultsTo: 'gosmee',
|
||||
)
|
||||
..addOption(
|
||||
'log-level',
|
||||
help: 'Minimum log level: trace, debug, info, warn, error.',
|
||||
);
|
||||
|
||||
addCommand(_InitConfigCommand());
|
||||
|
|
@ -64,6 +68,14 @@ class _CodeWorkSpawnerCommandRunner extends CommandRunner<void> {
|
|||
|
||||
@override
|
||||
Future<void> runCommand(ArgResults topLevelResults) async {
|
||||
final cliMinimumLevel = _resolveCliMinimumLevel(
|
||||
topLevelResults['log-level'] as String?,
|
||||
);
|
||||
_configureLogging(
|
||||
cliMinimumLevel: cliMinimumLevel,
|
||||
environment: AppEnvironment.variables,
|
||||
);
|
||||
|
||||
if (topLevelResults['help'] as bool) {
|
||||
stdout.writeln(usage);
|
||||
return;
|
||||
|
|
@ -76,7 +88,10 @@ class _CodeWorkSpawnerCommandRunner extends CommandRunner<void> {
|
|||
|
||||
final configPath = topLevelResults['config'] as String;
|
||||
AppEnvironment.loadForConfig(configPath);
|
||||
_configureLogging();
|
||||
_configureLogging(
|
||||
cliMinimumLevel: cliMinimumLevel,
|
||||
environment: AppEnvironment.variables,
|
||||
);
|
||||
|
||||
final config = await AppConfig.load(configPath);
|
||||
final logger = AppLogger('code_work_spawner.cli');
|
||||
|
|
@ -124,6 +139,21 @@ class _CodeWorkSpawnerCommandRunner extends CommandRunner<void> {
|
|||
await app.close();
|
||||
}
|
||||
}
|
||||
|
||||
AppLogLevel? _resolveCliMinimumLevel(String? value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
final parsed = AppLogger.parseLevel(value);
|
||||
if (parsed == null || parsed == AppLogLevel.fatal) {
|
||||
throw UsageException(
|
||||
'Invalid value for --log-level "$value". '
|
||||
'Allowed values: trace, debug, info, warn, error.',
|
||||
usage,
|
||||
);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
|
||||
String _cliEventSourceSettings(IssueEventSourceConfig eventSource) {
|
||||
|
|
@ -210,9 +240,14 @@ class _InitConfigCommand extends Command<void> {
|
|||
}
|
||||
}
|
||||
|
||||
void _configureLogging() {
|
||||
void _configureLogging({
|
||||
required Map<String, String> environment,
|
||||
AppLogLevel? cliMinimumLevel,
|
||||
}) {
|
||||
AppLogger.configure(
|
||||
minimumLevel: AppLogger.resolveMinimumLevel(AppEnvironment.variables),
|
||||
minimumLevel:
|
||||
cliMinimumLevel ??
|
||||
AppLogger.resolveMinimumLevel(environment, fallback: AppLogLevel.info),
|
||||
useColors: stdout.hasTerminal,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,98 @@
|
|||
import 'package:code_work_spawner/code_work_spawner.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../support/cli_utils.dart';
|
||||
|
||||
void main() {
|
||||
/// ```gherkin
|
||||
/// Feature: CLI log level option
|
||||
///
|
||||
/// As an operator running code_work_spawner
|
||||
/// I want to configure log verbosity with a CLI flag
|
||||
/// So that I can easily collect the right level of diagnostics
|
||||
/// ```
|
||||
group('code_work_spawner --log-level', () {
|
||||
setUp(AppEnvironment.resetForTest);
|
||||
|
||||
tearDown(() {
|
||||
AppEnvironment.resetForTest();
|
||||
AppLogger.configure(minimumLevel: AppLogLevel.info, useColors: false);
|
||||
});
|
||||
|
||||
/// ```gherkin
|
||||
/// Scenario: Parse a valid log level from the CLI
|
||||
/// Given the operator passes --log-level WARN
|
||||
/// When the CLI argument parser initializes logging
|
||||
/// Then the configured minimum level is warning
|
||||
/// ```
|
||||
test('Parse a valid log level from the CLI', () async {
|
||||
// Given the operator passes --log-level WARN.
|
||||
final result = await runCli(['--log-level', 'WARN', '--help']);
|
||||
|
||||
// When the CLI argument parser initializes logging.
|
||||
final minimumLevel = AppLogger.minimumLevel;
|
||||
|
||||
// Then the configured minimum level is warning.
|
||||
expect(result.exitCode, 0);
|
||||
expect(minimumLevel, AppLogLevel.warning);
|
||||
});
|
||||
|
||||
/// ```gherkin
|
||||
/// Scenario: Reject an invalid CLI log level
|
||||
/// Given the operator passes --log-level verbose
|
||||
/// When the CLI validates the value
|
||||
/// Then the command exits with a non-zero status and prints allowed values
|
||||
/// ```
|
||||
test('Reject an invalid CLI log level', () async {
|
||||
// Given the operator passes --log-level verbose.
|
||||
final result = await runCli(['--log-level', 'verbose']);
|
||||
|
||||
// When the CLI validates the value.
|
||||
final output = result.stdout;
|
||||
|
||||
// Then the command exits with a non-zero status and prints allowed values.
|
||||
expect(result.exitCode, isNonZero);
|
||||
expect(output, contains('Invalid value for --log-level "verbose".'));
|
||||
expect(
|
||||
output,
|
||||
contains('Allowed values: trace, debug, info, warn, error.'),
|
||||
);
|
||||
});
|
||||
|
||||
/// ```gherkin
|
||||
/// Scenario: CLI log level overrides environment variables
|
||||
/// Given LOG_LEVEL is set to error in the environment
|
||||
/// When the operator passes --log-level debug
|
||||
/// Then the minimum logging level is debug
|
||||
/// ```
|
||||
test('CLI log level overrides environment variables', () async {
|
||||
// Given LOG_LEVEL is set to error in the environment.
|
||||
AppEnvironment.resetForTest(const <String, String>{'LOG_LEVEL': 'error'});
|
||||
|
||||
// When the operator passes --log-level debug.
|
||||
final result = await runCli(['--log-level', 'debug', '--help']);
|
||||
|
||||
// Then the minimum logging level is debug.
|
||||
expect(result.exitCode, 0);
|
||||
expect(AppLogger.minimumLevel, AppLogLevel.debug);
|
||||
});
|
||||
|
||||
/// ```gherkin
|
||||
/// Scenario: Default log level falls back to info
|
||||
/// Given no CLI or environment log level is configured
|
||||
/// When the CLI initializes logging
|
||||
/// Then the minimum logging level is info
|
||||
/// ```
|
||||
test('Default log level falls back to info', () async {
|
||||
// Given no CLI or environment log level is configured.
|
||||
AppEnvironment.resetForTest(const <String, String>{});
|
||||
|
||||
// When the CLI initializes logging.
|
||||
final result = await runCli(['--help']);
|
||||
|
||||
// Then the minimum logging level is info.
|
||||
expect(result.exitCode, 0);
|
||||
expect(AppLogger.minimumLevel, AppLogLevel.info);
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
Reference in New Issue