Logging Customization
Overview
TeaQL logging is designed to be controlled at runtime and enriched by UserContext. The context can provide user identity, tenant, trace ID, request metadata, enabled log markers, and environment-specific policies.
Logging customization is useful when teams need:
- SQL debugging for a single user
- Tenant-aware diagnostics
- Request tracing
- Production-safe log filtering
- Dynamic marker enablement
- Compliance-friendly audit context
For dynamic marker operations, see also the TeaQL debugging and logging guide.
What Can Be Customized
| Area | Examples |
|---|---|
| Log identity | User name, tenant, organization, trace ID |
| Log markers | SQL_SELECT, SQL_UPDATE, HTTP_REQUEST, domain-specific markers |
| Log scope | Global, tenant, user, request, endpoint |
| Sensitive data handling | Mask fields, suppress payloads, deny URLs |
| Output format | Plain text, JSON, structured logs |
| Runtime switches | Enable or disable markers without restart |
Recommended Design
Use CustomUserContext to provide log context:
public class CustomUserContext extends UserContext {
public String traceId() {
return getOrCreateLocalValue("traceId", () -> "T" + System.nanoTime());
}
public String logIdentity() {
return currentUserName() + "@" + currentTenantCode();
}
}
Then make log output consistently include this context:
[traceId] [tenant] [user] [marker] message
Marker-Based Logging
Markers make logs controllable.
Common TeaQL markers include:
SEARCH_REQUEST_STARTSEARCH_REQUEST_ENDSQL_SELECTSQL_UPDATEHTTP_REQUESTHTTP_RESPONSE
Project-specific markers can also be added:
PERMISSION_CHECKCACHE_HITCACHE_MISSAUDIT_WRITELOCK_ACQUIRELOCK_RELEASE
Example:
userContext.debug("SQL_SELECT", "Loading active orders for user {}", userContext.currentUserId());
Adapt this to the actual logging facade used in your runtime.
User-Specific Debugging
Production debugging often needs to inspect one user without increasing logs for everyone.
Recommended policy:
public boolean shouldLogMarker(String marker) {
return logConfiguration().isGlobalMarkerEnabled(marker)
|| logConfiguration().isUserMarkerEnabled(currentUserId(), marker)
|| isCurrentRequestInDebugMode(marker);
}
This lets support teams enable SQL logging for one user or one request.
Sensitive Data Protection
Logging must not expose secrets.
Always mask:
- Passwords
- Tokens
- Authorization headers
- Payment data
- Personally identifiable information when not needed
- Large request bodies
Example masking hook:
public Map<String, Object> sanitizeLogFields(Map<String, Object> fields) {
fields.remove("password");
fields.remove("accessToken");
fields.computeIfPresent("phone", (key, value) -> maskPhone(value.toString()));
return fields;
}
Structured Logs
For production observability, prefer structured fields:
{
"traceId": "T2004754077140779008",
"tenant": "MICROSOFT",
"user": "Alice",
"marker": "SQL_SELECT",
"entity": "EmployeePermission",
"durationMs": 18
}
This format works better with log search systems and metrics dashboards.
Best Practices
- Include trace ID in every log line.
- Use markers instead of ad-hoc log text.
- Keep SQL logging disabled by default in production.
- Enable user-specific logs when debugging real support issues.
- Mask sensitive fields before output.
- Avoid logging full entity graphs unless debugging locally.
- Use
CustomUserContextas the source of tenant, user, and request metadata.
Testing Checklist
- Trace ID is present across request logs.
- SQL markers can be enabled and disabled.
- User-specific logging does not affect other users.
- Sensitive fields are masked.
- Denied URLs are not logged.
- Log output includes tenant and user identity.
Summary
Logging customization should be context-aware. CustomUserContext gives TeaQL logs the missing business context: who made the request, which tenant it belongs to, what trace ID connects the operation, and which markers should be visible.