Skip to main content
Version: 3.5

Logging

The library logs useful debug information to the apify_client logger whenever it sends requests to the Apify API. You can configure this logger to print debug information to the standard output by adding a handler:

import logging

# Configure the Apify client logger
apify_client_logger = logging.getLogger('apify_client')
apify_client_logger.setLevel(logging.DEBUG)
apify_client_logger.addHandler(logging.StreamHandler())

The log records include additional properties, provided via the extra argument, which can be helpful for debugging. Some of these properties are:

  • attempt - Number of retry attempts for the request.
  • status_code - HTTP status code of the response. Only present on records about a request's outcome.
  • url - URL of the API endpoint being called.
  • client_method - Method name of the client that initiated the request.
  • resource_id - Identifier of the resource being accessed.

To display these additional properties in the log output, you need to use a custom log formatter. Reference only the properties present on every record, since a %-style formatter raises an error for records that lack a referenced property. Here's a basic example:

import logging

# Create a custom logging formatter. Reference only the properties present
# on every record. Properties attached to some records only, such as
# `status_code`, would raise an error for the records that lack them.
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s - '
'%(client_method)s - %(attempt)s - %(url)s'
)

handler = logging.StreamHandler()
handler.setFormatter(formatter)

# Configure the Apify client logger to use the custom formatter
apify_client_logger = logging.getLogger('apify_client')
apify_client_logger.setLevel(logging.DEBUG)
apify_client_logger.addHandler(handler)

For more information on creating and using custom log formatters, refer to the official Python logging documentation.

Redirecting Actor run logs

When you start an Actor with ActorClient.call, the client redirects the run's log to a Python logger while it waits for the run to finish. The same logger also receives the run's status and status message whenever they change. The logger argument controls where the lines go:

  • 'default' (the default) - A built-in redirect logger named after the Actor and the run ID.
  • A logging.Logger - Your own logger receives the lines, so give it a handler and a level that let them through.
  • None - Redirection is turned off.
import logging

from apify_client import ApifyClientAsync

TOKEN = 'MY-APIFY-TOKEN'


async def main() -> None:
apify_client = ApifyClientAsync(TOKEN)
actor_client = apify_client.actor('username/actor-name')

# By default, the run's log and status messages go to a built-in redirect logger.
await actor_client.call()

# Send the run's log and status messages to your own logger.
logging.basicConfig(level=logging.INFO)
my_logger = logging.getLogger('my_actor_run')
await actor_client.call(logger=my_logger)

# Turn the redirection off.
await actor_client.call(logger=None)

For a run started with ActorClient.start, or any other run you have a client for, use RunClient.get_streamed_log to redirect its log and RunClient.get_status_message_watcher to redirect its status messages. Both accept an optional to_logger and work as context managers, or you can call start() and stop() yourself:

from apify_client import ApifyClientAsync

TOKEN = 'MY-APIFY-TOKEN'


async def main() -> None:
apify_client = ApifyClientAsync(TOKEN)
actor_client = apify_client.actor('username/actor-name')

actor_run = await actor_client.start()
run_client = apify_client.run(actor_run.id)

# Use the helpers as context managers to redirect while the run is in progress.
streamed_log = await run_client.get_streamed_log()
status_message_watcher = await run_client.get_status_message_watcher()
async with streamed_log, status_message_watcher:
await run_client.wait_for_finish()

# Or start and stop them yourself.
actor_run = await actor_client.start()
run_client = apify_client.run(actor_run.id)

# With `from_start=False`, only log lines written from now on are redirected.
streamed_log = await run_client.get_streamed_log(from_start=False)
streamed_log.start()
# Do other work while the run's log is redirected.
await streamed_log.stop()