Skip to content

Commit 04c3713

Browse files
HakonSohoelandreas-el
authored andcommitted
Format logged config dict to enhance readability
Previously some parts of the config dict has been filtered out from the log message to make it fit within the 32768 message size limit of App Insights (among others forward model steps). These parts should be kept, and instead the config dict logging is split into multiple messages when it exceeds the message size limit of App Insights. With this commit the config dict log message(s) will look as follows: ``` 2025-02-20 09:50:36.539 | Content of the config_dict (part 1/2): { "DEFINE": [ [ "<CONFIG_PATH>", "/var/folders/mg/jwjt9mcj02l1cqy_57szt4hc0000gp/T/tmph0lhx8yc" ],... 2025-02-20 09:50:36.540 | Content of the config_dict (part 2/2): <Continues where part 1 stopped> ... ```
1 parent 6fe82f9 commit 04c3713

File tree

2 files changed

+52
-11
lines changed

2 files changed

+52
-11
lines changed

src/ert/config/ert_config.py

+40-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# mypy: ignore-errors
22
import copy
3+
import json
34
import logging
45
import os
56
import re
@@ -22,6 +23,7 @@
2223
from pydantic import field_validator
2324
from pydantic.dataclasses import dataclass, rebuild_dataclass
2425

26+
from ert.config.parsing.context_values import ContextBoolEncoder
2527
from ert.plugins import ErtPluginManager
2628
from ert.substitutions import Substitutions
2729

@@ -911,14 +913,31 @@ def _log_config_file(cls, config_file: str, config_file_contents: str) -> None:
911913

912914
@classmethod
913915
def _log_config_dict(cls, content_dict: dict[str, Any]) -> None:
914-
tmp_dict = content_dict.copy()
915-
tmp_dict.pop("FORWARD_MODEL", None)
916-
tmp_dict.pop("LOAD_WORKFLOW", None)
917-
tmp_dict.pop("LOAD_WORKFLOW_JOB", None)
918-
tmp_dict.pop("HOOK_WORKFLOW", None)
919-
tmp_dict.pop("WORKFLOW_JOB_DIRECTORY", None)
920-
921-
logger.info(f"Content of the config_dict: {tmp_dict}")
916+
# The content of the message is sanitized before beeing sendt to App Insigths to make sure GDPR-rules are not violated.
917+
# In doing do, the message lenght will typically increase a bit. To Avoid hiting the App Insights' hard limit of message length, the limit is set to 80%
918+
# of MAX_MESSAGE_LENGTH_APP_INSIGHTS = 32768
919+
SAFE_MESSAGE_LENGTH_LIMIT = 26214 # <= MAX_MESSAGE_LENGTH_APP_INSIGHTS * 0.8
920+
try:
921+
config_dict_content = json.dumps(
922+
content_dict, indent=2, cls=ContextBoolEncoder
923+
)
924+
except Exception as err:
925+
config_dict_content = str(content_dict)
926+
logger.warning(
927+
f"Logging of config dict could not be formatted for enhanced readability. {err}"
928+
)
929+
config_dict_content_length = len(config_dict_content)
930+
if config_dict_content_length > SAFE_MESSAGE_LENGTH_LIMIT:
931+
config_sections = _split_string_into_sections(
932+
config_dict_content, SAFE_MESSAGE_LENGTH_LIMIT
933+
)
934+
section_count = len(config_sections)
935+
for i, section in enumerate(config_sections):
936+
logger.info(
937+
f"Content of the config_dict (part {i + 1}/{section_count}): {section}"
938+
)
939+
else:
940+
logger.info(f"Content of the config_dict: {config_dict_content}")
922941

923942
@classmethod
924943
def _log_custom_forward_model_steps(cls, user_config: ConfigDict) -> None:
@@ -1089,6 +1108,19 @@ def _create_observations(
10891108
return EnkfObs(obs_vectors, obs_time_list)
10901109

10911110

1111+
def _split_string_into_sections(input: str, section_length: int) -> list[str]:
1112+
"""
1113+
Splits a string into sections of length section_length
1114+
and returns it as a list.
1115+
1116+
If section_length is set to 0 or less, no sectioning is performed and the entire input string
1117+
is returned as one section in a list
1118+
"""
1119+
if section_length < 1:
1120+
return [input]
1121+
return [input[i : i + section_length] for i in range(0, len(input), section_length)]
1122+
1123+
10921124
def _get_files_in_directory(job_path, errors):
10931125
if not path.isdir(job_path):
10941126
errors.append(

tests/ert/unit_tests/config/test_ert_config.py

+12-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616
from pydantic import RootModel, TypeAdapter
1717

1818
from ert.config import ConfigValidationError, ErtConfig, HookRuntime
19-
from ert.config.ert_config import (
20-
create_forward_model_json,
21-
)
19+
from ert.config.ert_config import _split_string_into_sections, create_forward_model_json
2220
from ert.config.parsing import ConfigKeys, ConfigWarning
2321
from ert.config.parsing.context_values import (
2422
ContextBool,
@@ -1851,3 +1849,14 @@ def test_warning_is_emitted_when_malformatted_runpath():
18511849
("RUNPATH keyword contains no value placeholders" in str(w.message))
18521850
for w in all_warnings
18531851
)
1852+
1853+
1854+
@given(input=st.text(), section_length=st.integers())
1855+
def test_split_string_into_sections(input, section_length):
1856+
split_string = _split_string_into_sections(input, section_length)
1857+
assert "".join(split_string) == input
1858+
if section_length > 0:
1859+
for section in split_string:
1860+
assert len(section) <= section_length
1861+
else:
1862+
split_string = [input]

0 commit comments

Comments
 (0)