wenshao commented on code in PR #28855:
URL: https://github.com/apache/flink/pull/28855#discussion_r3696500725


##########
docs/content/docs/ops/logging_context.md:
##########
@@ -0,0 +1,86 @@
+---
+title: "Logging Context (MDC)"
+weight: 7
+type: docs

Review Comment:
   **[Suggestion]** Hugo `weight: 7` collides with sibling 
`docs/content/docs/ops/events.md` (also `weight: 7`), making their nav ordering 
non-deterministic. — Concrete cost: Hugo falls back to alphabetical 
tie-breaking between "Events" and "Logging Context (MDC)", so the sidebar 
position becomes an accident of the title rather than an editorial choice. The 
same collision exists in `docs/content.zh/docs/ops/logging_context.md`.
   
   ```suggestion
   title: "Logging Context (MDC)"
   weight: 8
   type: docs
   ```
   
   _— qwen3.8-max-preview via Qwen Code /review (v0.21.2)_



##########
flink-core/src/main/java/org/apache/flink/util/MdcUtils.java:
##########
@@ -112,7 +115,38 @@ public static ScheduledExecutorService scopeToJob(JobID 
jobID, ScheduledExecutor
         return new MdcAwareScheduledExecutorService(ses, asContextData(jobID));
     }
 
+    /**
+     * Build MDC context for a job. Consults the {@link JobMdcRegistry} for 
enriched context
+     * registered where the job {@link Configuration} is available; falls back 
to the plain job ID
+     * entry.
+     */
     public static Map<String, String> asContextData(JobID jobID) {
+        final Map<String, String> registered = JobMdcRegistry.lookup(jobID);
+        if (registered != null) {
+            return registered;
+        }
         return Collections.singletonMap(JOB_ID, jobID.toHexString());
     }
