# orange-mathoms-logging
**Repository Path**: mirrors_Orange-OpenSource/orange-mathoms-logging
## Basic Information
- **Project Name**: orange-mathoms-logging
- **Description**: Logging related Java tools from Orange Experts
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-08-18
- **Last Updated**: 2026-02-07
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Orange Mathoms: Logging
[](https://travis-ci.org/Orange-OpenSource/orange-mathoms-logging)
[ ](https://bintray.com/orange-opensource/maven/orange-mathoms-logging/_latestVersion)
This Java library - developed by the Orange Software Experts community - packages several [mathoms](http://tolkiengateway.net/wiki/Mathoms)
related to logging that are used here and there in our projects.
They are mostly relying on [JEE](https://en.wikipedia.org/wiki/Java_Platform,_Enterprise_Edition),
[SLF4J](https://www.slf4j.org/), [Logback](https://logback.qos.ch/) and
[logstash-logback-encoder](https://github.com/logstash/logstash-logback-encoder).
## License
This code is under [Apache-2.0 License](LICENSE.txt)
## Table of content
* [Including it in your project](#including)
* [Enrich logs with unique request IDs](#requestIds)
* [Enrich logs with user IDs](#userIds)
* [Enrich logs with session IDs](#sessionIds)
* [Enrich stack traces with unique signatures](#stackTraceSign)
* [Demo application](#demo)
## Include it in your project
Maven style (`pom.xml`):
```xml
bintray-orange
http://dl.bintray.com/orange-opensource/maven
true
false
...
com.orange.common
orange-mathoms-logging
1.0.0
...
```
## Enrich logs with unique request IDs
### Why
If you're relying on Spring Boot and building a microservices application, our obvious advice is to use [Spring Cloud Sleuth](https://cloud.spring.io/spring-cloud-sleuth/)
to enable distributed tracing and logs correlation.
But if you are in a simpler context (monolothic app) or not using Spring Boot, you might be interested by the
[RequestIdFilter](src/main/java/com/orange/common/logging/web/RequestIdFilter.java),
a servlet filter, that enriches the logging context (SLF4J's [Mapped Diagnostic Context](https://logback.qos.ch/manual/mdc.html))
with a unique request ID.
This unique request ID is either *retrieved* from the incoming request's headers (e.g. using an Apache Http server with
[mod_unique_id](https://httpd.apache.org/docs/current/en/mod/mod_unique_id.html) or any equivalent alternative),
or *generated* if not present.
Notice that you can also *propagate* the request ID when calling other servers by using the [HttpRequestHandlerWithMdcPropagation](src/main/java/com/orange/common/logging/web/HttpRequestHandlerWithMdcPropagation.java)
component (see JavaDoc for more details).
> :warning: The [RequestIdFilter](src/main/java/com/orange/common/logging/web/RequestIdFilter.java)
> has to be installed *as early as possible* in the filters chain, to enrich all subsequent logs with the request ID.
### Configuration
The *incoming request header name*, *MDC key* and *request attribute name* have default values, but can be configured either
programmatically, with filter init parameters, or Java properties:
parameter | Java property | filter init param | default value
--------- | ------------- | ----------------- | -------------
request header name | `slf4j.tools.request_filter.header` | `header` | `X-Track-RequestId`
MDC key | `slf4j.tools.request_filter.mdc` | `mdc` | `requestId`
request attribute name | `slf4j.tools.request_filter.attribute` | `attribute` | `track.requestId`
### Example (the Spring Boot way)
Using Spring Boot, a servlet filter can be easily installed as a `@Bean` of type `javax.servlet.Filter` in your Spring Boot application.
Example:
```java
/**
* Install {@link RequestIdFilter} on every request
*/
@Bean
public Filter requestIdFilter() {
RequestIdFilter filter = new RequestIdFilter();
// override the default incoming request header name
filter.setHeaderName("UNIQUE_ID");
return filter;
}
```
### Example (the web.xml way)
If you're not relying on Spring Boot, you can anyway use the [RequestIdFilter](src/main/java/com/orange/common/logging/web/RequestIdFilter.java)
filter by declaring it in your `web.xml` descriptor.
```xml
RequestIdFilter
com.orange.experts.utils.logging.web.RequestIdFilter
header
UNIQUE_ID
RequestIdFilter
/*
```
## Enrich logs with user IDs
### Why
For applications managing users authentication, tagging logs with user IDs enables filtering in one click all logs related to a single user, or
checking very easily if a given error happens more often on some users of if it's evenly distributed.
This can be done with [PrincipalFilter](src/main/java/com/orange/common/logging/web/PrincipalFilter.java),
a servlet filter, that adds the authenticated `java.security.Principal` name to the logging context
(SLF4J's [Mapped Diagnostic Context](https://logback.qos.ch/manual/mdc.html)).
> :warning: The [PrincipalFilter](src/main/java/com/orange/common/logging/web/PrincipalFilter.java)
> has to be installed *after* the authentication filter in the filters chain, so that the authentication context is set.
### Configuration
If the principal name is a personal user information (such as login or email address), it is recommended not to add it
"as-is" to the logging context, but generate a hash of it.
This filter allows configuring a hashing algorithm. Supported values are:
- `none`: principal name is added unchanged (default),
- `hashcode`: an heaxadecimal representation of the principal name hashcode,
- any other: shall refer to a valid message digest algorithm.
The *hashing algorithm*, *MDC key* and *request attribute name* have default values, but can be configured either
programmatically, with filter init parameters, or Java properties:
parameter | Java property | filter init param | default value
--------- | ------------- | ----------------- | -------------
hashing algorithm | `slf4j.tools.principal_filter.hash_algorithm` | `hash_algorithm` | `none`
MDC key | `slf4j.tools.principal_filter.mdc` | `mdc` | `userId`
request attribute name | `slf4j.tools.principal_filter.attribute` | `attribute` | `track.userId`
### Example (the Spring Boot way)
Using Spring Boot, a servlet filter can be easily installed as a `@Bean` of type `javax.servlet.Filter` in your Spring Boot application.
Example:
```java
/**
* Install {@link PrincipalFilter} on every request
*/
@Bean
public Filter principalFilter(@Value("${logging.principal.hash_algo}") String hashAlgorithm) throws NoSuchAlgorithmException {
PrincipalFilter filter = new PrincipalFilter();
// set hashing algorithm through Spring Boot config
filter.setHashAlgorithm(hashAlgorithm);
return filter;
}
```
### Example (the web.xml way)
If you're not relying on Spring Boot, you can anyway use the [PrincipalFilter](src/main/java/com/orange/common/logging/web/PrincipalFilter.java)
filter by declaring it in your `web.xml` descriptor.
Example:
```xml
PrincipalFilter
com.orange.common.logging.web.PrincipalFilter
hash_algorithm
SHA-1
PrincipalFilter
/*
```
## Enrich logs with session IDs
### Why
For stateful applications (i.e. managing JEE sessions), tagging logs with session IDs enables filtering in one click all
logs related to a single session.
It may help - for instance - understand the user journey within his session.
This can be done with [SessionIdFilter](src/main/java/com/orange/common/logging/web/SessionIdFilter.java)
a servlet filter, that adds the current JEE session ID to the logging context
(SLF4J's [Mapped Diagnostic Context](https://logback.qos.ch/manual/mdc.html)).
### Configuration
By default, the MDC key used to store the session ID is called `sessionId`, but it may be configured
either programmatically, with filter init parameters, or Java properties:
parameter | Java property | filter init param | default value
--------- | ------------- | ----------------- | -------------
MDC key | `slf4j.tools.session_filter.mdc` | `mdc` | `sessionId`
### Example (the Spring Boot way)
Using Spring Boot, a servlet filter can be easily installed as a `@Bean` of type `javax.servlet.Filter` in your Spring Boot application.
Example:
```java
/**
* Install {@link SessionIdFilter} on every request
*/
@Bean
public Filter sessionIdFilter() {
return new SessionIdFilter();
}
```
### Example (the web.xml way)
If you're not relying on Spring Boot, you can anyway use the [SessionIdFilter](src/main/java/com/orange/common/logging/web/SessionIdFilter.java)
filter by declaring it in your `web.xml` descriptor.
Example:
```xml
SessionIdFilter
com.orange.common.logging.web.SessionIdFilter
SessionIdFilter
/*
```
## Enrich stack traces with unique signatures
### Why
It is an easy way to track the error from the client (UI and/or API) to your logs, count their frequency, make sure a
problem has been fixed for good...
The idea is to generate a short, unique ID that identifies your stack trace.
Example:
```text
<#07e70d1e> com.xyz.MyApp$MyClient$MyClientException: An error occurred while getting the things
at com.xyz.MyApp$MyClient.getTheThings(MyApp.java:26)
at com.xyz.MyApp.test_logging(MyApp.java:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
...
Caused by: <#393b506a> com.xyz.MyApp$HttpStack$HttpError: I/O error on GET request for http://dummy/things
at com.xyz.MyApp$HttpStack.get(MyApp.java:40)
at com.xyz.MyApp$MyClient.getTheThings(MyApp.java:24)
... 23 common frames omitted
Caused by: <#d6db326f> java.net.SocketTimeoutException: Read timed out
at com.xyz.MyApp$HttpStack.get(MyApp.java:38)
... 24 common frames omitted```
```
### How
This feature is no longer part of the `orange-mathoms-logging` library, as it has been contributed to the [logstash-logback-encoder](https://github.com/logstash/logstash-logback-encoder) library (available from version `4.11`).
This is done thanks to the [ShortenedThrowableConverter](https://github.com/logstash/logstash-logback-encoder/blob/master/src/main/java/net/logstash/logback/stacktrace/ShortenedThrowableConverter.java) component .
Additionally, when pushing logs into JSON native format, you may also use the custom [StackHashJsonProvider](https://github.com/logstash/logstash-logback-encoder/blob/master/src/main/java/net/logstash/logback/composite/loggingevent/StackHashJsonProvider.java)
provider, that adds the stack trace signature (hash) as a separate field, for building advanced Kibana dashboards.
Both are installed and configured in Logback configuration files:
```xml
${logstash_host}
${logstash_port}
${STE_EXCLUSIONS}
true
${STE_EXCLUSIONS}
```
### Implementation details
Read more [details about error hash computation](https://github.com/logstash/logstash-logback-encoder/blob/master/stack-hash.md).
## Demo application
Most of those tools are demo'ed in [Woofer](https://github.com/Orange-OpenSource/woofer), a showcase web app based on Spring Boot.