Skip to content

Commit 755bf41

Browse files
committed
Changes
- Set level to debug for execution logs - Allow logging config in durabletask-python - Update docs for logging
1 parent 09bfe58 commit 755bf41

File tree

4 files changed

+40
-10
lines changed

4 files changed

+40
-10
lines changed

docs/features.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,4 +148,21 @@ Orchestrations can be suspended using the `suspend_orchestration` client API and
148148

149149
### Retry policies
150150

151-
Orchestrations can specify retry policies for activities and sub-orchestrations. These policies control how many times and how frequently an activity or sub-orchestration will be retried in the event of a transient error.
151+
Orchestrations can specify retry policies for activities and sub-orchestrations. These policies control how many times and how frequently an activity or sub-orchestration will be retried in the event of a transient error.
152+
153+
### Logging configuration
154+
155+
Both the TaskHubGrpcWorker and TaskHubGrpcClient (as well as DurableTaskSchedulerWorker and DurableTaskSchedulerClient for durabletask-azuremanaged) accept a log_handler and log_formatter object from `logging`. These can be used to customize verbosity, output location, and format of logs emitted by these sources.
156+
157+
For example, to output logs to a file called `worker.log` at level `DEBUG`, the following syntax might apply:
158+
159+
```python
160+
log_handler = logging.FileHandler('durable.log', encoding='utf-8')
161+
log_handler.setLevel(logging.DEBUG)
162+
163+
with DurableTaskSchedulerWorker(host_address=endpoint, secure_channel=secure_channel,
164+
taskhub=taskhub_name, token_credential=credential, log_handler=log_handler) as w:
165+
```
166+
167+
**NOTE**
168+
The worker and client output many logs at the `DEBUG` level that will be useful when understanding orchestration flow and diagnosing issues with Durable applications. Before submitting issues, please attempt a repro of the issue with debug logging enabled.

durabletask-azuremanaged/durabletask/azuremanaged/client.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Copyright (c) Microsoft Corporation.
22
# Licensed under the MIT License.
33

4+
import logging
5+
46
from typing import Optional
57

68
from azure.core.credentials import TokenCredential
@@ -18,7 +20,9 @@ def __init__(self, *,
1820
taskhub: str,
1921
token_credential: Optional[TokenCredential],
2022
secure_channel: bool = True,
21-
default_version: Optional[str] = None):
23+
default_version: Optional[str] = None,
24+
log_handler=None,
25+
log_formatter: Optional[logging.Formatter] = None):
2226

2327
if not taskhub:
2428
raise ValueError("Taskhub value cannot be empty. Please provide a value for your taskhub")
@@ -31,5 +35,7 @@ def __init__(self, *,
3135
host_address=host_address,
3236
secure_channel=secure_channel,
3337
metadata=None,
38+
log_handler=log_handler,
39+
log_formatter=log_formatter,
3440
interceptors=interceptors,
3541
default_version=default_version)

durabletask-azuremanaged/durabletask/azuremanaged/worker.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Copyright (c) Microsoft Corporation.
22
# Licensed under the MIT License.
33

4+
import logging
5+
46
from typing import Optional
57

68
from azure.core.credentials import TokenCredential
@@ -52,12 +54,15 @@ class DurableTaskSchedulerWorker(TaskHubGrpcWorker):
5254
parameter is set to None since authentication is handled by the
5355
DTS interceptor.
5456
"""
57+
5558
def __init__(self, *,
5659
host_address: str,
5760
taskhub: str,
5861
token_credential: Optional[TokenCredential],
5962
secure_channel: bool = True,
60-
concurrency_options: Optional[ConcurrencyOptions] = None):
63+
concurrency_options: Optional[ConcurrencyOptions] = None,
64+
log_handler=None,
65+
log_formatter: Optional[logging.Formatter] = None):
6166

6267
if not taskhub:
6368
raise ValueError("The taskhub value cannot be empty.")
@@ -70,5 +75,7 @@ def __init__(self, *,
7075
host_address=host_address,
7176
secure_channel=secure_channel,
7277
metadata=None,
78+
log_handler=log_handler,
79+
log_formatter=log_formatter,
7380
interceptors=interceptors,
7481
concurrency_options=concurrency_options)

durabletask/worker.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,7 +1238,7 @@ def execute(
12381238
if len(orchestration_started_events) >= 1:
12391239
orchestration_name = orchestration_started_events[0].executionStarted.name
12401240

1241-
self._logger.info(
1241+
self._logger.debug(
12421242
f"{instance_id}: Beginning replay for orchestrator {orchestration_name}..."
12431243
)
12441244

@@ -1279,7 +1279,7 @@ def execute(
12791279

12801280
except Exception as ex:
12811281
# Unhandled exceptions fail the orchestration
1282-
self._logger.info(f"{instance_id}: Orchestration {orchestration_name} failed")
1282+
self._logger.debug(f"{instance_id}: Orchestration {orchestration_name} failed")
12831283
ctx.set_failed(ex)
12841284

12851285
if not ctx._is_complete:
@@ -1295,7 +1295,7 @@ def execute(
12951295
completion_status_str = ph.get_orchestration_status_str(
12961296
ctx._completion_status
12971297
)
1298-
self._logger.info(
1298+
self._logger.debug(
12991299
f"{instance_id}: Orchestration {orchestration_name} completed with status: {completion_status_str}"
13001300
)
13011301

@@ -1764,7 +1764,7 @@ def execute(
17641764
encoded_input: Optional[str],
17651765
) -> Optional[str]:
17661766
"""Executes an activity function and returns the serialized result, if any."""
1767-
self._logger.info(
1767+
self._logger.debug(
17681768
f"{orchestration_id}/{task_id}: Executing activity '{name}'..."
17691769
)
17701770
fn = self._registry.get_activity(name)
@@ -1783,7 +1783,7 @@ def execute(
17831783
shared.to_json(activity_output) if activity_output is not None else None
17841784
)
17851785
chars = len(encoded_output) if encoded_output else 0
1786-
self._logger.info(
1786+
self._logger.debug(
17871787
f"{orchestration_id}/{task_id}: Activity '{name}' completed successfully with {chars} char(s) of encoded output."
17881788
)
17891789
return encoded_output
@@ -1803,7 +1803,7 @@ def execute(
18031803
encoded_input: Optional[str],
18041804
) -> Optional[str]:
18051805
"""Executes an entity function and returns the serialized result, if any."""
1806-
self._logger.info(
1806+
self._logger.debug(
18071807
f"{orchestration_id}: Executing entity '{entity_id}'..."
18081808
)
18091809
fn = self._registry.get_entity(entity_id.entity)
@@ -1837,7 +1837,7 @@ def execute(
18371837
shared.to_json(entity_output) if entity_output is not None else None
18381838
)
18391839
chars = len(encoded_output) if encoded_output else 0
1840-
self._logger.info(
1840+
self._logger.debug(
18411841
f"{orchestration_id}: Entity '{entity_id}' completed successfully with {chars} char(s) of encoded output."
18421842
)
18431843
return encoded_output

0 commit comments

Comments
 (0)