Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Cassandra Logging Configuration (logback.xml)

Cassandra uses Logback for logging, configured via logback.xml. This file controls log levels, output destinations, formats, and rotation policies.

FileLocation
logback.xml/etc/cassandra/

Changes to logback.xml are detected automatically within 60 seconds—no restart required.


Cassandra produces several log files by default:

Log FilePurposeDefault Location
system.logMain operational log/var/log/cassandra/
debug.logDetailed debug output/var/log/cassandra/
gc.logGarbage collection (JVM-configured)/var/log/cassandra/

<configuration scan="true" scanPeriod="60 seconds">
<!-- Appenders define where logs go -->
<appender name="..." class="...">
<!-- appender configuration -->
</appender>
<!-- Loggers define what gets logged -->
<logger name="..." level="..."/>
<!-- Root logger catches everything not matched by specific loggers -->
<root level="INFO">
<appender-ref ref="..."/>
</root>
</configuration>

Output to stdout (useful for containers):

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-5level [%thread] %date{ISO8601} %F:%L - %msg%n</pattern>
</encoder>
</appender>

Standard file appender with rotation:

<appender name="SYSTEMLOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${cassandra.logdir}/system.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- Roll daily -->
<fileNamePattern>${cassandra.logdir}/system.log.%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
<!-- Max 50MB per file -->
<maxFileSize>50MB</maxFileSize>
<!-- Keep 7 days of history -->
<maxHistory>7</maxHistory>
<!-- Cap total size at 5GB -->
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%-5level [%thread] %date{ISO8601} %F:%L - %msg%n</pattern>
</encoder>
</appender>

Separate file for DEBUG level messages:

<appender name="DEBUGLOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${cassandra.logdir}/debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${cassandra.logdir}/debug.log.%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%-5level [%thread] %date{ISO8601} %F:%L - %msg%n</pattern>
</encoder>
</appender>

Wrap appenders for non-blocking logging:

<appender name="ASYNCSYSTEMLOG" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>1024</queueSize>
<discardingThreshold>0</discardingThreshold>
<includeCallerData>true</includeCallerData>
<appender-ref ref="SYSTEMLOG"/>
</appender>

LevelDescriptionUse Case
TRACEMost detailedDeep debugging
DEBUGDetailed informationDevelopment, troubleshooting
INFONormal operationsProduction default
WARNPotential issuesProduction monitoring
ERRORErrors requiring attentionAlways enabled
OFFDisable loggingSpecific loggers only

Catches all log messages not matched by specific loggers:

<root level="INFO">
<appender-ref ref="SYSTEMLOG"/>
<appender-ref ref="STDOUT"/>
</root>

Control verbosity for specific components:

<!-- Reduce noisy components -->
<logger name="org.apache.cassandra.db.compaction" level="INFO"/>
<logger name="org.apache.cassandra.service.StorageService" level="INFO"/>
<!-- Increase verbosity for troubleshooting -->
<logger name="org.apache.cassandra.db.commitlog" level="DEBUG"/>
<logger name="org.apache.cassandra.streaming" level="DEBUG"/>
LoggerLevelPurpose
org.apache.cassandraINFOAll Cassandra components
org.apache.cassandra.db.compactionINFOCompaction operations
org.apache.cassandra.db.commitlogINFOCommit log operations
org.apache.cassandra.streamingINFOStreaming operations
org.apache.cassandra.hintsINFOHinted handoff
org.apache.cassandra.repairINFORepair operations
org.apache.cassandra.gmsINFOGossip protocol
org.apache.cassandra.netINFOInternode messaging
org.apache.cassandra.cql3INFOCQL processing
org.apache.cassandra.authINFOAuthentication/authorization

ElementDescriptionExample Output
%levelLog levelINFO
%-5levelLog level, left-padded to 5 charsINFO
%threadThread namemain
%date{ISO8601}ISO timestamp2024-01-15 10:30:45,123
%loggerLogger nameorg.apache.cassandra.db.Memtable
%FSource file nameMemtable.java
%LLine number234
%MMethod nameflush
%msgLog messageFlushing memtable
%nNewline
%X{key}MDC valueCustom context
<pattern>%-5level [%thread] %date{ISO8601} %F:%L - %msg%n</pattern>

Output:

INFO [main] 2024-01-15 10:30:45,123 StorageService.java:1234 - Starting listening for CQL clients
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
<jsonFormatter class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter"/>
<timestampFormat>yyyy-MM-dd'T'HH:mm:ss.SSS'Z'</timestampFormat>
<appendLineSeparator>true</appendLineSeparator>
</layout>
</encoder>

Roll logs based on both size and time:

<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${cassandra.logdir}/system.log.%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>

Roll logs daily without size limit:

<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${cassandra.logdir}/system.log.%d{yyyy-MM-dd}.zip</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>

Roll logs based on size only:

<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>${cassandra.logdir}/system.log.%i.zip</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>10</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>100MB</maxFileSize>
</triggeringPolicy>

