Skip to content

Logging

Gaurav Sharma edited this page Oct 16, 2025 · 3 revisions

This guide explains how to enable logging in the mssql-python driver to diagnose issues, monitor driver behavior, and troubleshoot database operations.


Overview

The mssql-python driver includes a built-in logging system that captures detailed diagnostic information from both the Python layer and the underlying DDBC (Direct Database Connectivity) engine. Logging is disabled by default and can be easily enabled when needed.

Key Benefits

  • Comprehensive Diagnostics: Capture detailed information from both Python and C++ layers
  • Simple Configuration: Just enable or disable - no complex log level settings to worry about
  • Flexible Output: Log to file or console (stdout)
  • Automatic File Management: Built-in log rotation prevents disk space issues
  • Organized Storage: Logs stored in package directory with timestamped filenames
  • Privacy & Security: Automatic sanitization of passwords and sensitive credentials
  • Minimal Performance Impact: Disabled by default, minimal overhead when enabled
  • Cross-Platform Support: Works consistently on Windows, macOS, and Linux

Quick Start

Enable File Logging (Default)

By default, logging writes to a file in the package installation directory:

import mssql_python

# Enable logging (writes to file only)
mssql_python.setup_logging()

# Your database operations
connection = mssql_python.connect("Server=localhost;Database=mydb;UID=user;PWD=password;...")
cursor = connection.cursor()
cursor.execute("SELECT * FROM users")

Enable Console Logging

To see log output in real-time on your console:

import mssql_python

# Enable logging to console (stdout)
mssql_python.setup_logging('stdout')

# Your database operations
connection = mssql_python.connect("Server=localhost;Database=mydb;...")

Logging Modes

The setup_logging() function accepts a single parameter for output destination:

mssql_python.setup_logging(mode='file')   # Default: log to file only
mssql_python.setup_logging('stdout')       # Log to console

Mode Options

Mode Description Use Case
'file' Logs written to file only (default) Production, persistent logging
'stdout' Logs written to console Development, real-time debugging, CI/CD

File Mode (Default)

Logs are written exclusively to a file in the package directory.

import mssql_python

# Explicitly specify file mode (this is the default)
mssql_python.setup_logging()
# or
mssql_python.setup_logging('file')

When to use:

  • Production environments where you need persistent logs
  • When analyzing issues after they occur
  • When you want minimal console clutter
  • Long-running applications that need historical logs

Stdout Mode

Logs are written to the console output for real-time monitoring.

import mssql_python

# Enable console output
mssql_python.setup_logging('stdout')

When to use:

  • Development and debugging
  • Real-time monitoring of driver behavior
  • Interactive testing and troubleshooting
  • CI/CD pipelines where console output is captured
  • When you want immediate feedback

Log File Location

Package Installation Directory

Log files are automatically stored in the logs/ subdirectory within the mssql_python package installation:

<python-site-packages>/mssql_python/
├── __init__.py
├── connection.py
├── cursor.py
├── ...
└── logs/
    ├── mssql_python_trace_20251015_143022_12345.log
    ├── mssql_python_trace_20251015_143022_12345.log.1
    └── mssql_python_trace_20251015_143022_12345.log.2

Finding Your Logs

To find where logs are stored on your system:

import mssql_python
from mssql_python.logging_config import LoggingManager
import os

# Enable logging
mssql_python.setup_logging()

# Get the log directory location
manager = LoggingManager()
if manager.enabled:
    log_dir = os.path.dirname(manager.log_file)
    print(f"Logs are stored in: {log_dir}")
    print(f"Current log file: {manager.log_file}")

Typical locations by platform:

  • Linux: /usr/local/lib/python3.x/site-packages/mssql_python/logs/
  • macOS: /Library/Frameworks/Python.framework/Versions/3.x/lib/python3.x/site-packages/mssql_python/logs/
  • Windows: C:\Python3x\Lib\site-packages\mssql_python\logs\
  • Virtual Environment: <venv>/lib/python3.x/site-packages/mssql_python/logs/

File Naming Convention

Log files use timestamped names for easy identification:

mssql_python_trace_YYYYMMDD_HHMMSS_PID.log

Components:

  • YYYYMMDD: Date (e.g., 20251015 for October 15, 2025)
  • HHMMSS: Time (e.g., 143022 for 2:30:22 PM)
  • PID: Process ID (e.g., 12345)

This ensures unique filenames for each execution and chronological sorting.

Automatic Log Rotation

To prevent log files from consuming excessive disk space, the driver implements automatic log rotation:

Property Value Description
Maximum File Size 512 MB When a log file reaches 512 MB, it's rotated
Backup Count 5 Keep up to 5 rotated backup files
Total Maximum Size ~3 GB 512 MB × (1 active + 5 backups)

