Fluent Syntax
Fluent Syntax
The fluent interface allows you to chain method calls together for expressive, readable logging code. Python's method chaining creates a natural, self-documenting style.
Method Chaining Basics
Chain methods together for elegant code:
from bytehide_logs import Log
# Fluent chaining
Log.with_tags("payment") \
.with_context("transaction_id", "txn_123") \
.with_correlation_id("req_456") \
.info("Payment processed")from bytehide_logs import Log
# Fluent chaining
Log.with_tags("payment") \
.with_context("transaction_id", "txn_123") \
.with_correlation_id("req_456") \
.info("Payment processed")Each method returns the same Log instance, allowing further method calls:
Log.with_tags()- Add tagsLog.with_context()- Add context dataLog.with_correlation_id()- Add correlation ID- Final logging method -
info(),error(),warning(), etc.
Line Continuation with Backslash
Use backslash for line continuation in fluent chains:
Log.with_tags("auth", "login") \
.with_context("user_id", "user_123") \
.with_context("ip_address", "192.168.1.1") \
.with_context("timestamp", "2026-03-02T15:30:00Z") \
.info("User login successful")Log.with_tags("auth", "login") \
.with_context("user_id", "user_123") \
.with_context("ip_address", "192.168.1.1") \
.with_context("timestamp", "2026-03-02T15:30:00Z") \
.info("User login successful")The backslash tells Python the statement continues on the next line. This keeps each method call clear and readable.
Formatting Chain Patterns
Different formatting styles for fluent chains:
Narrow Column Format (for files with width constraints)
Log \
.with_tags("payment") \
.with_context("user_id", "u123") \
.info("Payment complete")Log \
.with_tags("payment") \
.with_context("user_id", "u123") \
.info("Payment complete")Indented Format (most readable)
Log.with_tags("order") \
.with_context("order_id", "ord_456") \
.with_context("total", 99.99) \
.info("Order placed")Log.with_tags("order") \
.with_context("order_id", "ord_456") \
.with_context("total", 99.99) \
.info("Order placed")Compact Format (for simple chains)
Log.with_tags("api").with_context("endpoint", "/users").info("API called")Log.with_tags("api").with_context("endpoint", "/users").info("API called")Building Complex Context
Build rich context through fluent chaining:
Log.with_tags("checkout", "payment", "card") \
.with_context("customer_id", "cust_789") \
.with_context("amount_cents", 2999) \
.with_context("currency", "USD") \
.with_context("card_last_four", "4242") \
.with_correlation_id("checkout_req_123") \
.info("Credit card processed successfully")Log.with_tags("checkout", "payment", "card") \
.with_context("customer_id", "cust_789") \
.with_context("amount_cents", 2999) \
.with_context("currency", "USD") \
.with_context("card_last_four", "4242") \
.with_correlation_id("checkout_req_123") \
.info("Credit card processed successfully")Multiple Tags in Fluent Style
Add multiple tags in a single call:
# All tags in one call
Log.with_tags("user", "profile", "update").info("Profile updated")
# Tags in separate calls (also works)
Log.with_tags("user") \
.with_tags("profile") \
.with_tags("update") \
.info("Profile updated")# All tags in one call
Log.with_tags("user", "profile", "update").info("Profile updated")
# Tags in separate calls (also works)
Log.with_tags("user") \
.with_tags("profile") \
.with_tags("update") \
.info("Profile updated")Error Logging with Fluent Syntax
Build detailed error logs fluently:
Log.with_tags("database", "query", "error") \
.with_context("query_id", "q_abc123") \
.with_context("table", "users") \
.with_context("retry_attempt", 2) \
.with_context("max_retries", 3) \
.error("Database query failed", exception=db_error)Log.with_tags("database", "query", "error") \
.with_context("query_id", "q_abc123") \
.with_context("table", "users") \
.with_context("retry_attempt", 2) \
.with_context("max_retries", 3) \
.error("Database query failed", exception=db_error)Fluent vs Non-Fluent Styles
Both approaches produce identical results:
# Fluent style - expressive chaining
Log.with_tags("auth") \
.with_context("method", "oauth") \
.with_correlation_id("req_xyz") \
.info("OAuth authentication successful")
# Direct style - all at once (if using exception= or context= parameters)
Log.info("OAuth authentication successful", context={
"method": "oauth",
"tags": ["auth"],
"correlation_id": "req_xyz"
})
# Mixed style - some methods, some parameters
Log.with_tags("auth").info("OAuth authentication successful", context={
"method": "oauth"
})# Fluent style - expressive chaining
Log.with_tags("auth") \
.with_context("method", "oauth") \
.with_correlation_id("req_xyz") \
.info("OAuth authentication successful")
# Direct style - all at once (if using exception= or context= parameters)
Log.info("OAuth authentication successful", context={
"method": "oauth",
"tags": ["auth"],
"correlation_id": "req_xyz"
})
# Mixed style - some methods, some parameters
Log.with_tags("auth").info("OAuth authentication successful", context={
"method": "oauth"
})Choose the style that fits your code. The fluent style is often preferred for:
- Long chains with many attributes
- Progressive building of log entries
- Readability in complex operations
Fluent Syntax in Functions
Write helper functions using fluent syntax:
from bytehide_logs import Log
def log_payment_event(event_type, transaction_id, amount, status="pending"):
"""Log payment events with fluent syntax."""
return Log.with_tags("payment", event_type) \
.with_context("transaction_id", transaction_id) \
.with_context("amount_cents", amount) \
.with_context("status", status) \
.with_correlation_id(get_current_correlation_id())
# Usage
log_payment_event("charge", "txn_123", 5999).info("Payment initiated")
log_payment_event("charge", "txn_123", 5999).info("Payment completed")
log_payment_event("refund", "txn_123", 5999).warning("Payment refunded")from bytehide_logs import Log
def log_payment_event(event_type, transaction_id, amount, status="pending"):
"""Log payment events with fluent syntax."""
return Log.with_tags("payment", event_type) \
.with_context("transaction_id", transaction_id) \
.with_context("amount_cents", amount) \
.with_context("status", status) \
.with_correlation_id(get_current_correlation_id())
# Usage
log_payment_event("charge", "txn_123", 5999).info("Payment initiated")
log_payment_event("charge", "txn_123", 5999).info("Payment completed")
log_payment_event("refund", "txn_123", 5999).warning("Payment refunded")Conditional Fluent Chains
Build chains conditionally:
from bytehide_logs import Log
def log_user_action(action, user, **metadata):
"""Log user action with optional context."""
log_entry = Log.with_tags("user", action)
# Add user context if authenticated
if user:
log_entry = log_entry.with_context("user_id", user.id)
if hasattr(user, "email"):
log_entry = log_entry.with_context("email", user.email)
# Add optional metadata
for key, value in metadata.items():
log_entry = log_entry.with_context(key, value)
return log_entry
# Usage
user = get_current_user()
log_user_action("login", user, ip="192.168.1.1").info("User logged in")
log_user_action("logout", user).info("User logged out")from bytehide_logs import Log
def log_user_action(action, user, **metadata):
"""Log user action with optional context."""
log_entry = Log.with_tags("user", action)
# Add user context if authenticated
if user:
log_entry = log_entry.with_context("user_id", user.id)
if hasattr(user, "email"):
log_entry = log_entry.with_context("email", user.email)
# Add optional metadata
for key, value in metadata.items():
log_entry = log_entry.with_context(key, value)
return log_entry
# Usage
user = get_current_user()
log_user_action("login", user, ip="192.168.1.1").info("User logged in")
log_user_action("logout", user).info("User logged out")Fluent Syntax with Context Manager
Combine fluent syntax with Python's context managers:
from contextlib import contextmanager
from bytehide_logs import Log
import time
@contextmanager
def log_operation(operation_name, **tags):
"""Log operation start and completion with timing."""
log = Log.with_tags(operation_name, *tags.keys()) \
.with_context("operation", operation_name)
for key, value in tags.items():
log = log.with_context(key, value)
log.info("Operation started")
start_time = time.time()
try:
yield log
finally:
elapsed = time.time() - start_time
log.with_context("elapsed_ms", int(elapsed * 1000)).info("Operation completed")
# Usage
with log_operation("data_import", source="csv", count=1000) as log:
import_data_from_csv()from contextlib import contextmanager
from bytehide_logs import Log
import time
@contextmanager
def log_operation(operation_name, **tags):
"""Log operation start and completion with timing."""
log = Log.with_tags(operation_name, *tags.keys()) \
.with_context("operation", operation_name)
for key, value in tags.items():
log = log.with_context(key, value)
log.info("Operation started")
start_time = time.time()
try:
yield log
finally:
elapsed = time.time() - start_time
log.with_context("elapsed_ms", int(elapsed * 1000)).info("Operation completed")
# Usage
with log_operation("data_import", source="csv", count=1000) as log:
import_data_from_csv()Fluent Syntax with Exceptions
Chain methods while logging exceptions:
from bytehide_logs import Log
try:
risky_operation()
except PaymentError as e:
Log.with_tags("payment", "error") \
.with_context("error_code", e.code) \
.with_context("retry_available", e.retry_available) \
.with_correlation_id(get_correlation_id()) \
.error("Payment processing failed", exception=e)
except Exception as e:
Log.with_tags("error", "unexpected") \
.with_context("error_type", type(e).__name__) \
.error("Unexpected error occurred", exception=e)from bytehide_logs import Log
try:
risky_operation()
except PaymentError as e:
Log.with_tags("payment", "error") \
.with_context("error_code", e.code) \
.with_context("retry_available", e.retry_available) \
.with_correlation_id(get_correlation_id()) \
.error("Payment processing failed", exception=e)
except Exception as e:
Log.with_tags("error", "unexpected") \
.with_context("error_type", type(e).__name__) \
.error("Unexpected error occurred", exception=e)Fluent Syntax in Loops
Log repetitive operations fluently:
from bytehide_logs import Log
for item in items:
try:
result = process_item(item)
Log.with_tags("batch", "item") \
.with_context("item_id", item.id) \
.with_context("batch_id", batch_id) \
.with_context("result", result) \
.info("Item processed successfully")
except Exception as e:
Log.with_tags("batch", "item", "error") \
.with_context("item_id", item.id) \
.with_context("batch_id", batch_id) \
.error("Item processing failed", exception=e)from bytehide_logs import Log
for item in items:
try:
result = process_item(item)
Log.with_tags("batch", "item") \
.with_context("item_id", item.id) \
.with_context("batch_id", batch_id) \
.with_context("result", result) \
.info("Item processed successfully")
except Exception as e:
Log.with_tags("batch", "item", "error") \
.with_context("item_id", item.id) \
.with_context("batch_id", batch_id) \
.error("Item processing failed", exception=e)Formatting Guidelines
For consistent fluent syntax formatting:
Use backslash continuation for clarity:
# Good - clear method order
Log.with_tags("operation") \
.with_context("key", value) \
.with_correlation_id("id") \
.info("Message")# Good - clear method order
Log.with_tags("operation") \
.with_context("key", value) \
.with_correlation_id("id") \
.info("Message")Keep lines within reasonable width (80-100 characters):
# Good - readable line length
Log.with_tags("auth") \
.with_context("user_id", user_id) \
.info("Authentication successful")
# Avoid - very long single line
Log.with_tags("auth").with_context("user_id", user_id).with_context("auth_method", "oauth").with_context("timestamp", current_time).info("Authentication successful")# Good - readable line length
Log.with_tags("auth") \
.with_context("user_id", user_id) \
.info("Authentication successful")
# Avoid - very long single line
Log.with_tags("auth").with_context("user_id", user_id).with_context("auth_method", "oauth").with_context("timestamp", current_time).info("Authentication successful")Align continuations for readability:
# Good - aligned indentation
Log.with_tags("payment", "stripe") \
.with_context("amount", 9999) \
.with_context("currency", "USD") \
.info("Charge created")# Good - aligned indentation
Log.with_tags("payment", "stripe") \
.with_context("amount", 9999) \
.with_context("currency", "USD") \
.info("Charge created")Complete Example
from bytehide_logs import Log, LogSettings, AuthUser
from datetime import timedelta
import uuid
# Configure logging
settings = LogSettings(
duplicate_suppression_window=timedelta(seconds=5),
mask_sensitive_data=["password", "token", "api_key"]
)
Log.configure(settings)
def process_user_order(order_id, user_email, payment_token):
"""Process user order with fluent logging."""
# Generate tracking IDs
correlation_id = str(uuid.uuid4())
user = AuthUser(id=order_id, email=user_email, token=payment_token)
# Identify user
Log.identify(user)
# Log order start
Log.with_tags("order", "processing") \
.with_context("order_id", order_id) \
.with_context("user_email", user_email) \
.with_correlation_id(correlation_id) \
.info("Order processing initiated")
try:
# Validate order
Log.with_tags("order", "validation") \
.with_context("order_id", order_id) \
.with_correlation_id(correlation_id) \
.info("Validating order details")
validate_order(order_id)
# Process payment
Log.with_tags("order", "payment", "stripe") \
.with_context("order_id", order_id) \
.with_context("amount_cents", get_order_total(order_id)) \
.with_correlation_id(correlation_id) \
.info("Processing payment with Stripe")
payment_result = process_stripe_payment(order_id)
# Create shipment
Log.with_tags("order", "fulfillment") \
.with_context("order_id", order_id) \
.with_context("transaction_id", payment_result.id) \
.with_correlation_id(correlation_id) \
.info("Creating shipment")
shipment = create_shipment(order_id)
# Success
Log.with_tags("order", "complete") \
.with_context("order_id", order_id) \
.with_context("shipment_id", shipment.id) \
.with_context("transaction_id", payment_result.id) \
.with_correlation_id(correlation_id) \
.info("Order processed successfully")
return shipment
except Exception as e:
Log.with_tags("order", "error") \
.with_context("order_id", order_id) \
.with_context("error_message", str(e)) \
.with_correlation_id(correlation_id) \
.error("Order processing failed", exception=e)
raise
finally:
Log.logout()
# Usage
try:
shipment = process_user_order("ord_123", "user@example.com", "token_xyz")
except Exception as e:
print(f"Order processing failed: {e}")from bytehide_logs import Log, LogSettings, AuthUser
from datetime import timedelta
import uuid
# Configure logging
settings = LogSettings(
duplicate_suppression_window=timedelta(seconds=5),
mask_sensitive_data=["password", "token", "api_key"]
)
Log.configure(settings)
def process_user_order(order_id, user_email, payment_token):
"""Process user order with fluent logging."""
# Generate tracking IDs
correlation_id = str(uuid.uuid4())
user = AuthUser(id=order_id, email=user_email, token=payment_token)
# Identify user
Log.identify(user)
# Log order start
Log.with_tags("order", "processing") \
.with_context("order_id", order_id) \
.with_context("user_email", user_email) \
.with_correlation_id(correlation_id) \
.info("Order processing initiated")
try:
# Validate order
Log.with_tags("order", "validation") \
.with_context("order_id", order_id) \
.with_correlation_id(correlation_id) \
.info("Validating order details")
validate_order(order_id)
# Process payment
Log.with_tags("order", "payment", "stripe") \
.with_context("order_id", order_id) \
.with_context("amount_cents", get_order_total(order_id)) \
.with_correlation_id(correlation_id) \
.info("Processing payment with Stripe")
payment_result = process_stripe_payment(order_id)
# Create shipment
Log.with_tags("order", "fulfillment") \
.with_context("order_id", order_id) \
.with_context("transaction_id", payment_result.id) \
.with_correlation_id(correlation_id) \
.info("Creating shipment")
shipment = create_shipment(order_id)
# Success
Log.with_tags("order", "complete") \
.with_context("order_id", order_id) \
.with_context("shipment_id", shipment.id) \
.with_context("transaction_id", payment_result.id) \
.with_correlation_id(correlation_id) \
.info("Order processed successfully")
return shipment
except Exception as e:
Log.with_tags("order", "error") \
.with_context("order_id", order_id) \
.with_context("error_message", str(e)) \
.with_correlation_id(correlation_id) \
.error("Order processing failed", exception=e)
raise
finally:
Log.logout()
# Usage
try:
shipment = process_user_order("ord_123", "user@example.com", "token_xyz")
except Exception as e:
print(f"Order processing failed: {e}")Next Steps
- Learn about basic logging for foundational concepts
- Explore tags for effective categorization
- Discover metadata context for rich information