<configuration scan="true" scanPeriod="60 seconds">
<!-- JMX configuration -->
<jmxConfigurator/>
<!-- System log -->
<appender name="SYSTEMLOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${cassandra.logdir}/system.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${cassandra.logdir}/system.log.%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%-5level [%thread] %date{ISO8601} %F:%L - %msg%n</pattern>
</encoder>
</appender>
<!-- Debug log -->
<appender name="DEBUGLOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${cassandra.logdir}/debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${cassandra.logdir}/debug.log.%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%-5level [%thread] %date{ISO8601} %F:%L - %msg%n</pattern>
</encoder>
<!-- Only DEBUG level -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- Async wrappers -->
<appender name="ASYNCSYSTEMLOG" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>1024</queueSize>
<discardingThreshold>0</discardingThreshold>
<includeCallerData>true</includeCallerData>
<appender-ref ref="SYSTEMLOG"/>
</appender>
<appender name="ASYNCDEBUGLOG" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>1024</queueSize>
<discardingThreshold>0</discardingThreshold>
<includeCallerData>true</includeCallerData>
<appender-ref ref="DEBUGLOG"/>
</appender>
<!-- Reduce noisy loggers -->
<logger name="org.apache.cassandra.db.compaction.CompactionTask" level="INFO"/>
<logger name="org.apache.cassandra.service.StorageProxy" level="INFO"/>
<!-- Root logger -->
<root level="INFO">
<appender-ref ref="ASYNCSYSTEMLOG"/>
<appender-ref ref="ASYNCDEBUGLOG"/>
</root>
</configuration>
<configuration scan="true" scanPeriod="60 seconds">
<!-- Console output for container logs -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-5level [%thread] %date{ISO8601} %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Async wrapper -->
<appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>1024</queueSize>
<discardingThreshold>0</discardingThreshold>
<appender-ref ref="STDOUT"/>
</appender>
<!-- Reduce verbosity -->
<logger name="org.apache.cassandra.db.compaction" level="WARN"/>
<logger name="org.apache.cassandra.gms.Gossiper" level="WARN"/>
<root level="INFO">
<appender-ref ref="ASYNCSTDOUT"/>
</root>
</configuration>
<configuration scan="true" scanPeriod="60 seconds">
<appender name="SYSTEMLOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${cassandra.logdir}/system.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${cassandra.logdir}/system.log.%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>3</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%-5level [%thread] %date{ISO8601} %logger{36}:%L - %msg%n</pattern>
</encoder>
</appender>
<!-- Enable debug for specific subsystems -->
<logger name="org.apache.cassandra.db.compaction" level="DEBUG"/>
<logger name="org.apache.cassandra.streaming" level="DEBUG"/>
<logger name="org.apache.cassandra.repair" level="DEBUG"/>
<logger name="org.apache.cassandra.hints" level="DEBUG"/>
<logger name="org.apache.cassandra.net" level="DEBUG"/>
<logger name="org.apache.cassandra.gms" level="DEBUG"/>
<root level="DEBUG">
<appender-ref ref="SYSTEMLOG"/>
</root>
</configuration>

Modify log levels without restart using nodetool:

Terminal window
# View current levels
nodetool getlogginglevels
# Set level for specific logger
nodetool setlogginglevel org.apache.cassandra.db.compaction DEBUG
# Reset to configuration file settings
nodetool setlogginglevel org.apache.cassandra.db.compaction RESET

Runtime vs Persistent Changes

Changes via nodetool are temporary and reset on restart. For persistent changes, modify logback.xml.


Cassandra 4.0+ includes built-in audit logging:

<!-- Audit log appender -->
<appender name="AUDIT" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${cassandra.logdir}/audit/audit.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${cassandra.logdir}/audit/audit.log.%d{yyyy-MM-dd}.%i.zip</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%-5level [%thread] %date{ISO8601} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.apache.cassandra.audit" level="INFO" additivity="false">
<appender-ref ref="AUDIT"/>
</logger>

Enable in cassandra.yaml:

audit_logging_options:
enabled: true
logger:
- class_name: BinAuditLogger
included_keyspaces: my_keyspace
included_categories: QUERY,DML,DDL,AUTH

Log all CQL queries for debugging:

Terminal window
# Enable via nodetool
nodetool enablefullquerylog --path /var/log/cassandra/fql
# Disable
nodetool disablefullquerylog
# Read logs
fqltool dump /var/log/cassandra/fql

Log queries exceeding threshold:

cassandra.yaml
slow_query_log_timeout_in_ms: 500

Slow queries appear in system.log at WARN level.


  1. Check directory permissions:

    Terminal window
    ls -la /var/log/cassandra/
  2. Verify cassandra.logdir property:

    Terminal window
    grep logdir /etc/cassandra/cassandra-env.sh
  3. Check for XML syntax errors:

    Terminal window
    xmllint --noout /etc/cassandra/logback.xml

Configure aggressive rotation:

<maxFileSize>25MB</maxFileSize>
<maxHistory>3</maxHistory>
<totalSizeCap>1GB</totalSizeCap>

Use async appenders to minimize logging overhead:

<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>1024</queueSize>
<discardingThreshold>0</discardingThreshold>
<neverBlock>true</neverBlock>
<appender-ref ref="SYSTEMLOG"/>
</appender>

Ensure includeCallerData is enabled for async appenders:

<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<includeCallerData>true</includeCallerData>
<appender-ref ref="SYSTEMLOG"/>
</appender>

PracticeRecommendation
Production log levelINFO for root, WARN for noisy components
Async appendersAlways use for production
RotationSize + time based with totalSizeCap
Debug logsSeparate file, enable only when needed
Container deploymentsConsole output, let orchestrator handle rotation
Disk monitoringAlert when log partition exceeds 80%
Retention7-30 days depending on compliance requirements