How it works:

  1. Active log file: mssql_python_trace_20251015_143022_12345.log
  2. When it reaches 512 MB, it's renamed to .log.1
  3. A new active log file is created
  4. Older backups are shifted: .log.1.log.2, .log.2.log.3, etc.
  5. The oldest backup (.log.5) is deleted automatically

Log Format and Content

Log Entry Format

Each log entry follows this format:

YYYY-MM-DD HH:MM:SS,mmm - LEVEL - filename.py - [Layer] Message

Example:

2025-10-15 14:30:22,145 - INFO - connection.py - [Python Layer log] Connecting to server: localhost
2025-10-15 14:30:22,156 - DEBUG - connection.py - [DDBC Bindings log] Connection handle allocated

Log Layers

The driver distinguishes between two layers:

1. Python Layer Logs

Messages from the Python code (connection management, query execution, error handling):

[Python Layer log] Executing query: SELECT * FROM users
[Python Layer log] Connection closed successfully
[Python Layer log] Cursor created for statement execution

2. DDBC Bindings Logs

Messages from the underlying C++ DDBC engine (low-level operations, TDS protocol, memory management):

[DDBC Bindings log] Allocating statement handle
[DDBC Bindings log] Binding parameter 1: type=SQL_VARCHAR, size=50
[DDBC Bindings log] SQLExecDirect completed, rows affected: 42

Sample Log Output

2025-10-15 14:30:22,145 - INFO - db_connection.py - [Python Layer log] Initializing connection
2025-10-15 14:30:22,147 - INFO - db_connection.py - [Python Layer log] Final connection string: Server=localhost;Database=mydb;UID=admin;PWD=***;
2025-10-15 14:30:22,150 - DEBUG - connection.py - [DDBC Bindings log] SQLAllocHandle(SQL_HANDLE_DBC) called
2025-10-15 14:30:22,152 - INFO - connection.py - [DDBC Bindings log] Connection established successfully
2025-10-15 14:30:22,155 - DEBUG - cursor.py - [Python Layer log] Creating cursor object
2025-10-15 14:30:22,157 - DEBUG - cursor.py - [DDBC Bindings log] SQLAllocHandle(SQL_HANDLE_STMT) called
2025-10-15 14:30:22,160 - INFO - cursor.py - [Python Layer log] Executing SQL: SELECT * FROM users WHERE active = 1
2025-10-15 14:30:22,175 - DEBUG - cursor.py - [DDBC Bindings log] SQLExecDirect completed, rows affected: 42
2025-10-15 14:30:22,180 - INFO - cursor.py - [Python Layer log] Query executed successfully
2025-10-15 14:30:22,185 - DEBUG - cursor.py - [Python Layer log] Fetching 42 rows
2025-10-15 14:30:22,190 - INFO - cursor.py - [Python Layer log] Fetch completed

Privacy & Security

Automatic Credential Sanitization

The mssql-python driver automatically sanitizes all sensitive information before writing to logs. You can safely enable logging without worrying about credential exposure.

What Gets Sanitized

The driver automatically removes or masks the following from logs:

Item How It's Sanitized Example
Passwords (PWD=) Replaced with *** PWD=secret123PWD=***
User IDs in auth contexts Removed from sensitive operations Authentication params filtered
Access Tokens Never logged Token values are not written to logs
Client Secrets Never logged Service principal secrets are not written

Example of Sanitized Logging

Your Code:

import mssql_python

mssql_python.setup_logging()

connection_string = (
    "Server=myserver.database.windows.net;"
    "Database=mydb;"
    "[email protected];"
    "PWD=SuperSecret123!;"
    "Encrypt=yes;"
)

conn = mssql_python.connect(connection_string)

What Gets Logged:

2025-10-15 14:30:22,147 - INFO - connection.py - [Python Layer log] Final connection string: Server=myserver.database.windows.net;Database=mydb;[email protected];PWD=***;Encrypt=yes;

Notice how PWD=SuperSecret123! becomes PWD=*** automatically.

Safe to Share Logs

