0% complete

Testing, debugging, and concurrency · Lesson 2 of 3

Debugging, logging, and application configuration

Diagnose failures with tracebacks and structured logs without leaking secrets.

Lesson

1. Concept and mental model

When an exception occurs, read its type and message, then inspect the traceback from the failing line toward the caller. Reproduce the problem with the smallest input that still fails. A debugger can inspect values and step through code, but temporary print statements should not become a substitute for understanding control flow. Remove sensitive values from debugging output before sharing logs.

2. How it works

Use the logging module for operational diagnostics. Log a useful event, severity, and context such as a job identifier; avoid logging passwords, API keys, authorization headers, or unnecessary personal data. Choose levels consistently: debug for details, info for normal milestones, warning for recoverable unexpected conditions, and error for failed operations. Do not catch an exception and log it as success.

3. Use it safely and effectively

Configuration belongs outside source code. Read environment variables or a settings file at the application boundary, validate required values at startup, and provide safe defaults only when they have well-understood behavior. Separate development and production configuration, and never place secrets in a version-controlled example. For difficult incidents, preserve the exact exception chain and safe request identifiers to support diagnosis without exposing confidential data.

4. Syntax reference

import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
logger.info('Import completed', extra={'batch_id': 'batch-42'})

5. Guided walkthrough

Reproduce the problem with a small input, inspect the complete traceback, and add a breakpoint or targeted log at the point where the value changes unexpectedly. Keep configuration outside the code and validate required settings when the application starts.

6. Common mistakes to avoid

  • Logging passwords, API tokens, personal records, or complete request bodies.
  • Replacing useful exception context with a generic message that makes diagnosis harder.

Visual guide

Investigate a failure

  1. Step 01 Observe

    Capture a safe exception and request context.

  2. Step 02 Reproduce

    Reduce the issue to a minimal case.

  3. Step 03 Correct

    Fix the cause and add a regression test.

Code examples

Worked example
PYTHON
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
logger.info('Import completed', extra={'batch_id': 'batch-42'})
Expected output
An informational log event with a safe batch identifier.
Configure a useful log level
PYTHON
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
logger.info('Import job started')
Expected output
INFO:__main__:Import job started
Read required configuration explicitly
PYTHON
import os

api_url = os.environ.get('API_URL')
if not api_url:
    raise RuntimeError('API_URL is required')
print(api_url)
Expected output
Prints the configured URL or raises a clear startup error.

Key points

  • Diagnose failures with tracebacks and structured logs without leaking secrets.
  • Prefer explicit, testable behavior over hidden side effects.
  • Validate assumptions at system boundaries and handle failure deliberately.

Check your understanding

Practice

Which values should never be written to ordinary application logs?

Your learning progress

Finish this lesson