@@ -268,6 +268,77 @@ message formatting.
268268> Create the replay- safe logger once at the start of your orchestrator
269269> and reuse it throughout the function.
270270
271+ # ## SDK logging
272+
273+ `TaskHubGrpcClient` , `AsyncTaskHubGrpcClient` , and `TaskHubGrpcWorker`
274+ accept a configured `logging.Logger` through their `logger` parameter. The
275+ SDK uses a supplied logger unchanged: it does not add handlers or modify its
276+ formatter, level, filters, or propagation setting. The Durable Task Scheduler
277+ client and worker accept the same parameter.
278+
279+ Use one shared logger when client and worker records should use the same
280+ destination, format , and correlation filters:
281+
282+ ```python
283+ import logging
284+
285+ from durabletask.client import TaskHubGrpcClient
286+ from durabletask.worker import TaskHubGrpcWorker
287+
288+ sdk_logger = logging.getLogger(" myapp.durabletask" )
289+ sdk_logger.setLevel(logging.INFO )
290+
291+ handler = logging.StreamHandler()
292+ handler.setFormatter(logging.Formatter(
293+ " %(asctime)s %(name)s %(levelname)s %(message)s " ))
294+ sdk_logger.addHandler(handler)
295+ sdk_logger.propagate = False
296+
297+ worker = TaskHubGrpcWorker(logger = sdk_logger)
298+ client = TaskHubGrpcClient(logger = sdk_logger)
299+ ```
300+
301+ Because `logging.getLogger()` returns the same logger for a given name,
302+ configure a shared logger once during application startup. Do not add a new
303+ handler every time a client or worker is constructed, or every record will be
304+ emitted once by each handler.
305+
306+ Alternatively, configure handlers on the root logger and allow propagation:
307+
308+ ```python
309+ import logging
310+
311+ logging.basicConfig(level = logging.INFO )
312+ sdk_logger = logging.getLogger(" myapp.durabletask" )
313+
314+ worker = TaskHubGrpcWorker(logger = sdk_logger)
315+ client = TaskHubGrpcClient(logger = sdk_logger)
316+ ```
317+
318+ > [! WARNING ]
319+ > Use either handlers attached directly to `sdk_logger` with
320+ > `sdk_logger.propagate = False ` , or root handlers with propagation enabled.
321+ > Combining both emits each Durable Task record twice.
322+
323+ Pass separate named loggers when clients and workers need independently
324+ configured levels, destinations, or filters:
325+
326+ ```python
327+ worker = TaskHubGrpcWorker(
328+ logger = logging.getLogger(" myapp.durabletask.worker" ))
329+ client = TaskHubGrpcClient(
330+ logger = logging.getLogger(" myapp.durabletask.client" ))
331+ ```
332+
333+ The older `log_handler` and `log_formatter` parameters are deprecated. They
334+ will be removed in a future major release. Passing either one together with
335+ `logger` raises `ValueError ` ; none of the supplied logging options are ignored.
336+
337+ > [! NOTE ]
338+ > SDK clients and workers emit detailed `DEBUG ` logs that can help diagnose
339+ > orchestration behavior. Enable that level on the logger you pass to the SDK
340+ > when reproducing an issue.
341+
271342# ## Large payload externalization
272343
273344Orchestration inputs, outputs, and event data are transmitted through gRPC messages. When these
@@ -571,34 +642,6 @@ export_client = ExportHistoryClient(
571642> first- party destinations (S3, GCS , etc.) will be packaged as
572643> additional optional extras using the same pattern.
573644
574- # ## Logging configuration
575-
576- Both the TaskHubGrpcWorker and TaskHubGrpcClient (as well as DurableTaskSchedulerWorker and
577- DurableTaskSchedulerClient for durabletask- azuremanaged) accept a log_handler and log_formatter
578- object from `logging` . These can be used to customize verbosity, output location, and format of logs
579- emitted by these sources.
580-
581- For example, to output logs to a file called `worker.log` at level `DEBUG ` , the following syntax
582- might apply:
583-
584- ```python
585- log_handler = logging.FileHandler(' durable.log' , encoding = ' utf-8' )
586- log_handler.setLevel(logging.DEBUG )
587-
588- with DurableTaskSchedulerWorker(
589- host_address = endpoint,
590- secure_channel = secure_channel,
591- taskhub = taskhub_name,
592- token_credential = credential,
593- log_handler = log_handler,
594- ) as w:
595- ```
596-
597- > [! NOTE ]
598- > The worker and client output many logs at the `DEBUG ` level that will be useful when understanding
599- orchestration flow and diagnosing issues with Durable applications. Before submitting issues, please
600- attempt a repro of the issue with debug logging enabled.
601-
602645# ## Work item filtering
603646
604647By default a worker receives ** all ** work items from the backend, regardless of which
0 commit comments