+
+    /**
+     * Build MDC context from a job ID and job configuration, enriching with 
context entries
+     * configured via {@link MdcOptions#JOB_CONFIGURATION_TO_MDC_KEYS}.
+     */
+    public static Map<String, String> asContextData(
+            final JobID jobID, final Configuration jobConfiguration) {
+        final Map<String, String> mdcKeyMapping =
+                jobConfiguration.get(MdcOptions.JOB_CONFIGURATION_TO_MDC_KEYS);
+        final Map<String, String> context = new HashMap<>();
+        for (Map.Entry<String, String> entry : mdcKeyMapping.entrySet()) {
+            final String value = jobConfiguration.getString(entry.getKey(), 
null);
+            if (value != null && !value.isBlank()) {
+                context.put(entry.getValue(), value);

Review Comment:
   **[Suggestion]** The mapping target (MDC key name, `entry.getValue()`) is 
not validated for blank/empty, while the mapping source value is explicitly 
checked for blankness — an asymmetry that allows an empty or whitespace-only 
MDC key to be published. — Failure scenario: an operator configures 
`mdc.job-configuration-to-mdc-keys: {my.key: ""}` in `config.yaml`. The code 
puts an entry with an empty-string key into the context map, which is then set 
on every thread's MDC for that job. In Log4j2 JSON layout this produces `"": 
"some-value"` in every log record; in pattern layout, `%X{}` with an empty key 
has implementation-dependent behavior.
   
   ```suggestion
                        for (Map.Entry<String, String> entry : 
mdcKeyMapping.entrySet()) {
                                final String value = 
jobConfiguration.getString(entry.getKey(), null);
                                final String mdcKey = entry.getValue();
                                if (value != null && !value.isBlank() && mdcKey 
!= null && !mdcKey.isBlank()) {
                                        context.put(mdcKey, value);
   ```
   
   _— qwen3.8-max-preview via Qwen Code /review (v0.21.2)_



##########
flink-core/src/main/java/org/apache/flink/util/JobMdcRegistry.java:
##########
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.util;
+
+import org.apache.flink.annotation.Internal;
+import org.apache.flink.annotation.VisibleForTesting;
+import org.apache.flink.api.common.JobID;
+import org.apache.flink.configuration.Configuration;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Process-wide registry mapping {@link JobID} to enriched MDC context, 
populated where the job
+ * {@link Configuration} is available and consulted by {@link 
MdcUtils#asContextData(JobID)}.
+ */
+@Internal
+@ThreadSafe
+public final class JobMdcRegistry {
+
+    private static final Map<JobID, Map<String, String>> REGISTRY = new 
ConcurrentHashMap<>();
+
+    private JobMdcRegistry() {}
+
+    /**
+     * Registers enriched MDC context if the configuration carries any MDC key 
mappings; clears any
+     * stale entry otherwise. Equivalent to {@link #unregister} when the 
config is unenriched.
+     */
+    public static void registerOrClear(final JobID jobID, final Configuration 
jobConfiguration) {
+        final Map<String, String> context = MdcUtils.asContextData(jobID, 
jobConfiguration);
+        if (context.size() > 1) {
+            REGISTRY.put(jobID, context);
+        } else {
+            unregister(jobID);
+        }

Review Comment:
   **[Suggestion]** No diagnostic logging at any level when MDC enrichment is 
configured but resolves to zero entries, making misconfiguration invisible at 
runtime. — Failure scenario: an operator configures 
`mdc.job-configuration-to-mdc-keys: pipeline.name: pipeline-name` but the job 
is submitted without `-Dpipeline.name=...`. Every mapped key is silently 
skipped, `registerOrClear` calls `unregister`, and all log records carry only 
`flink-job-id`. At 3 AM, the oncall engineer sees no error, no warning, and no 
debug message explaining why the expected `pipeline-name` field is absent from 
every log record.
   
   Consider adding a debug-level log that reports the configured mapping size 
and the resolved entry count, e.g.:
   ```java
   if (LOG.isDebugEnabled()) {
       LOG.debug("MDC enrichment for job {}: {} configured key(s), {} resolved 
entry(ies).",
           jobID, mdcKeyMapping.size(), context.size() - 1);
   }
   ```
   
   _— qwen3.8-max-preview via Qwen Code /review (v0.21.2)_



##########
flink-runtime/src/main/java/org/apache/flink/runtime/taskexecutor/TaskExecutor.java:
##########
@@ -2078,6 +2084,7 @@ private void releaseJobResources(JobID jobId, Exception 
cause) {
         taskInformationCache.clearCacheForGroup(jobId);
         shuffleDescriptorsCache.clearCacheForGroup(jobId);
         fileMergingManager.releaseMergingSnapshotManagerForJob(jobId);
+        JobMdcRegistry.unregister(jobId);

Review Comment:
   **[Suggestion]** The TaskExecutor-side cleanup (`JobMdcRegistry.unregister` 
in the job release method) has no test; `TaskExecutorSubmissionTest` only 
verifies registration, not deregistration on release. — Failure scenario: if 
the `unregister` call were removed, every completed job's MDC entry would 
remain in the static `ConcurrentHashMap` for the lifetime of the TaskManager 
process. On a long-running TaskManager processing hundreds of short-lived jobs, 
this is an unbounded memory leak in a process-wide static registry. The 
Dispatcher-side cleanup is tested 
(`testJobMdcContextRegisteredOnSubmissionAndClearedOnTermination`), but the 
TM-side equivalent is not.
   
   _— qwen3.8-max-preview via Qwen Code /review (v0.21.2)_



##########
flink-runtime/src/main/java/org/apache/flink/runtime/taskexecutor/TaskExecutor.java:
##########
@@ -661,9 +662,20 @@ public CompletableFuture<Acknowledge> submitTask(
             TaskDeploymentDescriptor tdd, JobMasterId jobMasterId, Duration 
timeout) {
 
         final JobID jobId = tdd.getJobId();
-        // todo: consider adding task info
-        try (MdcCloseable ignored = 
MdcUtils.withContext(MdcUtils.asContextData(jobId))) {
-
+        JobInformation jobInformation = null;
+        try {
+            jobInformation = tdd.getJobInformation();
+        } catch (IllegalStateException ignored) {
+            // Expected when job information is offloaded to blob storage and 
not yet loaded.

Review Comment:
   **[Suggestion]** The new early-deserialization fallback for offloaded job 
information (the `IllegalStateException` catch and the `jobInformation == null` 
ternary) has no test coverage. — Failure scenario: 
`TaskExecutorSubmissionTest.testJobMdcContextRegisteredOnSubmitTask` always 
constructs a TDD with inline job information, so `tdd.getJobInformation()` 
never throws `IllegalStateException`. If a future refactor removes the catch 
block or the null-guarded ternary, tasks with job information offloaded to blob 
storage (the production path for large job graphs) would fail submission with 
an unhandled `IllegalStateException`, and no test would catch the regression.
   
   _— qwen3.8-max-preview via Qwen Code /review (v0.21.2)_



##########
flink-runtime/src/main/java/org/apache/flink/runtime/dispatcher/Dispatcher.java:
##########
@@ -572,6 +573,7 @@ private void runRecoveredJob(
         initJobClientExpiredTime(recoveredJob);
 
         final JobID jobId = recoveredJob.getJobID();
+        JobMdcRegistry.registerOrClear(jobId, 
recoveredJob.getJobConfiguration());
         try (MdcCloseable ignored = 
MdcUtils.withContext(MdcUtils.asContextData(jobId))) {

Review Comment:
   **[Suggestion]** The Dispatcher recovery path (`recoverJob`) MDC 
registration and its failure-path cleanup (`unregister` in the catch block) 
have no test coverage; `DispatcherTest` only tests the submission path. — 
Failure scenario: if the `registerOrClear` call in `recoverJob` were removed 
during a refactor, jobs recovered after a JobManager failover would silently 
lose enriched MDC context — all log lines for recovered jobs would carry only 
`flink-job-id` despite the job having MDC mappings configured. No existing test 
would fail.
   
   _— qwen3.8-max-preview via Qwen Code /review (v0.21.2)_



-- 
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]

Reply via email to