Skip to content

Commit

Permalink
ID-3537: Featureswitch for debug-logging (#75)
Browse files Browse the repository at this point in the history
  • Loading branch information
oyri authored Nov 15, 2023
1 parent 44be41a commit baff53f
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 5 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,21 @@ tomcat:
```
Set this property to 'enabled' or remove completely to enable Tomcat access logging.
Use your own logback-access.xml file or configure debug-logging:
```yaml
digdir:
access:
logging:
debug-level: request
config-file: my-logback.xml # will override debug setting
```
USE EITHER `debug-level` OR `config-file`, not both.
Valid values for debug-level are:
* `request`: logging attribute `fullRequest` in addition to normal logging.
* `response`: logging attributes `fullRequest` and `fullResponse` in addition to normal logging.
* Use default config if not set or null.

NB: `debug-level` mode will log very much, use only temporary on servers with not to high load to avoid exhausting central logging-system.

## Troubleshooting
If you can not see any access logging in IntelliJ, then try Maven->reload project.
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,62 @@
@Configuration
@EnableConfigurationProperties(AccessLogsProperties.class)
public class AccessLogsConfiguration {



// Static properties to make spring application properties available to AccesslogProvider
private static AccessLogsProperties properties = null;

public static AccessLogsProperties getProperties(){
protected static final String DEFAULT_LOGBACK_CONFIG_FILE = "logback-access.xml";
protected static final String LOGBACK_CONFIG_REQ_FULL_FILE = "logback-access-req-full.xml";
protected static final String LOGBACK_CONFIG_REQ_RESP_FULL_FILE = "logback-access-req-resp-full.xml";

public static AccessLogsProperties getProperties() {
return properties;
}

@Value("${digdir.access.logging.config-file:logback-access.xml}")
String logConfigfile;

@Value("${digdir.access.logging.debug-level:}")
String debugLevel;


@Bean
@ConditionalOnProperty(prefix = "tomcat", name = "accesslog", havingValue = "enabled", matchIfMissing = true)
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> accessLogsCustomizer(AccessLogsProperties props) {
LoggerFactory.getLogger(AccessLogsConfiguration.class).info("Initialize accessLogsCustomizer for Tomcat Access Logging as JSON" );
if(properties == null){
if (properties == null) {
properties = props;
}
String logbackConfigFile = checkIfDebugFeatureEnabledAndConfigureLogbackfile(logConfigfile, debugLevel);

LoggerFactory.getLogger(AccessLogsConfiguration.class).info("Initialize accessLogsCustomizer for Tomcat Access Logging as JSON. Use config-file: " + logbackConfigFile);

return factory -> {
var logbackValve = new LogbackValve();
logbackValve.setFilename(logConfigfile);
logbackValve.setFilename(logbackConfigFile);
logbackValve.setAsyncSupported(true);
factory.addContextValves(logbackValve);
};
}

/**
* Use application provided logback-access.xml if property digdir.access.logging.config-file is configured,
* otherwise check if debug-level is configured.
*
* @param configFile
* @param debug
*/
protected String checkIfDebugFeatureEnabledAndConfigureLogbackfile(String configFile, String debug) {

if (DEFAULT_LOGBACK_CONFIG_FILE.equals(configFile) && debug != null && !debug.isEmpty()) {
if ("request".equalsIgnoreCase(debug)) {
return LOGBACK_CONFIG_REQ_FULL_FILE;
} else if ("response".equalsIgnoreCase(debug)) {
return LOGBACK_CONFIG_REQ_RESP_FULL_FILE;
}
}
return configFile;
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<property resource="application.yaml" />
<property resource="application.yml" />
<appender name="accessJsonConsoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.AccessEventCompositeJsonEncoder">

<providers>
<timestamp />
<pattern>
<pattern>
{
"@version" : "1",
"@type" : "access",
"logtype": "tomcat-access",
"x_forwarded_for": "%header{X-Forwarded-For}",
"client_host" : "%clientHost",
"remote_user" : "%user",
"request_method" : "%requestMethod",
"request_url" : "%requestURL",
"request_uri" : "%requestURI",
"status_code" : "#asLong{%statusCode}",
"bytes_sent" : "#asLong{%bytesSent}",
"elapsed_time" : "#asLong{%elapsedTime}",
"message" : "%requestURL %statusCode",
"user_agent": "%i{User-Agent}",
"referer": "%header{Referer}",
"fullRequest":"%fullRequest"
}
</pattern>
</pattern>
<provider class="no.idporten.logging.access.AccesslogProvider"/>
</providers>

</encoder>
</appender>
<appender-ref ref="accessJsonConsoleAppender" />
</configuration>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<property resource="application.yaml" />
<property resource="application.yml" />
<appender name="accessJsonConsoleAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.AccessEventCompositeJsonEncoder">

<providers>
<timestamp />
<pattern>
<pattern>
{
"@version" : "1",
"@type" : "access",
"logtype": "tomcat-access",
"x_forwarded_for": "%header{X-Forwarded-For}",
"client_host" : "%clientHost",
"remote_user" : "%user",
"request_method" : "%requestMethod",
"request_url" : "%requestURL",
"request_uri" : "%requestURI",
"status_code" : "#asLong{%statusCode}",
"bytes_sent" : "#asLong{%bytesSent}",
"elapsed_time" : "#asLong{%elapsedTime}",
"message" : "%requestURL %statusCode",
"user_agent": "%i{User-Agent}",
"referer": "%header{Referer}",
"fullRequest":"%fullRequest",
"fullResponse":"%fullResponse"
}
</pattern>
</pattern>
<provider class="no.idporten.logging.access.AccesslogProvider"/>
</providers>

</encoder>
</appender>
<appender-ref ref="accessJsonConsoleAppender" />
</configuration>
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package no.idporten.logging.access;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;

import static no.idporten.logging.access.AccessLogsConfiguration.*;
import static org.junit.jupiter.api.Assertions.assertEquals;

@ExtendWith(MockitoExtension.class)
class AccessLogsConfigurationTest {
@DisplayName("When no configfile or debug configured then use default configfile")
@Test
public void useDefaultConfigFile() {
AccessLogsConfiguration config = new AccessLogsConfiguration();
String configToUse = config.checkIfDebugFeatureEnabledAndConfigureLogbackfile(DEFAULT_LOGBACK_CONFIG_FILE, null);
assertEquals(DEFAULT_LOGBACK_CONFIG_FILE, configToUse);
}

@DisplayName("When external configfile is set, but no debug then use external configfile")
@Test
public void useExternalConfigFile() {
AccessLogsConfiguration config = new AccessLogsConfiguration();
String configToUse = config.checkIfDebugFeatureEnabledAndConfigureLogbackfile("config-so-perfect.xml", null);
assertEquals("config-so-perfect.xml", configToUse);
}

@DisplayName("When external configfile is set and debug then use external configfile")
@Test
public void useExternalConfigFileWhenDebugSet() {
AccessLogsConfiguration config = new AccessLogsConfiguration();
String configToUse = config.checkIfDebugFeatureEnabledAndConfigureLogbackfile("config-so-perfect.xml", "request");
assertEquals("config-so-perfect.xml", configToUse);
}

@DisplayName("When no external configfile is set and debug is request then use full request file")
@Test
public void useDebugRequestFileWhenDebugSetAndNoExternalConfig() {
AccessLogsConfiguration config = new AccessLogsConfiguration();
String configToUse = config.checkIfDebugFeatureEnabledAndConfigureLogbackfile(DEFAULT_LOGBACK_CONFIG_FILE, "request");
assertEquals(LOGBACK_CONFIG_REQ_FULL_FILE, configToUse);
}

@DisplayName("When no external configfile is set and debug is response then use full response file")
@Test
public void useDebugResponseFileWhenDebugSetAndNoExternalConfig() {
AccessLogsConfiguration config = new AccessLogsConfiguration();
String configToUse = config.checkIfDebugFeatureEnabledAndConfigureLogbackfile(DEFAULT_LOGBACK_CONFIG_FILE, "response");
assertEquals(LOGBACK_CONFIG_REQ_RESP_FULL_FILE, configToUse);
}


}

0 comments on commit baff53f

Please sign in to comment.