Logging
The Intapp REST Client includes structured logging for debugging and monitoring.
Default Behavior
By default, the client logs at INFO level:
from intapp_rest_client import RestClient
client = RestClient(
base_url="https://api.example.com",
api_key="your-key"
)
# INFO level logs
data = client.get("/api/resources")
# Output: Request: GET https://api.example.com/api/resources
# Output: Response: 200 (123.4ms)Log Levels
from intapp_rest_client import RestClient, LogLevel
# Debug level - see all details
client = RestClient(
base_url="https://api.example.com",
api_key="your-key",
log_level=LogLevel.DEBUG
)
# Warning level - only warnings and errors
client = RestClient(
base_url="https://api.example.com",
api_key="your-key",
log_level=LogLevel.WARNING
)| Level | Value | Shows |
|---|---|---|
DEBUG | 10 | Everything including headers and bodies |
INFO | 20 | Request/response summary (default) |
WARNING | 30 | Warnings and errors only |
ERROR | 40 | Errors only |
CRITICAL | 50 | Critical errors only |
Log Output
INFO Level
2024-01-15 10:30:45 - intapp_rest_client.RestClient - INFO - Request: GET https://api.example.com/api/resources
2024-01-15 10:30:45 - intapp_rest_client.RestClient - INFO - Response: 200 (123.4ms)DEBUG Level
2024-01-15 10:30:45 - intapp_rest_client.RestClient - INFO - Request: GET https://api.example.com/api/resources
2024-01-15 10:30:45 - intapp_rest_client.RestClient - DEBUG - Request details: RequestLog(timestamp='2024-01-15T10:30:45', method='GET', url='https://api.example.com/api/resources', headers={'Content-Type': 'application/json', 'Authorization': '***MASKED***'}, params=None, body=None, request_id='abc-123')
2024-01-15 10:30:45 - intapp_rest_client.RestClient - INFO - Response: 200 (123.4ms)
2024-01-15 10:30:45 - intapp_rest_client.RestClient - DEBUG - Response details: ResponseLog(timestamp='2024-01-15T10:30:45', status_code=200, headers={...}, body='{"data": [...]}', duration_ms=123.4, request_id='abc-123')Sensitive Data Masking
The client automatically masks sensitive headers:
# These headers are automatically masked in logs:
# - Authorization
# - X-API-Key
# - Api-Key
# - Secret
# - Password
# Log output shows:
# headers={'Authorization': '***MASKED***', 'X-API-Key': '***MASKED***', ...}Request ID Tracking
Each request is assigned a unique ID for tracing:
client = RestClient(
base_url="https://api.example.com",
api_key="your-key",
enable_request_id=True, # Default
request_id_header="X-Request-ID" # Default header name
)Request IDs appear in:
- Request headers sent to the server
- Log entries
- Error messages
Custom Logging Configuration
Using Python's logging module
import logging
# Configure the client's logger
logger = logging.getLogger("intapp_rest_client.RestClient")
logger.setLevel(logging.DEBUG)
# Add a custom handler
handler = logging.FileHandler("api_requests.log")
handler.setFormatter(logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
))
logger.addHandler(handler)Disable Logging
import logging
# Disable client logging entirely
logging.getLogger("intapp_rest_client").setLevel(logging.CRITICAL)JSON Logging
For structured logging in production:
import logging
import json
class JSONFormatter(logging.Formatter):
def format(self, record):
return json.dumps({
"timestamp": self.formatTime(record),
"level": record.levelname,
"logger": record.name,
"message": record.getMessage()
})
logger = logging.getLogger("intapp_rest_client.RestClient")
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logger.addHandler(handler)Request/Response Hooks
For custom logging or metrics:
from intapp_rest_client import RestClient
def log_request(method, url, headers, body):
print(f"→ {method} {url}")
if body:
print(f" Body: {body}")
def log_response(response, duration_ms):
print(f"← {response.status_code} ({duration_ms:.1f}ms)")
client = RestClient(
base_url="https://api.example.com",
api_key="your-key",
pre_request_hook=log_request,
post_response_hook=log_response
)
data = client.get("/api/resources")
# Output:
# → GET https://api.example.com/api/resources
# ← 200 (123.4ms)Metrics Collection
from prometheus_client import Counter, Histogram
REQUEST_COUNT = Counter('api_requests_total', 'Total API requests', ['method', 'status'])
REQUEST_LATENCY = Histogram('api_request_latency_seconds', 'Request latency')
def collect_metrics(response, duration_ms):
REQUEST_COUNT.labels(
method=response.request.method,
status=response.status_code
).inc()
REQUEST_LATENCY.observe(duration_ms / 1000)
client = RestClient(
base_url="https://api.example.com",
api_key="your-key",
post_response_hook=collect_metrics
)💡
Hooks are called even when requests fail, making them reliable for metrics collection.
Best Practices
- Production: Use
INFOlevel for normal operation - Debugging: Switch to
DEBUGtemporarily to diagnose issues - CI/CD: Use
WARNINGor higher to reduce log noise - Sensitive Data: Never log request/response bodies containing PII
Next Steps
- Tracing - OpenTelemetry integration
- Error Handling - Handle and log errors
- Retry Configuration - Retry logging