Skip to content

Commit 950d9d9

Browse files
author
Dilyan Marinov
committed
vdk-structlog: add default logging format values
Why? There should be separate default configs for local and cloud runs What? Refactor structlog plugin to eliminate repeating code Remove syslog config tests Fix bug with vdk fields crashing logging for custom format Add tests for vdk fields with custom format Add default logging config to the data job base image Note: The default config will not have effect unless vdk-structlog is installed How was this tested? Functional tests CI What kind of change is this? Feature/non-breaking Signed-off-by: Dilyan Marinov <mdilyan@vmware.com>
1 parent 59d2a85 commit 950d9d9

File tree

6 files changed

+222
-336
lines changed

6 files changed

+222
-336
lines changed

projects/control-service/projects/job-base-image/Dockerfile-data-job-base

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ WORKDIR /job
1111
# Install native dependencies so that requirements in requirements.txt can be installed
1212
# some (like openssl) should be pre-installed in the base image but let's be explicit
1313
RUN set -ex \
14-
&& apt-get update \
15-
&& apt-get -y install --no-install-recommends \
16-
build-essential openssl g++
14+
&& apt-get update \
15+
&& apt-get -y install --no-install-recommends \
16+
build-essential openssl g++
1717

1818
# Install the native dependencies necessary for cx_Oracle python library
1919
# See https://oracle.github.io/odpi/doc/installation.html#linux
@@ -27,6 +27,11 @@ RUN set -ex \
2727
&& ldconfig \
2828
&& apt-get purge -y --auto-remove curl unzip
2929

30+
# Setup default logging with vdk-structlog
31+
ENV VDK_STRUCTLOG_FORMAT="console"
32+
ENV VDK_STRUCTLOG_CONSOLE_CUSTOM_FORMAT="%(asctime)s [VDK] %(vdk_job_name)s [%(levelname)-5.5s] %(name)-30.30s %(filename)20.20s:%(lineno)-4.4s %(funcName)-16.16s[id:%(attempt_id)s] - %(message)s"
33+
34+
3035
# libaio1 - LGPL-2.1+ https://developer.puri.sm/licenses/Librem5/Birch/libaio1/copyright
3136
# curl - MIT/X* modified https://curl.se/docs/copyright.html
3237
# unzip - MIT https://github.com/vipsoft/Unzip/blob/master/LICENSE

projects/vdk-plugins/vdk-structlog/src/vdk/plugin/structlog/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
STRUCTLOG_LOGGING_FORMAT_DEFAULT = "console"
1212

1313
STRUCTLOG_LOGGING_METADATA_JOB = {
14+
"attempt_id": "%(attempt_id)s",
1415
"vdk_job_name": "%(vdk_job_name)s",
1516
"vdk_step_name": "%(vdk_step_name)s",
1617
"vdk_step_type": "%(vdk_step_type)s",
@@ -44,6 +45,7 @@
4445
}
4546

