A custom Logback encoder for converting EDN-formatted logs to structured JSON, designed for seamless integration with Loki and Grafana.
Logs in EDN format aren't easily parsed by log aggregation systems like Loki. This encoder converts EDN logs to structured JSON while preserving all semantic information, making your logs fully searchable and analyzable in Grafana.
# Clone the repository
git clone https://github.com/hamann/logback-edn-json-encoder.git
cd logback-edn-json-encoder
# Build the JAR
bb build
# The encoder JAR will be in target/edn-json-encoder-0.1.1.jar
{:deps {com.github.hamann/edn-json-encoder {:mvn/version "0.1.1"}}}
Create a logback.xml
file in the config directory:
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!-- Console appender for local development -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="com.github.hamann.EdnToJsonEncoder">
<!-- Optional: Set to true to preserve original EDN in output -->
<preserveOriginals>false</preserveOriginals>
</encoder>
</appender>
<!-- Root logger -->
<root level="${ROOT_LOG_LEVEL:-WARN}">
<appender-ref ref="${LOG_APPENDER:-CONSOLE}" />
</root>
</configuration>
The encoder generates JSON logs in this format:
{
"timestamp": "2023-12-25T10:30:45.123Z",
"level": "INFO",
"logger": "datomic.transaction",
"thread": "datomic-tx-thread",
"tx-id": 12345,
"operation": "commit",
"entities": ["user", "account", "preference"],
"edn_parsed": true,
"mdc": {
"user-id": 789,
"session-data": {
"role": "admin",
"team": "eng"
}
}
}
You can enable preservation of original EDN values in the logback.xml configuration:
<encoder class="com.github.hamann.EdnToJsonEncoder">
<preserveOriginals>true</preserveOriginals>
</encoder>
When enabled, the encoder includes the original values in the output:
{
"_original_message": "{:tx-id 12345 :operation :commit :entities [:user :account :preference]}",
"_original_mdc": {
"user-id": "789",
"session-data": "{:role :admin :team :eng}"
}
}
With this encoder, you can perform rich queries in Grafana:
# All errors for a specific transaction
{app="datomic"} | json | level="ERROR" and tx_id=12345
# All transactions for a specific user
{app="datomic"} | json | mdc_user_id=789
# Errors with specific exception
{app="datomic"} | json | exception_class=~".*TransactionException.*"
# Find operations with more than X entities
{app="datomic"} | json | operation="commit" | length(entities) > 3
# Full build
bb build
# Just compile
bb compile
# Run tests
bb test
# Run linting
bb lint
# Development REPL
bb dev
A flake.nix
is provided for reproducible development environments:
# Start a development shell
nix develop
This project is licensed under the Eclipse Public License 2.0 - see the LICENSE file for details.
The EPL-2.0 is a copyleft license that:
This project includes a bb publish
task for publishing to Maven repositories (like Clojars). Before publishing:
Set up Clojars account (or your preferred Maven repository)
Set up SOPS for credential management:
# Generate age key (recommended) or use existing GPG key
age-keygen -o ~/.config/sops/age/keys.txt
# Update .sops.yaml with your age public key
# (The public key is printed when you generate it)
Create encrypted secrets file:
# Create secrets file with your credentials
cat > secrets.yaml << EOF
clojars:
username: your-clojars-username
password: your-clojars-deploy-token
EOF
# Encrypt with SOPS (safe to commit)
sops -e -i secrets.yaml
Update project metadata in build.clj
if needed:
group-id
and artifact-id
(currently com.github.hamann/edn-json-encoder
)version
(currently 0.1.1
)url
and SCM URLs (currently pointing to github.com/hamann/edn-to-json-encoder
)# Build and publish to Maven repository
bb publish
The publish task will:
bb build
)Once published, users can add it to their deps.edn
:
{:deps {com.github.hamann/edn-json-encoder {:mvn/version "0.1.1"}}}
Or include the JAR in their Java classpath for Logback configuration.
Contributions welcome! Please feel free to submit a Pull Request.
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close