Skip to main content

How to Print Timestamps in Python Logs

Adding timestamps to log messages is crucial for debugging, monitoring, and understanding the sequence of events in your Python applications.

This guide demonstrates how to configure logging to include timestamps, using both the logging.basicConfig() approach and creating custom loggers for more granular control.

Adding Timestamps with logging.basicConfig()

The logging.basicConfig() method provides a quick way to configure logging and add timestamps to log messages.

import logging
import time

logging.basicConfig(
format='%(asctime)s %(levelname)-8s %(message)s',
level=logging.DEBUG,
datefmt='%Y-%m-%d %H:%M:%S'
)

logging.info('Info message #1')
time.sleep(2)
logging.info('Info message #2')
time.sleep(2)
logging.debug('Debug message #1')
time.sleep(2)
logging.error('Error message #1')
time.sleep(2)
logging.warning('Warning message #1')
time.sleep(2)
logging.critical('Critical message #1')

# Example Output:
# 2023-10-27 14:35:40 INFO Info message #1
# 2023-10-27 14:35:42 INFO Info message #2
# 2023-10-27 14:35:44 DEBUG Debug message #1
# 2023-10-27 14:35:46 ERROR Error message #1
# 2023-10-27 14:35:48 WARNING Warning message #1
# 2023-10-27 14:35:50 CRITICAL Critical message #1
  • The logging.basicConfig() method creates a StreamHandler with a default Formatter and adds it to the root logger.
  • format='%(asctime)s %(levelname)-8s %(message)s' specifies the log message format. %(asctime)s includes the timestamp.
  • level=logging.DEBUG sets the logging level to DEBUG, so all messages (DEBUG, INFO, WARNING, ERROR, CRITICAL) are logged. Change this to logging.INFO, logging.WARNING, etc. to control the verbosity.
  • datefmt='%Y-%m-%d %H:%M:%S' sets the format of the timestamp using the strftime directives.

Understanding Format and datefmt

  • format: This string determines the layout of your log messages. Common placeholders include:

    • %(asctime)s: Human-readable time (formatted according to datefmt).
    • %(levelname)s: The logging level (e.g., INFO, DEBUG, ERROR).
    • %(message)s: The log message itself.
    • %(name)s: The logger’s name
    • %(funcName)s: The name of the function
    • You can customize this string to include other information, such as the module name (%(module)s), line number (%(lineno)d), or process ID (%(process)d). See the Python logging documentation for all options.
  • datefmt: This string controls the format of the timestamp. It uses standard strftime directives:

    • %Y: Year with century (e.g., 2023)
    • %m: Month as a zero-padded decimal number (01-12)
    • %d: Day of the month as a zero-padded decimal number (01-31)
    • %H: Hour (24-hour clock) as a zero-padded decimal number (00-23)
    • %M: Minute as a zero-padded decimal number (00-59)
    • %S: Second as a zero-padded decimal number (00-59)
    • Refer to strftime() and strptime() Format Codes

    Example for printing timestamp in DD/MM/YYYY hh:mm:ss format

    import time
    import logging

    logging.basicConfig(
    format='%(asctime)s %(levelname)-8s %(message)s',
    level=logging.DEBUG,
    datefmt='%d/%m/%Y %H:%M:%S',
    force=True
    )

    logging.info('Info message #1')
    time.sleep(2)
    logging.info('Info message #2')
    # Output:
    # 27/10/2023 14:52:37 INFO Info message #1
    # 27/10/2023 14:52:39 INFO Info message #2

Controlling the Log Level

The level argument in basicConfig() determines the minimum severity level of messages that will be logged. Common levels include:

  • logging.DEBUG: Detailed information, typically of interest only when diagnosing problems.
  • logging.INFO: Confirmation that things are working as expected.
  • logging.WARNING: An indication that something unexpected happened, or may happen in the near future (e.g., 'disk space low'). The software is still working as expected.
  • logging.ERROR: Due to a more serious problem, the software has not been able to perform some function.
  • logging.CRITICAL: A very serious error, indicating that the program itself may be unable to continue running.

If you set the level to logging.INFO, DEBUG messages will be ignored:

import logging
logging.basicConfig(
format='%(asctime)s %(levelname)-8s %(message)s',
level=logging.INFO, # Set to INFO level
datefmt='%Y-%m-%d %H:%M:%S',
)

logging.info('Info message #1') # This will be printed
logging.debug('Debug message #1') # This will NOT be printed

Forcing Reconfiguration

By default, basicConfig() only configures the root logger if no handlers are already set. If you need to reconfigure logging (e.g., change the format or level), use the force=True argument:

    import logging
import time
logging.basicConfig(
format='%(asctime)s %(levelname)-8s %(message)s',
level=logging.DEBUG,
datefmt='%Y-%m-%d %H:%M:%S',
force=True # Setting the force parameter to True
)

Adding Timestamps with a Custom Logger

For more fine-grained control, create a custom logger:

import logging
import sys
import time

def create_logger(name):
formatter = logging.Formatter(
fmt='%(asctime)s %(levelname)-8s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)

# Write to a file
file_handler = logging.FileHandler('log_file.txt', mode='w')
file_handler.setFormatter(formatter)

# Also write to the console
stream_handler = logging.StreamHandler(stream=sys.stdout)
stream_handler.setFormatter(formatter)

logger_ = logging.getLogger(name) # Use a unique name
logger_.setLevel(logging.DEBUG) # Set the logger level
logger_.addHandler(file_handler) # Add file handler
logger_.addHandler(stream_handler) # Add console handler

return logger_

logger = create_logger('example-app')

logger.info('Info message #1')
time.sleep(2)
logger.info('Info message #2')

# Example output to console and log_file.txt:
# 2023-10-27 15:12:37 INFO Info message #1
# 2023-10-27 15:12:39 INFO Info message #2
  • This approach creates a custom logger with both a file handler (log_file.txt) and a stream handler (for console output).
  • The Formatter object configures the output format, which is used in the file_handler and stream_handler.
  • You can create multiple loggers with different names, levels, and handlers for different parts of your application.