Copilot commented on code in PR #13090:
URL: https://github.com/apache/trafficserver/pull/13090#discussion_r3114074153
##########
src/mgmt/config/ConfigReloadTrace.cc:
##########
@@ -287,6 +296,65 @@ ConfigReloadTask::aggregate_status()
}
}
+void
+ConfigReloadTask::log_reload_summary(State final_state)
+{
+ if (!_info.main_task || !is_terminal(final_state) || _summary_logged) {
+ return;
+ }
+ _summary_logged = true;
+
Review Comment:
ConfigReloadTask::log_reload_summary reads/writes `_info` (e.g.,
`_info.main_task`, `_info.sub_tasks`, `_info.token`) and `_summary_logged`
without holding `_mutex`. Other methods in this class treat `_info` as
protected by `_mutex`, and readers (e.g., status queries) can run concurrently,
so this risks data races. Consider taking a lock (or copying via `get_info()`
under lock) and making `_summary_logged` atomic or also guarded by the same
lock.
##########
doc/developer-guide/config-reload-framework.en.rst:
##########
@@ -672,6 +672,228 @@ See the :ref:`get_reload_config_status` response examples
for how log messages a
task tree output.
+.. _config-reload-unified-macros:
+
+Unified Diagnostic Macros (``CfgLoad*``)
+=========================================
+
+Config handlers often need the same message in two places: the ATS diagnostic
log
+(``diags.log`` / ``error.log``) **and** the reload task log (visible via
+:option:`traffic_ctl config status`). The ``CfgLoad*`` macros in
+``mgmt/config/ConfigContextDiags.h`` format the message once and dispatch to
both destinations.
+
+Include the header in any source file that uses these macros:
+
+.. code-block:: cpp
+
+ #include "mgmt/config/ConfigContextDiags.h"
+
+Quick Reference
+---------------
+
+.. list-table::
+ :header-rows: 1
+ :widths: 15 15 40
+
+ * - Want in diags?
+ - Want in task log?
+ - Use
+ * - Note
+ - yes + in_progress
+ - ``CfgLoadInProgress(ctx, ...)`` (subtasks)
+ * - Note
+ - yes + complete
+ - ``CfgLoadComplete(ctx, ...)``
+ * - Error
+ - yes + fail
+ - ``CfgLoadFail(ctx, ...)``
+ * - Error + Errata
+ - yes + fail
+ - ``CfgLoadFailWithErrata(ctx, errata, ...)``
+ * - Note / Warning
+ - yes (no state change)
+ - ``CfgLoadLog(ctx, DL_Note|DL_Warning, ...)``
+ * - Dbg (conditional on tag)
+ - yes
+ - ``CfgLoadDbg(ctx, ctl, ...)``
+ * - no
+ - yes
+ - ``ctx.log(...)``
+ * - no
+ - yes + state
+ - ``ctx.complete()`` / ``ctx.fail()``
+ * - yes
+ - no
+ - ``Note()`` / ``Warning()`` / ``Error()`` / ``Dbg()`` directly
+
+Macro Details
+-------------
+
+``CfgLoadInProgress(ctx, fmt, ...)``
+ Emits a ``Note()`` to ``diags.log`` and calls ``ctx.in_progress(msg)``. The
framework
+ sets ``IN_PROGRESS`` on handler tasks automatically, so this macro is
primarily useful
+ for subtasks created via ``add_dependent_ctx()``:
+
+ .. code-block:: cpp
+
+ CfgLoadInProgress(ctx, "%s loading ...", filename);
+
+``CfgLoadComplete(ctx, fmt, ...)``
+ Emits a ``Note()`` to ``diags.log`` and calls ``ctx.complete(msg)``. Use
when a config
+ operation finishes successfully:
+
+ .. code-block:: cpp
+
+ CfgLoadComplete(ctx, "%s finished loading", filename);
+
+``CfgLoadFail(ctx, fmt, ...)``
+ Emits an ``Error()`` to ``diags.log`` and the task log, then marks the task
as FAIL.
+ Fail always implies ``DL_Error`` — if the condition is merely degraded (not
fatal to
+ the load), use ``CfgLoadLog(ctx, DL_Warning, ...)`` + ``CfgLoadComplete()``
instead:
+
+ .. code-block:: cpp
+
+ CfgLoadFail(ctx, "%s failed to load", filename);
+
+``CfgLoadFailWithErrata(ctx, errata, fmt, ...)``
+ Like ``CfgLoadFail`` but also appends ``swoc::Errata`` annotations to the
task log.
+ Combines ``CfgLoadFail`` + ``ctx.fail(errata)`` in one call — see
+ :ref:`config-reload-errata-handling` below.
+
+``CfgLoadLog(ctx, level, fmt, ...)``
+ Emits at the given ``DiagsLevel`` and calls ``ctx.log(level, msg)``
**without changing
+ task state**. Use for intermediate informational messages:
+
+ .. code-block:: cpp
+
+ CfgLoadLog(ctx, DL_Warning, "ControlMatcher - Cannot open config file:
%s", path);
+ CfgLoadLog(ctx, DL_Note, "loaded %d categories from %s", count,
filename);
+
+``CfgLoadDbg(ctx, dbg_ctl, fmt, ...)``
+ Emits via ``Dbg()`` (conditional on the tag being enabled) and always adds
to the task log
+ at ``DL_Debug``. Use for debug-level messages that should also appear in
reload status:
+
+ .. code-block:: cpp
+
+ CfgLoadDbg(ctx, dbg_ctl_ssl, "Reload SNI file");
+
+.. _config-reload-errata-handling:
+
+Errata Handling
+---------------
+
+For failures with ``swoc::Errata`` detail, use ``CfgLoadFailWithErrata`` to
combine
+the diags summary, errata detail, and state change in a single call:
+
+.. code-block:: cpp
+
+ CfgLoadFailWithErrata(ctx, errata, "%s failed to load", filename);
+
+This logs the formatted message to ``diags.log`` at ``DL_Error``, appends it to
+the task log, then calls ``ctx.fail(errata)`` which stores each errata
annotation
+(with its own severity) in the task log and marks the task as FAIL.
+
+For errors that should not change state, pair ``CfgLoadLog`` with
``ctx.log(errata)``:
+
+.. code-block:: cpp
+
+ CfgLoadLog(ctx, DL_Error, "Cannot open %s", path);
+ ctx.log(errata); // errata detail -> task log only
+
+When NOT to Use Macros
+-----------------------
+
+- **Task-log-only messages** — use ``ctx.log()`` directly when the message is
only useful in
+ ``traffic_ctl`` output and should not appear in ``diags.log``.
+- **State-only transitions** — use ``ctx.in_progress()`` / ``ctx.complete()``
/ ``ctx.fail()``
+ directly when there is no message to emit to ``diags.log``.
+- **Fatal errors** — ``Fatal()`` terminates the process; reload status is
irrelevant.
+ Call ``Fatal()`` directly.
+
+
+Severity-Aware Task Logs
+=========================
+
+Each task log entry carries a ``DiagsLevel`` severity. State-transition
methods carry implicit
+severity: ``in_progress(text)`` and ``complete(text)`` store ``DL_Note``,
``fail(text)`` stores
+``DL_Error``. The ``CfgLoad*`` macros and ``ctx.log(level, text)`` store the
caller-specified
+level. Only the one-argument ``ctx.log(text)`` (no level) stores
``DL_Undefined`` — these
+entries are always shown regardless of ``--min-level`` filtering.
+
+In :option:`traffic_ctl config status` output, entries with a defined severity
are prefixed
+with a tag:
+
+.. code-block:: text
+
+ ✗ ssl_client_coordinator ······················· 2ms ✗ FAIL
+ │ [Note] SSL configs reloaded
+ ├─ ✔ SSLConfig ································· 1ms
+ │ [Note] SSLConfig loading ...
+ │ [Note] SSLConfig reloaded
+ ├─ ✗ SNIConfig ································· 1ms ✗ FAIL
+ │ [Note] sni.yaml loading ...
+ │ [Err] sni.yaml failed to load
+ └─ ✔ SSLCertificateConfig ······················ 0ms
+ [Note] (ssl) ssl_multicert.yaml loading ...
+ [Warn] Cannot open SSL certificate configuration
"ssl_multicert.yaml" - No such file or directory
+ [Note] (ssl) ssl_multicert.yaml finished loading
+
+The ``--min-level`` option on :option:`traffic_ctl config status` filters log
entries
+by severity — see :option:`traffic_ctl config status` for details.
+
+The severity is also available in JSON output (``--format json``) as an
integer ``level``
+field on each log entry, where the value maps to the ``DiagsLevel`` enum (e.g.
``1`` = Debug,
+``3`` = Note, ``4`` = Warning, ``5`` = Error).
+
+
+.. _config-reload-diags-log:
+
+Reload Summary in ``diags.log``
+================================
+
+After a reload reaches a terminal state (confirmed after a 5-second grace
period), a summary
+line is logged to ``diags.log``:
+
+**Success:**
+
+.. code-block:: text
+
+ NOTE: Config reload [my-token] completed successfully: 3 tasks succeeded (3
total)
Review Comment:
The documented success summary line here ("completed successfully: 3 tasks
succeeded (3 total)") doesn’t match the current implementation in
`ConfigReloadTask::log_reload_summary()` (which logs "completed: %d/%d tasks
succeeded"). Please align the documentation with the actual output, or adjust
the code to emit the documented message format.
```suggestion
NOTE: Config reload [my-token] completed: 3/3 tasks succeeded
```
##########
src/mgmt/config/ConfigReloadTrace.cc:
##########
@@ -287,6 +296,65 @@ ConfigReloadTask::aggregate_status()
}
}
+void
+ConfigReloadTask::log_reload_summary(State final_state)
+{
+ if (!_info.main_task || !is_terminal(final_state) || _summary_logged) {
+ return;
+ }
+ _summary_logged = true;
+
+ int success_count{0}, fail_count{0}, total{0};
+ for (const auto &sub : _info.sub_tasks) {
+ State st = sub->get_state();
+ if (st == State::SUCCESS) {
+ success_count++;
+ } else if (st == State::FAIL || st == State::TIMEOUT) {
+ fail_count++;
+ }
+ total++;
+ }
+
+ if (final_state == State::SUCCESS) {
+ Note("Config reload [%s] completed: %d/%d tasks succeeded",
_info.token.c_str(), success_count, total);
Review Comment:
The success summary log text here ("completed: %d/%d tasks succeeded") does
not match the documented example in
`doc/developer-guide/config-reload-framework.en.rst` ("completed successfully:
3 tasks succeeded (3 total)"). Either update the log format to match the
docs/examples or adjust the documentation so operators can grep/recognize the
exact message.
```suggestion
Note("Config reload [%s] completed successfully: %d tasks succeeded (%d
total)", _info.token.c_str(), success_count,
total);
```
##########
src/iocore/net/SSLConfig.cc:
##########
@@ -572,6 +573,7 @@ SSLConfigParams::initialize()
Emergency("Can't initialize the SSL client, HTTPS in remap rules will not
function");
} else {
SSLError("Can't initialize the SSL client, HTTPS in remap rules will not
function");
+ CfgLoadLog(ctx, DL_Warning, "Can't initialize the SSL client, HTTPS in
remap rules will not function");
Review Comment:
This logs the same message twice to diags: once via `SSLError(...)` (which
already emits to the diagnostics system) and again via `CfgLoadLog(...)` (which
also emits to diags via `DiagsError`). If the goal is to get the message into
the reload task log, consider using `ctx.log(DL_Warning, ...)` (task-log-only)
instead of `CfgLoadLog`, or otherwise avoid duplicating the diags entry.
```suggestion
ctx.log(DL_Warning, "Can't initialize the SSL client, HTTPS in remap
rules will not function");
```
##########
src/traffic_ctl/CtrlCommands.cc:
##########
@@ -267,6 +268,22 @@ ConfigCommand::config_status()
count = ""; // server will ignore this if token is set anyways.
}
+ if (!min_level.empty()) {
+ static const std::unordered_map<std::string_view, DiagsLevel> level_map = {
+ {"debug", DL_Debug },
+ {"note", DL_Note },
+ {"warning", DL_Warning},
+ {"error", DL_Error },
+ };
+ if (auto it = level_map.find(min_level); it != level_map.end()) {
+ _printer->as<ConfigReloadPrinter>()->set_min_level(it->second);
+ } else {
+ _printer->write_output("Invalid --min-level value. Use: debug, note,
warning, error");
Review Comment:
`--min-level` parsing is currently case-sensitive
(`level_map.find(min_level)`), but the CLI docs describe the values as
case-insensitive. Consider normalizing the input (e.g., lowercase) before
lookup (and possibly trimming) so `--min-level Warning` works as documented.
##########
include/mgmt/config/ConfigReloadTrace.h:
##########
@@ -171,6 +171,15 @@ class ConfigReloadTask : public
std::enable_shared_from_this<ConfigReloadTask>
return
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}
+ /// A single log entry with optional severity.
+ /// Entries from log() carry a DiagsLevel; entries from state-change methods
+ /// (in_progress, complete, fail) use DL_Undefined (the task state itself
+ /// conveys severity).
+ struct LogEntry {
+ DiagsLevel level{DL_Undefined}; ///< DL_Undefined for state-change
messages
Review Comment:
This comment says state-change methods (in_progress/complete/fail) store log
entries with `DL_Undefined`, but `ConfigContext` now records `DL_Note` for
in_progress/complete messages and `DL_Error` for fail(reason) messages (see
`src/mgmt/config/ConfigContext.cc`). Please update the comment to reflect the
new severity behavior so it stays consistent with the implementation.
```suggestion
/// Entries from log() carry a DiagsLevel; state-change methods use
/// DL_Note for in_progress/complete messages and DL_Error for fail()
/// messages.
struct LogEntry {
DiagsLevel level{DL_Undefined}; ///< log() supplies the level; state
changes use DL_Note or DL_Error
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]