Posted on 2024-11-07
Tagged as: How To

Fine grained logging

The Language Server (LS) creates logs using the log4j framework. During normal operation, by default, the LS will log to the VS Code console at “warning” level.

By default, the LS accepts commands from the client to set the log level for the entire LS. You can change this log level from the VS Code extension through this setting:

VS Code Setting The Global Log Level

From time to time, this setting will be too coarse-grained. For example, suppose you want to obtain trace logging for a certain set of classes. In this case, you probably don’t want to enable trace logging for the entire LS. If you did so, then the amount of log-messages would be prohibitive. What you actually want is to enable trace-logging for a select set of classes and not for the rest of the LS. This cannot be accomplished by modifying the above client setting.

Instead, this How To will explain how to enable fine-grained log4j configuration. First, you have to provide a startup property to the LS that indicates that you want to use the log4j mechanism:

-Dlog4j.configuration=file:/home/mchristi/sigasi-development-project-master/git/sigasi/com.sigasi.lsp.server/src/log4j.xml
VS Code Setting The Log4J Configuration

When the log4j.configuration property is set, we disable the coarse-grained log-level setting and allow log4j to consult the configuration file. In the configuration file we can enable and disable logging as we see fit. We can also select different logging targets (files, console). An example log4j.xml file looks like this:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN"
	"http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
<log4j:configuration debug="false"
	xmlns:log4j='http://jakarta.apache.org/log4j/'>

	<!-- This appender will write logs up to INFO to the stdout console -->
	<appender name="CONSOLE"
		class="org.apache.log4j.ConsoleAppender">
		<param name="Target" value="System.out" />
		<param name="Threshold" value="TRACE" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern"
				value="%d{HH:mm:ss.SSS} %-5p [%-40.40c|%t] %m%n" />
		</layout>
		<filter class="org.apache.log4j.varia.LevelRangeFilter">
			<param name="levelMin" value="TRACE" />
			<param name="levelMax" value="INFO" />
		</filter>
	</appender>

	<!-- This appender will write WARN, ERROR and FATAL logs to the stderr console -->
	<appender name="CONSOLE_ERR"
		class="org.apache.log4j.ConsoleAppender">
		<param name="Target" value="System.err" />
		<param name="Threshold" value="WARN" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern"
				value="%d{HH:mm:ss.SSS} %-5p [%c|%t] %m%n" />
		</layout>

		<filter
			class="com.sigasi.lsp.server.NonSourceCodeLeakingFilter" />
	</appender>

	<appender name="FILE"
		class="org.apache.log4j.RollingFileAppender">
		<param name="file" value=".log" />
		<param name="MaxFileSize" value="1024KB" />
		<param name="MaxBackupIndex" value="5" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%c %x- %m" />
		</layout>

		<filter
			class="com.sigasi.lsp.server.NonSourceCodeLeakingFilter" />
	</appender>

	<logger name="com.sigasi.hdt.shared.ide.utils">
		<level value="DEBUG" />
	</logger>

	<root>
		<level value="WARN" />
		<appender-ref ref="CONSOLE" />
		<appender-ref ref="CONSOLE_ERR" />
		<appender-ref ref="FILE" />
	</root>

</log4j:configuration>

The above configuration will log everything at “warning” level except for log messages originating from the Java package com.sigasi.hdt.shared.ide.utils. Classes in this package will be allowed to log at “debug” level.

See also