4647
CONSOLE_STRUCTLOG_LOGGING_METADATA_JOB = {
48+
"attempt_id": "[id:%(attempt_id)s]",
4749
"vdk_job_name": "%(vdk_job_name)s",
4850
"vdk_step_name": "%(vdk_step_name)s",
4951
"vdk_step_type": "%(vdk_step_type)s",

projects/vdk-plugins/vdk-structlog/src/vdk/plugin/structlog/structlog_plugin.py

Lines changed: 125 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from vdk.plugin.structlog.filters import AttributeAdder
3636
from vdk.plugin.structlog.formatters import create_formatter
3737
from vdk.plugin.structlog.log_level_utils import set_non_root_log_levels
38-
from vdk.plugin.structlog.syslog_config import configure_syslog_handler
38+
from vdk.plugin.structlog.syslog_config import create_syslog_handler
3939

4040
"""
4141
Handlers
@@ -77,6 +77,74 @@ def process(self, msg, kwargs):
7777
"""
7878

7979

80+
def _get_syslog_config(context: CoreContext):
81+
syslog_enabled = context.configuration.get_value(
82+
SYSLOG_ENABLED_KEY
83+
)
84+
syslog_host = context.configuration.get_value(SYSLOG_HOST_KEY)
85+
syslog_port = context.configuration.get_value(SYSLOG_PORT_KEY)
86+
syslog_protocol = context.configuration.get_value(
87+
SYSLOG_PROTOCOL_KEY
88+
)
89+
90+
return syslog_enabled, syslog_host, syslog_port, syslog_protocol
91+
92+
93+
def _create_formatter_and_metadata_filter(context: CoreContext):
94+
metadata_keys = context.configuration.get_value(STRUCTLOG_LOGGING_METADATA_KEY)
95+
logging_formatter = context.configuration.get_value(
96+
STRUCTLOG_LOGGING_FORMAT_KEY
97+
)
98+
custom_format_string = context.configuration.get_value(
99+
STRUCTLOG_CONSOLE_LOG_PATTERN
100+
)
101+
102+
formatter, metadata_filter = create_formatter(
103+
logging_formatter, metadata_keys, custom_format_string
104+
)
105+
return formatter, metadata_filter
106+
107+
108+
def _configure_non_root_log_levels(context: CoreContext):
109+
if logging.getLogger().getEffectiveLevel() == logging.NOTSET:
110+
log_level = os.environ.get(
111+
"LOG_LEVEL_VDK", os.environ.get("VDK_LOG_LEVEL_VDK", "INFO")
112+
).upper()
113+
logging.getLogger().setLevel(log_level)
114+
vdk_log_level = context.configuration.get_value(vdk_config.LOG_LEVEL_VDK)
115+
if vdk_log_level is None:
116+
vdk_log_level = logging.getLogger().getEffectiveLevel()
117+
log_level_module = context.configuration.get_value(vdk_config.LOG_LEVEL_MODULE)
118+
set_non_root_log_levels(vdk_log_level, log_level_module)
119+
120+
121+
def _clear_root_logger_handlers():
122+
root_logger = logging.getLogger()
123+
handlers_to_remove = root_logger.handlers
124+
for handler in handlers_to_remove:
125+
root_logger.removeHandler(handler)
126+
127+
128+
def _configure_root_logger(context: CoreContext, formatter, *filters):
129+
_clear_root_logger_handlers()
130+
root_logger = logging.getLogger()
131+
132+
handlers = [logging.StreamHandler(sys.stderr)]
133+
134+
syslog_config = _get_syslog_config(context)
135+
syslog_handler = create_syslog_handler(
136+
*syslog_config
137+
)
138+
if syslog_handler:
139+
handlers.append(syslog_handler)
140+
141+
for handler in handlers:
142+
for f in filters:
143+
handler.addFilter(f)
144+
handler.setFormatter(formatter)
145+
root_logger.addHandler(handler)
146+
147+
80148
class StructlogPlugin:
81149
@hookimpl(tryfirst=True)
82150
def vdk_configure(self, config_builder: ConfigurationBuilder):
@@ -134,208 +202,99 @@ def vdk_configure(self, config_builder: ConfigurationBuilder):
134202

135203
@hookimpl
136204
def vdk_initialize(self, context: CoreContext):
137-
if logging.getLogger().getEffectiveLevel() == logging.NOTSET:
138-
log_level = os.environ.get(
139-
"LOG_LEVEL_VDK", os.environ.get("VDK_LOG_LEVEL_VDK", "INFO")
140-
).upper()
141-
logging.getLogger().setLevel(log_level)
142-
vdk_log_level = context.configuration.get_value(vdk_config.LOG_LEVEL_VDK)
143-
if vdk_log_level is None:
144-
vdk_log_level = logging.getLogger().getEffectiveLevel()
145-
log_level_module = context.configuration.get_value(vdk_config.LOG_LEVEL_MODULE)
146-
147-
set_non_root_log_levels(vdk_log_level, log_level_module)
148-
149-
metadata_keys = context.configuration.get_value(STRUCTLOG_LOGGING_METADATA_KEY)
150-
logging_formatter = context.configuration.get_value(
151-
STRUCTLOG_LOGGING_FORMAT_KEY
152-
)
153-
custom_format_string = context.configuration.get_value(
154-
STRUCTLOG_CONSOLE_LOG_PATTERN
155-
)
205+
_configure_non_root_log_levels(context)
206+
formatter, metadata_filter = _create_formatter_and_metadata_filter(context)
156207

157-
formatter, metadata_filter = create_formatter(
158-
logging_formatter, metadata_keys, custom_format_string
159-
)
208+
attempt_id = context.state.get(CommonStoreKeys.ATTEMPT_ID)
209+
attempt_id_adder = AttributeAdder("attempt_id", attempt_id)
160210

161-
root_logger = logging.getLogger()
162-
root_logger.removeHandler(root_logger.handlers[0])
211+
# Add placeholder values in case of custom format string
212+
job_name_adder = AttributeAdder("vdk_job_name", "")
213+
step_name_adder = AttributeAdder("vdk_step_name", "")
214+
step_type_adder = AttributeAdder("vdk_step_type", "")
163215

164-
handler = logging.StreamHandler(sys.stderr)
165-
handler.addFilter(metadata_filter)
166-
handler.setFormatter(formatter)
167-
168-
root_logger.addHandler(handler)
216+
_configure_root_logger(context, formatter, attempt_id_adder, job_name_adder, step_name_adder,
217+
step_type_adder, metadata_filter)
169218

170219
@hookimpl(hookwrapper=True)
171220
def initialize_job(self, context: JobContext) -> None:
172-
metadata_keys = context.core_context.configuration.get_value(
173-
STRUCTLOG_LOGGING_METADATA_KEY
174-
)
175-
job_name = context.name
176-
if logging.getLogger().getEffectiveLevel() == logging.NOTSET:
177-
log_level = os.environ.get(
178-
"LOG_LEVEL_VDK", os.environ.get("VDK_LOG_LEVEL_VDK", "INFO")
179-
).upper()
180-
logging.getLogger().setLevel(log_level)
181-
vdk_log_level = context.core_context.configuration.get_value(
182-
vdk_config.LOG_LEVEL_VDK
183-
)
184-
if vdk_log_level is None:
185-
vdk_log_level = logging.getLogger().getEffectiveLevel()
186-
log_level_module = context.core_context.configuration.get_value(
187-
vdk_config.LOG_LEVEL_MODULE
188-
)
189221

190-
set_non_root_log_levels(vdk_log_level, log_level_module)
222+
_configure_non_root_log_levels(context.core_context)
223+
formatter, metadata_filter = _create_formatter_and_metadata_filter(context.core_context)
191224

192-
logging_formatter = context.core_context.configuration.get_value(
193-
STRUCTLOG_LOGGING_FORMAT_KEY
194-
)
195-
custom_format_string = context.core_context.configuration.get_value(
196-
STRUCTLOG_CONSOLE_LOG_PATTERN
197-
)
225+
attempt_id = context.core_context.state.get(CommonStoreKeys.ATTEMPT_ID)
226+
attempt_id_adder = AttributeAdder("attempt_id", attempt_id)
198227

199-
formatter, metadata_filter = create_formatter(
200-
logging_formatter, metadata_keys, custom_format_string
201-
)
228+
job_name = context.name
202229
job_name_adder = AttributeAdder("vdk_job_name", job_name)
203230

204-
root_logger = logging.getLogger()
205-
root_logger.removeHandler(root_logger.handlers[0])
231+
# Add placeholder values in case of custom format string
232+
step_name_adder = AttributeAdder("vdk_step_name", "")
233+
step_type_adder = AttributeAdder("vdk_step_type", "")
206234

207-
handler = logging.StreamHandler(sys.stderr)
208-
handler.setFormatter(formatter)
209-
handler.addFilter(job_name_adder)
210-
handler.addFilter(metadata_filter)
211-
212-
root_logger.addHandler(handler)
213-
214-
syslog_enabled = context.core_context.configuration.get_value(
215-
SYSLOG_ENABLED_KEY
216-
)
217-
syslog_host = context.core_context.configuration.get_value(SYSLOG_HOST_KEY)
218-
syslog_port = context.core_context.configuration.get_value(SYSLOG_PORT_KEY)
219-
syslog_protocol = context.core_context.configuration.get_value(
220-
SYSLOG_PROTOCOL_KEY
221-
)
222-
attempt_id = context.core_context.state.get(CommonStoreKeys.ATTEMPT_ID)
223-
syslog_handler = configure_syslog_handler(
224-
syslog_enabled,
225-
syslog_host,
226-
syslog_port,
227-
syslog_protocol,
228-
job_name,
229-
attempt_id,
230-
)
231-
if syslog_handler:
232-
root_logger.addHandler(syslog_handler)
235+
_configure_root_logger(context.core_context, formatter, attempt_id_adder, job_name_adder, step_name_adder,
236+
step_type_adder, metadata_filter)
233237

234238
out: HookCallResult
235239
out = yield
236240

237-
root_logger.removeHandler(handler)
238-
if syslog_handler:
239-
root_logger.removeHandler(syslog_handler)
241+
_clear_root_logger_handlers()
240242

241243
@hookimpl(hookwrapper=True)
242244
def run_job(self, context: JobContext) -> Optional[ExecutionResult]:
243-
metadata_keys = context.core_context.configuration.get_value(
244-
STRUCTLOG_LOGGING_METADATA_KEY
245-
)
246-
job_name = context.name
247-
if logging.getLogger().getEffectiveLevel() == logging.NOTSET:
248-
log_level = os.environ.get(
249-
"LOG_LEVEL_VDK", os.environ.get("VDK_LOG_LEVEL_VDK", "INFO")
250-
).upper()
251-
logging.getLogger().setLevel(log_level)
252-
vdk_log_level = context.core_context.configuration.get_value(
253-
vdk_config.LOG_LEVEL_VDK
254-
)
255-
if vdk_log_level is None:
256-
vdk_log_level = logging.getLogger().getEffectiveLevel()
257-
log_level_module = context.core_context.configuration.get_value(
258-
vdk_config.LOG_LEVEL_MODULE
259-
)
260245

261-
set_non_root_log_levels(vdk_log_level, log_level_module)
246+
_configure_non_root_log_levels(context.core_context)
247+
formatter, metadata_filter = _create_formatter_and_metadata_filter(context.core_context)
262248

263-
logging_formatter = context.core_context.configuration.get_value(
264-
STRUCTLOG_LOGGING_FORMAT_KEY
265-
)
266-
custom_format_string = context.core_context.configuration.get_value(
267-
STRUCTLOG_CONSOLE_LOG_PATTERN
268-
)
249+
attempt_id = context.core_context.state.get(CommonStoreKeys.ATTEMPT_ID)
250+
attempt_id_adder = AttributeAdder("attempt_id", attempt_id)
269251

270-
formatter, metadata_filter = create_formatter(
271-
logging_formatter, metadata_keys, custom_format_string
272-
)
252+
job_name = context.name
273253
job_name_adder = AttributeAdder("vdk_job_name", job_name)
274254

275-
root_logger = logging.getLogger()
276-
root_logger.removeHandler(root_logger.handlers[0])
277-
278-
handler = logging.StreamHandler(sys.stderr)
279-
handler.setFormatter(formatter)
280-
handler.addFilter(job_name_adder)
281-
handler.addFilter(metadata_filter)
282-
283-
root_logger.addHandler(handler)
255+
# Add placeholder values in case of custom format string
256+
step_name_adder = AttributeAdder("vdk_step_name", "")
257+
step_type_adder = AttributeAdder("vdk_step_type", "")
284258

285-
syslog_enabled = context.core_context.configuration.get_value(
286-
SYSLOG_ENABLED_KEY
287-
)
288-
syslog_host = context.core_context.configuration.get_value(SYSLOG_HOST_KEY)
289-
syslog_port = context.core_context.configuration.get_value(SYSLOG_PORT_KEY)
290-
syslog_protocol = context.core_context.configuration.get_value(
291-
SYSLOG_PROTOCOL_KEY
292-
)
293-
attempt_id = context.core_context.state.get(CommonStoreKeys.ATTEMPT_ID)
294-
syslog_handler = configure_syslog_handler(
295-
syslog_enabled,
296-
syslog_host,
297-
syslog_port,
298-
syslog_protocol,
299-
job_name,
300-
attempt_id,
301-
)
302-
if syslog_handler:
303-
root_logger.addHandler(syslog_handler)
259+
_configure_root_logger(context.core_context, formatter, attempt_id_adder, job_name_adder, step_name_adder,
260+
step_type_adder, metadata_filter)
304261

305262
out: HookCallResult
306263
out = yield
307-
308-
# do not remove the handler, we need it until the end
264+
# do not remove handlers, we need them until the end
309265

310266
@hookimpl(hookwrapper=True)
311267
def run_step(self, context: JobContext, step: Step) -> Optional[StepResult]:
312-
root_logger = logging.getLogger()
313-
handler = root_logger.handlers[0]
314-
metadata_filter = None
315-
# make sure the metadata filter executes last
316-
# so that step_name and step_type are filtered if necessary
317-
metadata_filter_result = [
318-
f for f in handler.filters if f.name == "metadata_filter"
319-
]
320-
if metadata_filter_result:
321-
metadata_filter = metadata_filter_result[0]
322-
323-
if metadata_filter:
324-
handler.removeFilter(metadata_filter)
325268

269+
root_logger = logging.getLogger()
326270
step_name_adder = AttributeAdder("vdk_step_name", step.name)
327271
step_type_adder = AttributeAdder("vdk_step_type", step.type)
328-
handler.addFilter(step_name_adder)
329-
handler.addFilter(step_type_adder)
330272

331-
# make sure the metadata filter executes last
332-
# so that step_name and step_type are filtered if necessary
333-
if metadata_filter:
334-
handler.addFilter(metadata_filter)
273+
for handler in root_logger.handlers:
274+
metadata_filter = None
275+
# make sure the metadata filter executes last
276+
# so that step_name and step_type are filtered if necessary
277+
metadata_filter_result = [
278+
f for f in handler.filters if f.name == "metadata_filter"
279+
]
280+
if metadata_filter_result:
281+
metadata_filter = metadata_filter_result[0]
282+
283+
if metadata_filter:
284+
handler.removeFilter(metadata_filter)
285+
286+
handler.addFilter(step_name_adder)
287+
handler.addFilter(step_type_adder)
288+
289+
# make sure the metadata filter executes last
290+
# so that step_name and step_type are filtered if necessary
291+
if metadata_filter:
292+
handler.addFilter(metadata_filter)
335293
out: HookCallResult
336294
out = yield
337-
handler.removeFilter(step_name_adder)
338-
handler.removeFilter(step_type_adder)
295+
for handler in root_logger.handlers:
296+
handler.removeFilter(step_name_adder)
297+
handler.removeFilter(step_type_adder)
339298

340299

341300
@hookimpl

0 commit comments

Comments
 (0)