From f3e996fc0613bfb1fda94e5a2b4355496ce6fb76 Mon Sep 17 00:00:00 2001
From: Kevin <kevlu@nvidia.com>
Date: Thu, 9 Jan 2025 20:45:28 -0500
Subject: [PATCH 1/5] add error log sending to master template and create
 provisioning function to configure it

---
 nvflare/lighter/constants.py                  |  1 +
 nvflare/lighter/ctx.py                        | 15 +++++++++++++-
 nvflare/lighter/impl/static_file.py           | 20 ++++++++++++++++++-
 nvflare/lighter/templates/master_template.yml | 14 +++++++++++--
 4 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/nvflare/lighter/constants.py b/nvflare/lighter/constants.py
index a6341d3abb..5a62052901 100644
--- a/nvflare/lighter/constants.py
+++ b/nvflare/lighter/constants.py
@@ -43,6 +43,7 @@ class PropKey:
     OVERSEER_END_POINT = "overseer_end_point"
     ADMIN_PORT = "admin_port"
     FED_LEARN_PORT = "fed_learn_port"
+    ALLOW_ERROR_SENDING = "allow_error_sending"
 
 
 class CtxKey(WorkDir, PropKey):
diff --git a/nvflare/lighter/ctx.py b/nvflare/lighter/ctx.py
index f55cdfd303..8838873787 100644
--- a/nvflare/lighter/ctx.py
+++ b/nvflare/lighter/ctx.py
@@ -13,6 +13,7 @@
 # limitations under the License.
 import json
 import os
+from calendar import c
 
 import yaml
 
@@ -103,8 +104,20 @@ def yaml_load_template_section(self, section_key: str):
     def json_load_template_section(self, section_key: str):
         return json.loads(self.get_template_section(section_key))
 
-    def build_from_template(self, dest_dir: str, temp_section: str, file_name, replacement=None, mode="t", exe=False):
+    def build_from_template(
+        self,
+        dest_dir: str,
+        temp_section: str,
+        file_name,
+        replacement=None,
+        mode="t",
+        exe=False,
+        content_modify_cb=None,
+        **cb_kwargs,
+    ):
         section = self.get_template_section(temp_section)
         if replacement:
             section = utils.sh_replace(section, replacement)
+        if content_modify_cb:
+            section = content_modify_cb(section, **cb_kwargs)
         utils.write(os.path.join(dest_dir, file_name), section, mode, exe=exe)
diff --git a/nvflare/lighter/impl/static_file.py b/nvflare/lighter/impl/static_file.py
index 742f2eaac2..a6d85abd31 100644
--- a/nvflare/lighter/impl/static_file.py
+++ b/nvflare/lighter/impl/static_file.py
@@ -17,6 +17,8 @@
 import os
 
 import yaml
+from sphinx import ret
+from sympy import comp, content
 
 from nvflare.lighter import utils
 from nvflare.lighter.constants import CtxKey, OverseerRole, PropKey, ProvFileName, ProvisionMode, TemplateSectionKey
@@ -218,7 +220,11 @@ def _build_client(self, client, ctx):
         ctx.build_from_template(dest_dir, TemplateSectionKey.LOG_CONFIG, ProvFileName.LOG_CONFIG_DEFAULT)
 
         ctx.build_from_template(
-            dest_dir, TemplateSectionKey.LOCAL_CLIENT_RESOURCES, ProvFileName.RESOURCES_JSON_DEFAULT
+            dest_dir,
+            TemplateSectionKey.LOCAL_CLIENT_RESOURCES,
+            ProvFileName.RESOURCES_JSON_DEFAULT,
+            content_modify_cb=self._modify_error_sender,
+            client=client,
         )
 
         ctx.build_from_template(
@@ -233,6 +239,18 @@ def _build_client(self, client, ctx):
         dest_dir = ctx.get_ws_dir(client)
         ctx.build_from_template(dest_dir, TemplateSectionKey.CLIENT_README, ProvFileName.README_TXT)
 
+    def _modify_error_sender(self, section: dict, client: Participant):
+        allow = client.get_prop_fb(PropKey.ALLOW_ERROR_SENDING, False)
+        if not allow:
+            components = section.get("components")
+            assert isinstance(components, list)
+            for c in components:
+                if c["id"] == "error_log_sender":
+                    components.remove(c)
+                    break
+
+        return section
+
     @staticmethod
     def _check_host_name(host_name: str, server: Participant) -> str:
         if host_name == server.get_default_host():
diff --git a/nvflare/lighter/templates/master_template.yml b/nvflare/lighter/templates/master_template.yml
index 68961077d2..d5ca34a1fc 100644
--- a/nvflare/lighter/templates/master_template.yml
+++ b/nvflare/lighter/templates/master_template.yml
@@ -97,7 +97,12 @@ local_client_resources: |
         "id": "process_launcher",
         "path": "nvflare.app_common.job_launcher.client_process_launcher.ClientProcessJobLauncher",
         "args": {}
-      }
+      },
+      {
+          "id": "error_log_sender",
+          "path": "nvflare.app_common.logging.log_sender.ErrorLogSender",
+          "args": {}
+      },
     ]
   }
 
