Skip to content

Commit 4dac0c7

Browse files
Merge pull request #257 from cleverage/157
#157 - Configure the level of the end of process logs
2 parents 29db12e + 9493df7 commit 4dac0c7

12 files changed

Lines changed: 468 additions & 49 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Latest
99
* [#117](https://github.com/cleverage/process-bundle/issues/117) MappingTransformer: writing a target property that is a nested path (e.g. `address.city`) on an array destination, which silently created an `address.city` literal key, is deprecated and will throw an `\UnexpectedValueException` in v6.0. Use `[address.city]` for a literal key or `[address][city]` for a nested array; a simple property name (e.g. `name`) is still added as a key. Update documentation, add tests.
1010
* [#258](https://github.com/cleverage/process-bundle/issues/258) Add XmlStreamReaderTask: iterable task reading an XML file element by element with `\XMLReader` (constant memory), outputting each element named `node_name` as a `\DOMElement` in its own `\DOMDocument`, ready for XpathEvaluatorTransformer. The file path is set in the `file_path` option or given as input. Add documentation and tests.
1111
* [#259](https://github.com/cleverage/process-bundle/issues/259) JsonStreamWriterTask: add a `mode` option (default `wb`, e.g. `ab` to append to an existing JSON Lines file), and release the file on `finalize()`. Update documentation, add tests.
12+
* [#157](https://github.com/cleverage/process-bundle/issues/157) Configure the level of the logs written at the end of each process with the new `logs` option, globally (`clever_age_process.logs`) or per process (`configurations.<code>.logs`): `success_level` (default `info`) for `Process <code> succeed`, and `failed_level` (default `debug`) for the new `Process <code> failed` log, written when a process fails, with or without exception. Update documentation, add tests.
1213

1314
## Fixes
1415
* [#143](https://github.com/cleverage/process-bundle/issues/143) Fix InputIteratorTask: an `\IteratorAggregate` input whose `getIterator()` does not return an `\Iterator` (e.g. another `\IteratorAggregate`) is iterated instead of failing with a `TypeError`. Update documentation, add tests.

‎config/services/registry.yaml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ services:
55
arguments:
66
- ~
77
- ~
8+
- ~
89

910
cleverage_process.registry.transformer:
1011
class: CleverAge\ProcessBundle\Registry\TransformerRegistry

‎docs/01-quick_start.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,14 @@ framework:
5151
5252
You can use `./bin/console config:dump-reference clever_age_process` to have a summary of current configuration.
5353

54-
The configuration has three root keys:
54+
The configuration has four root keys:
5555
- `configurations`: your processes (see [process definition](reference/01-process_definition.md))
5656
- `generic_transformers`: reusable transformers built from configuration (see
5757
[generic transformers definition](reference/03-generic_transformers_definition.md))
5858
- `default_error_strategy`: the behavior of a task that encounters an error when it does not define its own
5959
`error_strategy`. Allowed values are `stop` (the default) and `skip`.
60+
- `logs`: the levels of the logs written at the end of each process, `success_level` (`info` by default) and
61+
`failed_level` (`debug` by default), see [process definition](reference/01-process_definition.md#global-attributes)
6062

6163
We recommend keeping the `stop` default, and then specify task by task which one can be skipped:
6264

‎docs/cookbooks/performances_monitoring.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,10 @@ SQL n/a n/a
5252
## Built-in timing information
5353

5454
Before profiling, the process logs already give some timing information:
55-
- on success, the process manager logs `Process <process_code> succeed` (level `info`, channel `cleverage_process`)
56-
with the total `duration` of the process, in seconds, in the record context
55+
- at the end, the process manager logs `Process <process_code> succeed` (level `info` by default, channel
56+
`cleverage_process`) or `Process <process_code> failed` (level `debug` by default), with the total `duration` of
57+
the process, in seconds, in the record context. Both levels can be configured, see the `logs` option of the
58+
[process definition](../reference/01-process_definition.md)
5759
- at `debug` level, the same channel logs each task execution (`Processing task <task_code>`, `Proceeding task ...`,
5860
`Flushing task ...`): with a formatter displaying milliseconds, it shows where the time is spent. With the Monolog
5961
console handler of the Symfony recipe, `-vvv` displays debug records in the console:

‎docs/reference/01-process_definition.md‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ YAML Configuration
77
```yaml
88
clever_age_process:
99
default_error_strategy: <stop|skip>
10+
logs:
11+
success_level: <emergency|alert|critical|error|warning|notice|info|debug>
12+
failed_level: <emergency|alert|critical|error|warning|notice|info|debug>
1013
configurations:
1114
<process_code>:
1215
description: <string>
@@ -15,6 +18,9 @@ clever_age_process:
1518
end_point: <task_code>
1619
public: <true|false>
1720
options: <array>
21+
logs:
22+
success_level: <emergency|alert|critical|error|warning|notice|info|debug>
23+
failed_level: <emergency|alert|critical|error|warning|notice|info|debug>
1824
tasks:
1925
<task_code>: <task_definition>
2026
```
@@ -25,6 +31,16 @@ Global attributes
2531
**default_error_strategy**: optional, either *stop* (default) or *skip*. Error strategy used by every task that does
2632
not define its own `error_strategy` (see [task definition](02-task_definition.md)).
2733

34+
**logs**: optional [RFC 5424](https://datatracker.ietf.org/doc/html/rfc5424) severities of the logs written at the end
35+
of each process (channel `cleverage_process`, with the `duration` of the process in seconds in the record context):
36+
* `success_level` (default *info*): level of the `Process <process_code> succeed` log
37+
* `failed_level` (default *debug*): level of the `Process <process_code> failed` log, written when the process fails,
38+
either with an exception (in addition to the `Critical process failure` log) or when it is stopped without exception
39+
(e.g. by a [StopTask](tasks/stop_task.md))
40+
41+
Without UI, the success log is the only trace of a succeeded process: lower its level (e.g. *debug*) only if processes
42+
are followed by other means.
43+
2844
Process attributes
2945
------------------
3046

@@ -51,6 +67,9 @@ from the process list (unless `--all` is used) but execution is still allowed.
5167
through `ProcessConfiguration::getOptions()`, e.g. [cleverage/ui-process-bundle](https://github.com/cleverage/ui-process-bundle)
5268
reads its `ui` key to configure the launch form.
5369

70+
**logs**: optional `success_level` and `failed_level` overriding, for this process only, the global
71+
[`logs`](#global-attributes) levels (e.g. a scheduled process that often has nothing to do).
72+
5473
**tasks**: list of task definitions contained in the process, indexed by task code. See
5574
[task definition](02-task_definition.md).
5675

‎src/Configuration/ProcessConfiguration.php‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
use CleverAge\ProcessBundle\Exception\CircularProcessException;
1717
use CleverAge\ProcessBundle\Exception\MissingTaskConfigurationException;
18+
use Psr\Log\LogLevel;
1819

1920
/**
2021
* Holds the processes configuration to launch a task.
@@ -44,6 +45,8 @@ public function __construct(
4445
protected string $description = '',
4546
protected string $help = '',
4647
protected bool $public = true,
48+
protected string $successLogLevel = LogLevel::INFO,
49+
protected string $failedLogLevel = LogLevel::DEBUG,
4750
) {
4851
}
4952

@@ -93,6 +96,22 @@ public function isPublic(): bool
9396
return $this->public;
9497
}
9598

99+
/**
100+
* Level of the "Process <code> succeed" log.
101+
*/
102+
public function getSuccessLogLevel(): string
103+
{
104+
return $this->successLogLevel;
105+
}
106+
107+
/**
108+
* Level of the "Process <code> failed" log.
109+
*/
110+
public function getFailedLogLevel(): string
111+
{
112+
return $this->failedLogLevel;
113+
}
114+
96115
public function isPrivate(): bool
97116
{
98117
return !$this->public;

‎src/DependencyInjection/CleverAgeProcessExtension.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public function load(array $configs, ContainerBuilder $container): void
4040
$processConfigurationRegistry = $container->getDefinition('cleverage_process.registry.process_configuration');
4141
$processConfigurationRegistry->replaceArgument(0, $config['configurations']);
4242
$processConfigurationRegistry->replaceArgument(1, $config['default_error_strategy']);
43+
$processConfigurationRegistry->replaceArgument(2, $config['logs']);
4344

4445
// Automatic transformer creation from config
4546
foreach ($config['generic_transformers'] as $transformerCode => $transformerConfig) {

‎src/DependencyInjection/Configuration.php‎

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@
2727
*/
2828
class Configuration implements ConfigurationInterface
2929
{
30+
protected const LOG_LEVELS = [
31+
LogLevel::EMERGENCY,
32+
LogLevel::ALERT,
33+
LogLevel::CRITICAL,
34+
LogLevel::ERROR,
35+
LogLevel::WARNING,
36+
LogLevel::NOTICE,
37+
LogLevel::INFO,
38+
LogLevel::DEBUG,
39+
];
40+
3041
public function __construct(
3142
protected string $root = 'clever_age_process',
3243
) {
@@ -42,6 +53,19 @@ public function getConfigTreeBuilder(): TreeBuilder
4253
->values([TaskConfiguration::STRATEGY_SKIP, TaskConfiguration::STRATEGY_STOP])
4354
->defaultValue(TaskConfiguration::STRATEGY_STOP);
4455

56+
// Default log levels of the end of the processes
57+
$logsDefinition = $definition->arrayNode('logs')
58+
->addDefaultsIfNotSet()
59+
->children();
60+
$logsDefinition->enumNode('success_level')
61+
->values(self::LOG_LEVELS)
62+
->defaultValue(LogLevel::INFO)
63+
->info('Level of the "Process <code> succeed" log');
64+
$logsDefinition->enumNode('failed_level')
65+
->values(self::LOG_LEVELS)
66+
->defaultValue(LogLevel::DEBUG)
67+
->info('Level of the "Process <code> failed" log');
68+
4569
$this->appendRootProcessConfigDefinition($definition);
4670
$this->appendRootTransformersConfigDefinition($definition);
4771

@@ -125,6 +149,20 @@ protected function appendProcessConfigDefinition(NodeBuilder $definition): void
125149
->arrayNode('options')
126150
->prototype('variable')
127151
->end()
152+
->end()
153+
->arrayNode('logs')
154+
->info('Override the default log levels of the end of the process')
155+
->addDefaultsIfNotSet()
156+
->children()
157+
->enumNode('success_level')
158+
->values([...self::LOG_LEVELS, null])
159+
->defaultNull()
160+
->end()
161+
->enumNode('failed_level')
162+
->values([...self::LOG_LEVELS, null])
163+
->defaultNull()
164+
->end()
165+
->end()
128166
->end();
129167

130168
/** @var ArrayNodeDefinition $tasksArrayDefinition */
@@ -145,17 +183,6 @@ protected function appendProcessConfigDefinition(NodeBuilder $definition): void
145183

146184
protected function appendTaskConfigDefinition(NodeBuilder $definition): void
147185
{
148-
$logLevels = [
149-
LogLevel::EMERGENCY,
150-
LogLevel::ALERT,
151-
LogLevel::CRITICAL,
152-
LogLevel::ERROR,
153-
LogLevel::WARNING,
154-
LogLevel::NOTICE,
155-
LogLevel::INFO,
156-
LogLevel::DEBUG,
157-
];
158-
159186
$definition->scalarNode('service')
160187
->isRequired();
161188
$definition->scalarNode('description')
@@ -168,7 +195,7 @@ protected function appendTaskConfigDefinition(NodeBuilder $definition): void
168195
$definition->scalarNode('error_strategy')
169196
->defaultNull();
170197
$definition->enumNode('log_level')
171-
->values($logLevels)
198+
->values(self::LOG_LEVELS)
172199
->defaultValue(LogLevel::CRITICAL);
173200

174201
foreach (['outputs', 'errors', 'error_outputs'] as $nodeName) {

‎src/Manager/ProcessManager.php‎

Lines changed: 53 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -129,44 +129,54 @@ protected function doExecute(string $processCode, mixed $input = null, array $co
129129
$processConfiguration = $this->processConfigurationRegistry->getProcessConfiguration($processCode);
130130
$processHistory = $this->initializeStates($processConfiguration, $context);
131131
$this->processHistory = $processHistory;
132-
$this->checkProcess($processConfiguration);
133132

134-
// First initialize the whole stack in a linear way, tasks are initialized in the order they are configured
135-
foreach ($processConfiguration->getTaskConfigurations() as $taskConfiguration) {
136-
$this->initialize($taskConfiguration);
137-
}
133+
try {
134+
$this->checkProcess($processConfiguration);
138135

139-
// If defined, set the input of a task
140-
if ($processConfiguration->getEntryPoint() instanceof TaskConfiguration) {
141-
$processConfiguration->getEntryPoint()
142-
->getState()
143-
->setInput($input);
144-
} elseif (null !== $input) {
145-
$this->processLogger->warning('Process has no entry point for input');
146-
}
136+
// First initialize the whole stack in a linear way, tasks are initialized in the order they are configured
137+
foreach ($processConfiguration->getTaskConfigurations() as $taskConfiguration) {
138+
$this->initialize($taskConfiguration);
139+
}
147140

148-
// Resolve task from main branch, starting by the end
149-
$taskList = array_reverse($processConfiguration->getTaskConfigurations());
150-
$allowedTasks = $processConfiguration->getMainTaskGroup();
151-
foreach ($taskList as $taskConfiguration) {
152-
if (\in_array($taskConfiguration->getCode(), $allowedTasks, true)) {
153-
$this->resolve($taskConfiguration);
141+
// If defined, set the input of a task
142+
if ($processConfiguration->getEntryPoint() instanceof TaskConfiguration) {
143+
$processConfiguration->getEntryPoint()
144+
->getState()
145+
->setInput($input);
146+
} elseif (null !== $input) {
147+
$this->processLogger->warning('Process has no entry point for input');
154148
}
155-
}
156149

157-
// Finalize the process in a linear way
158-
foreach ($processConfiguration->getTaskConfigurations() as $taskConfiguration) {
159-
$this->finalize($taskConfiguration);
160-
}
150+
// Resolve task from main branch, starting by the end
151+
$taskList = array_reverse($processConfiguration->getTaskConfigurations());
152+
$allowedTasks = $processConfiguration->getMainTaskGroup();
153+
foreach ($taskList as $taskConfiguration) {
154+
if (\in_array($taskConfiguration->getCode(), $allowedTasks, true)) {
155+
$this->resolve($taskConfiguration);
156+
}
157+
}
161158

162-
$this->endProcess($processHistory);
159+
// Finalize the process in a linear way
160+
foreach ($processConfiguration->getTaskConfigurations() as $taskConfiguration) {
161+
$this->finalize($taskConfiguration);
162+
}
163163

164-
// If defined, return the output of a task
165-
$returnValue = null;
166-
if ($processConfiguration->getEndPoint() instanceof TaskConfiguration) {
167-
$returnValue = $processConfiguration->getEndPoint()
168-
->getState()
169-
->getOutput();
164+
$this->endProcess($processHistory);
165+
166+
// If defined, return the output of a task
167+
$returnValue = null;
168+
if ($processConfiguration->getEndPoint() instanceof TaskConfiguration) {
169+
$returnValue = $processConfiguration->getEndPoint()
170+
->getState()
171+
->getOutput();
172+
}
173+
} catch (\Throwable $error) {
174+
if ($processHistory->isStarted()) {
175+
$processHistory->setFailed();
176+
}
177+
$this->endProcess($processHistory);
178+
179+
throw $error;
170180
}
171181

172182
$this->processHistory = $parentProcessHistory;
@@ -519,16 +529,27 @@ protected function handleState(ProcessState $state): void
519529

520530
protected function endProcess(ProcessHistory $history): void
521531
{
532+
$processConfiguration = $this->processConfigurationRegistry->getProcessConfiguration($history->getProcessCode());
533+
522534
// Do not change state if already set
523535
if ($history->isStarted()) {
524536
$history->setSuccess();
525537

526-
$this->processLogger->info(
538+
$this->processLogger->log(
539+
$processConfiguration->getSuccessLogLevel(),
527540
"Process {$history->getProcessCode()} succeed",
528541
[
529542
'duration' => $history->getDuration(),
530543
]
531544
);
545+
} elseif ($history->isFailed()) {
546+
$this->processLogger->log(
547+
$processConfiguration->getFailedLogLevel(),
548+
"Process {$history->getProcessCode()} failed",
549+
[
550+
'duration' => $history->getDuration(),
551+
]
552+
);
532553
}
533554
}
534555

‎src/Registry/ProcessConfigurationRegistry.php‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ class ProcessConfigurationRegistry
3030
protected array $processConfigurations = [];
3131

3232
/**
33-
* @param array<string, array<string, mixed>> $rawConfiguration
33+
* @param array<string, array<string, mixed>> $rawConfiguration
34+
* @param array{success_level?: string, failed_level?: string} $defaultLogLevels
3435
*/
3536
public function __construct(
3637
protected array $rawConfiguration,
3738
protected string $defaultErrorStrategy,
39+
protected array $defaultLogLevels = [],
3840
) {
3941
}
4042

@@ -105,7 +107,9 @@ protected function resolveConfiguration(string $processCode): void
105107
$rawProcessConfiguration['end_point'],
106108
$rawProcessConfiguration['description'],
107109
$rawProcessConfiguration['help'],
108-
$rawProcessConfiguration['public']
110+
$rawProcessConfiguration['public'],
111+
$rawProcessConfiguration['logs']['success_level'] ?? $this->defaultLogLevels['success_level'] ?? LogLevel::INFO,
112+
$rawProcessConfiguration['logs']['failed_level'] ?? $this->defaultLogLevels['failed_level'] ?? LogLevel::DEBUG
109113
);
110114

111115
// Set links between tasks

0 commit comments

Comments
 (0)