Chenile external API logging captures request and response records at third-party integration boundaries and publishes them through Chenile Pub/Sub when configured.
The feature is intentionally selective. Normal Chenile logging can continue for all requests, but external API Pub/Sub publication happens only when the request is explicitly marked external or when the outbound call uses Chenile’s external client wrapper.
External Boundaries
Chenile recognizes two external directions:
| Direction | Boundary | Trigger |
|---|---|---|
| Inbound | Third-party client calls a Chenile HTTP API | @ExternalApi on the Chenile controller class or operation method |
| Outbound | Chenile service calls a third-party HTTP server | ChenileExternalClient.exchange(...) |
Chenile proxy calls are not considered outbound external API calls. The proxy framework is for Chenile-to-Chenile communication and location transparency. Third-party HTTP calls should use ChenileExternalClient.
Components
| Component | Module | Responsibility |
|---|---|---|
@ExternalApi |
chenile-core |
Marks an inbound controller or operation as third-party facing |
ExternalApiMetadata |
chenile-core |
Reads external metadata from the current ChenileExchange |
LogOutput |
chenile-core |
Builds inbound LogRecord and publishes external records when metadata exists |
ChenileExternalClient |
chenile-core |
Wraps outbound third-party HTTP calls and captures request/response/error details |
ExternalApiLogSupport |
chenile-core |
Applies common fields, masks headers, serializes and truncates payloads |
ExternalApiProperties |
chenile-core |
Holds enabled flag, topics, payload size, and masked header settings |
ExternalApiPublisher |
chenile-core |
Publisher extension point |
NoopExternalApiPublisher |
chenile-core |
Default publisher when publication is disabled or not configured |
PubSubExternalApiPublisher |
chenile-pub-sub |
Publishes serialized records to Chenile Pub/Sub topics |
Configuration
Core properties:
chenile.external-api.logging.enabled=true
chenile.external-api.logging.publisher=pubsub
chenile.external-api.logging.inbound-topic=external.api.inbound
chenile.external-api.logging.outbound-topic=external.api.outbound
chenile.external-api.logging.max-payload-bytes=65536
chenile.external-api.logging.masked-headers=Authorization,x-Authorization
Configuration behavior:
| Property | Default | Meaning |
|---|---|---|
enabled |
true |
Enables capture and publish attempts |
publisher |
none |
Selects no-op or Pub/Sub publisher |
inbound-topic |
empty | Topic used for inbound external records |
outbound-topic |
empty | Topic used for outbound external records |
max-payload-bytes |
65536 |
Payload truncation limit |
masked-headers |
Authorization,x-Authorization |
Headers replaced with **** |
Publisher selection:
- Core creates
NoopExternalApiPublisherwhen no otherExternalApiPublisherbean exists andpublisher=noneor the property is absent. chenile-pub-subcreatesPubSubExternalApiPublisherwhenpublisher=pubsub,ExternalApiPropertiesexists, and the Pub/Sub module is loaded.- Applications can provide their own
ExternalApiPublisherbean for custom destinations.
If a topic is blank, the Pub/Sub publisher returns without publishing. If ChenilePub is not available, it also returns without failing the request.
Log Record Schema
External API records use org.chenile.core.context.LogRecord.
| Field | Description |
|---|---|
direction |
INBOUND or OUTBOUND |
external |
Always true for external records |
externalSystem |
Third-party system or client name |
externalOperation |
External operation name |
serviceName / operationName |
Chenile service and operation for inbound requests |
protocol |
HTTP for outbound calls; inbound uses the entry point header |
target |
Outbound URL |
httpMethod |
Outbound HTTP method |
httpStatusCode |
HTTP response status when available |
durationMillis |
Execution time in milliseconds |
timestamp |
Record creation timestamp |
requestId |
x-request-id |
correlationId |
x-correlation-id, or request ID when absent |
requestPayload |
Serialized request payload after truncation |
responsePayload |
Serialized response payload after truncation |
errorCode / errorMessage |
Error metadata when available |
headers |
Headers with configured masking |
Inbound Chain
Inbound external logging is part of the normal Chenile last-mile interceptor chain.
Sequence:
- A third-party client invokes a Spring MVC controller.
- The controller delegates to Chenile through
ControllerSupport.process(...). - Chenile builds
ChenileExchangewith service, operation, headers, body, and entry point metadata. - The configured core interceptors execute.
- The target service method executes.
- Response or exception information is stored on the exchange.
LogOutput.doPostProcessing(...)creates the normalLogRecord.LogOutputchecksExternalApiMetadata.from(exchange).- If no
@ExternalApimetadata exists, no external Pub/Sub record is published. - If metadata exists and logging is enabled,
ExternalApiLogSupportenriches the record. ExternalApiPublisher.publish(record)is called.- Publication failures are caught and logged as warnings.
- The HTTP response continues back to the caller.
Request and response capture:
| Point | Captured data |
|---|---|
| Before service invocation | Start time is stored in an exchange header |
| After service invocation | Success flag, response, response messages, status, exception, duration |
| External enrichment | External system, external operation, request payload, response payload, request ID, correlation ID, masked headers |
Outbound Chain
Outbound external logging is not in the inbound interceptor chain. It is captured inside ChenileExternalClient.
Sequence:
- A Chenile service decides to call a third-party HTTP system.
- The service builds
ExternalApiRequest. - The service calls
ChenileExternalClient.exchange(request). - The client copies request headers and propagates
x-request-idandx-correlation-idfromContextContainerwhen absent. - The client builds a base outbound
LogRecord. RestTemplate.exchange(...)sends the HTTP request.- On success, status, success flag, response payload, and duration are captured.
- On
RestClientResponseException, HTTP status, response body, error details, and duration are captured. - On other
RestClientException, error details and duration are captured. - The record is published if logging is enabled.
- The response body is converted to the requested response type, or the original exception is rethrown.
Request and response capture:
| Point | Captured data |
|---|---|
| Before HTTP call | External system, operation, URL, method, request headers, request payload, request/correlation IDs |
| Successful response | HTTP status, success flag, response payload, duration |
| HTTP error response | HTTP status, error response payload, error message, duration |
| Client error | Error message and duration |
Metadata Resolution
Inbound metadata comes from @ExternalApi.
Rules:
- A class-level annotation applies to all operations in the controller.
- A method-level annotation overrides class-level metadata.
enabled=falsedisables external metadata for that annotated element.- If
operationis blank, Chenile uses the operation name from the exchange.
Outbound metadata comes from ExternalApiRequest.system and ExternalApiRequest.operation.
Payload Handling
ExternalApiLogSupport.payload(...) serializes non-string payloads as JSON. If serialization fails, it falls back to String.valueOf(payload).
Payloads are truncated using chenile.external-api.logging.max-payload-bytes. Truncated values are suffixed with ...[truncated].
Header values listed in chenile.external-api.logging.masked-headers are copied as ****.
Failure Behavior
External API logging is best effort.
| Failure | Behavior |
|---|---|
| Logging disabled | No external record is published |
No @ExternalApi metadata on inbound request |
No external record is published |
| No outbound topic or inbound topic | Pub/Sub publisher skips publication |
No ChenilePub bean |
Pub/Sub publisher skips publication |
| Publisher throws exception | Caller flow continues; warning is logged |
| Outbound third-party call fails | Record is captured, then the original RestClientException is rethrown |
Duplicate Prevention
The framework prevents most duplicate records by making external logging opt-in:
- Inbound records are published only for
@ExternalApiservices or operations. - Outbound records are published only through
ChenileExternalClient. - Chenile proxy calls are not automatically classified as outbound external calls.
Operationally, keep separate inbound and outbound topics if consumers need independent processing.
Developer Guide
For implementation examples and an end-to-end checklist, see External API Logging Developer Guide.