@@ -226,7 +231,12 @@ local_server_resources: |
               "id": "process_launcher",
               "path": "nvflare.app_common.job_launcher.server_process_launcher.ServerProcessJobLauncher",
               "args": {}
-          }
+          },
+          {
+              "id": "log_receiver",
+              "path": "nvflare.app_common.logging.log_receiver.LogReceiver",
+              "args": {}
+          },
       ]
   }
 

From 3bdb1e02105fd42bc8e4e94bfec0adcbef5d35a9 Mon Sep 17 00:00:00 2001
From: Kevin <kevlu@nvidia.com>
Date: Fri, 10 Jan 2025 17:09:21 -0500
Subject: [PATCH 2/5] fix ci

---
 nvflare/lighter/ctx.py              | 1 -
 nvflare/lighter/impl/static_file.py | 2 --
 2 files changed, 3 deletions(-)

diff --git a/nvflare/lighter/ctx.py b/nvflare/lighter/ctx.py
index 8838873787..ad44fce735 100644
--- a/nvflare/lighter/ctx.py
+++ b/nvflare/lighter/ctx.py
@@ -13,7 +13,6 @@
 # limitations under the License.
 import json
 import os
-from calendar import c
 
 import yaml
 
diff --git a/nvflare/lighter/impl/static_file.py b/nvflare/lighter/impl/static_file.py
index a6d85abd31..299712e24e 100644
--- a/nvflare/lighter/impl/static_file.py
+++ b/nvflare/lighter/impl/static_file.py
@@ -17,8 +17,6 @@
 import os
 
 import yaml
-from sphinx import ret
-from sympy import comp, content
 
 from nvflare.lighter import utils
 from nvflare.lighter.constants import CtxKey, OverseerRole, PropKey, ProvFileName, ProvisionMode, TemplateSectionKey

From c9d6873abf081df7ab034693b2221f55791a94e3 Mon Sep 17 00:00:00 2001
From: Kevin <kevlu@nvidia.com>
Date: Mon, 13 Jan 2025 15:00:34 -0500
Subject: [PATCH 3/5] add docstring

---
 nvflare/lighter/ctx.py | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/nvflare/lighter/ctx.py b/nvflare/lighter/ctx.py
index ad44fce735..2d0a2ce603 100644
--- a/nvflare/lighter/ctx.py
+++ b/nvflare/lighter/ctx.py
@@ -114,6 +114,19 @@ def build_from_template(
         content_modify_cb=None,
         **cb_kwargs,
     ):
+        """Build a file from a template section and writes it to the specified location.
+
+        Args:
+            dest_dir: destination directory
+            temp_section: template section key
+            file_name: file name
+            replacement: replacement dict
+            mode: file mode
+            exe: executable
+            content_modify_cb: content modification callback, can be included to take the section content as the first argument and return the modified content
+            cb_kwargs: additional keyword arguments for the callback
+
+        """
         section = self.get_template_section(temp_section)
         if replacement:
             section = utils.sh_replace(section, replacement)

From 5d882b768d88e6eb3b9c1a3f1fee1e6e08a74959 Mon Sep 17 00:00:00 2001
From: Kevin <kevlu@nvidia.com>
Date: Wed, 15 Jan 2025 13:28:39 -0500
Subject: [PATCH 4/5] fix problem with CI

---
 nvflare/lighter/impl/static_file.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/nvflare/lighter/impl/static_file.py b/nvflare/lighter/impl/static_file.py
index 0c88325df1..e8ffcaaf90 100644
--- a/nvflare/lighter/impl/static_file.py
+++ b/nvflare/lighter/impl/static_file.py
@@ -274,6 +274,8 @@ def _build_client(self, client, ctx):
         ctx.build_from_template(dest_dir, TemplateSectionKey.CLIENT_README, ProvFileName.README_TXT)
 
     def _modify_error_sender(self, section: dict, client: Participant):
+        if not isinstance(section, dict):
+            return section
         allow = client.get_prop_fb(PropKey.ALLOW_ERROR_SENDING, False)
         if not allow:
             components = section.get("components")

From 7d7a60ebfdcaacb379e11dfe2797c9a2c1bafc63 Mon Sep 17 00:00:00 2001
From: Kevin <kevlu@nvidia.com>
Date: Wed, 15 Jan 2025 14:20:19 -0500
Subject: [PATCH 5/5] try to fix ci

---
 nvflare/lighter/templates/master_template.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/nvflare/lighter/templates/master_template.yml b/nvflare/lighter/templates/master_template.yml
index d5ca34a1fc..d9dbd58521 100644
--- a/nvflare/lighter/templates/master_template.yml
+++ b/nvflare/lighter/templates/master_template.yml
@@ -102,7 +102,7 @@ local_client_resources: |
           "id": "error_log_sender",
           "path": "nvflare.app_common.logging.log_sender.ErrorLogSender",
           "args": {}
-      },
+      }
     ]
   }
 
@@ -236,7 +236,7 @@ local_server_resources: |
               "id": "log_receiver",
               "path": "nvflare.app_common.logging.log_receiver.LogReceiver",
               "args": {}
-          },
+          }
       ]
   }