Logs are safe to share with support teams - Passwords and secrets are automatically redacted
No manual redaction required - The driver handles it for you
SQL queries are logged - To help with troubleshooting (ensure queries don't contain secrets)

Best Practices for Privacy

While the driver sanitizes credentials, follow these best practices:

  1. Review SQL queries: If your queries contain sensitive data (like SSNs or credit cards), be cautious when sharing logs
  2. Don't hardcode credentials: Use environment variables or secure credential stores
  3. Limit log sharing: Only share relevant portions of logs when reporting issues

Common Use Cases

1. Debugging Connection Issues

import mssql_python

# Enable console logging to see connection diagnostics in real-time
mssql_python.setup_logging('stdout')

try:
    connection = mssql_python.connect(
        "Server=myserver.database.windows.net;"
        "Database=mydb;"
        "Authentication=ActiveDirectoryInteractive;"
        "Encrypt=yes;"
    )
    print("Connection successful!")
except Exception as e:
    print(f"Connection failed: {e}")
    # Check the console output or log file for detailed diagnostic information

2. Production Monitoring

import mssql_python

# Production: Log to file for persistent diagnostics
mssql_python.setup_logging('file')

# Application logic
connection = mssql_python.connect(connection_string)
# ... your database operations ...
# Logs are automatically written to the package directory

3. Development and Testing

import mssql_python

# Development: Use stdout for immediate feedback
mssql_python.setup_logging('stdout')

connection = mssql_python.connect(connection_string)
cursor = connection.cursor()
cursor.execute("SELECT * FROM users")
rows = cursor.fetchall()
print(f"Fetched {len(rows)} rows")
# Watch the console for detailed operation logs

4. CI/CD Pipeline Diagnostics

import mssql_python
import sys

# In CI/CD, log to stdout so it's captured in build logs
mssql_python.setup_logging('stdout')

try:
    connection = mssql_python.connect(connection_string)
    cursor = connection.cursor()
    cursor.execute("SELECT 1")
    print("✅ Database connectivity test: PASSED")
    sys.exit(0)
except Exception as e:
    print(f"❌ Database connectivity test: FAILED - {e}")
    sys.exit(1)

5. Troubleshooting Specific Operations

import mssql_python

# Regular operations without logging
connection = mssql_python.connect("Server=localhost;...")

# Enable logging when you need to diagnose an issue
mssql_python.setup_logging('stdout')

# This operation will be logged
cursor = connection.cursor()
cursor.execute("SELECT * FROM problematic_table")
rows = cursor.fetchall()

# Note: Logging remains enabled for the rest of the session

Best Practices

✅ Do's

  1. Enable logging when developing or debugging

    mssql_python.setup_logging('stdout')
  2. Use file mode for production environments

    mssql_python.setup_logging('file')
  3. Call setup_logging() early in your application

    import mssql_python
    
    # Call this before any database operations
    mssql_python.setup_logging()
    
    # Now proceed with your application
  4. Enable logging when reporting issues

    • Include relevant log excerpts in bug reports
    • Logs are already sanitized, but review SQL queries if they contain sensitive data
  5. Monitor disk space in long-running applications

    • The automatic rotation handles this (max ~3GB)
    • Be aware of the storage location in your package directory

❌ Don'ts

  1. Don't leave logging enabled in production unless needed

    • Can generate large log files over time
    • May have minor performance impact
    • Enable only when troubleshooting
  2. Don't ignore log rotation

    • With 5 backups at 512MB each, you're using ~3GB in the package directory
    • Plan disk space accordingly
  3. Don't assume logs need manual redaction

    • Passwords are automatically masked
    • But review SQL queries if they contain sensitive business data
  4. Don't call setup_logging() multiple times unnecessarily

    • The logger uses a singleton pattern
    • Once enabled, it stays enabled for the session
  5. Don't forget where logs are stored

    • They're in the package installation directory, not your application directory
    • Use the helper code above to find the exact location

Troubleshooting

Issue: Logs are not being generated

Solution:

# Verify logging is enabled
from mssql_python.logging_config import LoggingManager

manager = LoggingManager()
print(f"Logging enabled: {manager.enabled}")
print(f"Log file: {manager.log_file}")

# If not enabled, call setup_logging()
import mssql_python
mssql_python.setup_logging()

Issue: Can't find log files

Solution:

import mssql_python
from mssql_python.logging_config import LoggingManager
import os

# Enable logging first
mssql_python.setup_logging()

# Get the exact path
manager = LoggingManager()
log_dir = os.path.dirname(manager.log_file)
print(f"📁 Log directory: {log_dir}")
print(f"📄 Current log file: {manager.log_file}")

# List all log files
import glob
log_files = glob.glob(os.path.join(log_dir, "mssql_python_trace_*.log*"))
print(f"\n📋 Found {len(log_files)} log file(s):")
for f in sorted(log_files):
    size_mb = os.path.getsize(f) / (1024 * 1024)
    print(f"  - {os.path.basename(f)} ({size_mb:.2f} MB)")

Issue: Permission errors when writing logs

Possible Causes:

  • Package installed in system directory without write permissions
  • Virtual environment has restricted permissions

Solution:

# If using system Python, consider using a virtual environment
python -m venv myenv
source myenv/bin/activate  # On Windows: myenv\Scripts\activate
pip install mssql-python

# Or install with user flag
pip install --user mssql-python

Issue: Want to see logs immediately without checking files

Solution:

import mssql_python

# Use stdout mode for real-time output
mssql_python.setup_logging('stdout')

# All operations will now print logs to console

Issue: Need to copy logs to a different location

Solution:

import mssql_python
from mssql_python.logging_config import LoggingManager
import shutil
import os

# Enable logging
mssql_python.setup_logging()

# Do your operations
connection = mssql_python.connect(connection_string)
# ... database operations ...
connection.close()

# Copy log file to desired location
manager = LoggingManager()
source_log = manager.log_file
destination = "/my/custom/path/app_logs/mssql_debug.log"

os.makedirs(os.path.dirname(destination), exist_ok=True)
shutil.copy2(source_log, destination)
print(f"Log copied to: {destination}")

Performance Considerations

Impact on Performance

Enabling logging has minimal performance impact for most applications:

Scenario Performance Impact
Logging disabled 0% (no overhead)
Logging enabled < 5% for typical workloads
High-throughput applications 5-10% in extreme cases

Recommendations

  1. Development: Always enable logging with 'stdout' for immediate feedback
  2. Testing/Staging: Enable logging with 'file' for diagnostics
  3. Production:
    • Disable logging for normal operations
    • Enable temporarily when investigating issues
    • Use 'file' mode if you need persistent production logging
  4. High-Performance Applications: Only enable logging when actively troubleshooting

Frequently Asked Questions

Q: Is logging enabled by default?

A: No. Logging is disabled by default to minimize performance impact. You must explicitly call setup_logging() to enable it.

Q: Can I disable logging after enabling it?

A: The driver doesn't provide a disable method by design. Logging remains active once enabled for the session. The recommended approach is to enable it only when needed, or restart your application to disable it.

Q: Are passwords exposed in logs?

A: No. The driver automatically sanitizes passwords and sensitive credentials before writing to logs. Passwords are replaced with *** and access tokens are never logged.

Q: Can I share log files with support teams?

A: Yes! Log files are safe to share. Credentials are automatically redacted. Just review SQL queries if they contain sensitive business data (like SSNs, credit cards, etc.).

Q: What's the difference between 'file' and 'stdout' modes?

A:

  • 'file': Logs written to file in package directory (silent console)
  • 'stdout': Logs written to console for real-time monitoring

Q: Where exactly are the log files stored?

A: Logs are stored in the logs/ subdirectory of the mssql_python package installation. Use the code snippet in the "Finding Your Logs" section to get the exact path on your system.

Q: Can I change the log file location?

A: Not directly. The driver stores logs in its package directory by design. However, you can copy or symlink the log files to another location after they're created.

Q: Do I need to worry about log levels?

A: No! The driver captures all relevant diagnostic information automatically when you enable logging. You don't need to configure log levels - just turn logging on or off.

Q: How do I get just the Python layer logs or just the DDBC logs?

A: You can parse the log file and filter by the prefix:

with open(log_file, 'r') as f:
    for line in f:
        if '[Python Layer log]' in line:
            print(line)  # Python layer only
        # or
        if '[DDBC Bindings log]' in line:
            print(line)  # DDBC layer only

Q: What happens when log files reach the rotation limit?

A: The oldest backup (.log.5) is automatically deleted, and newer files are shifted. This ensures you never exceed approximately 3GB of log storage in the package directory.

Q: Can I use logging in a multi-threaded application?

A: Yes! The logging system is thread-safe. Each thread's operations will be logged with proper synchronization.


Getting Help

If you encounter issues with logging or need assistance:

  1. Check the logs - Log files often contain detailed error information
  2. Consult the FAQ - See above for common questions
  3. GitHub Issues - Create an issue at github.com/microsoft/mssql-python/issues
  4. Email Support - Contact the mssql-python team

When reporting issues, please include:

  • Log file excerpts (credentials are already sanitized!)
  • Driver version: pip show mssql-python
  • Python version: python --version
  • Operating system and version
  • Database server type (SQL Server, Azure SQL, etc.)
  • Log file location on your system

Summary

The mssql-python driver's logging system is designed for simplicity and security:

Simple to use: Just call setup_logging() or setup_logging('stdout')
No complex configuration: No log levels to worry about
Two output modes: File (persistent) or stdout (real-time)
Automatic management: Log rotation prevents disk issues
Privacy-first: Passwords and secrets automatically sanitized
Package directory storage: Logs stored with the mssql_python package installation
Minimal overhead: Negligible performance impact for most applications
Developer-friendly: Detailed diagnostics for troubleshooting

Quick Start:

import mssql_python

# For development/debugging (real-time console output)
mssql_python.setup_logging('stdout')

# For production (persistent file logging)
mssql_python.setup_logging()  # or setup_logging('file')
Clone this wiki locally