Skip to content

Commit 5b44462

Browse files
committed
api v2 data logger service and integration test, some refactoring
* fixed audit/data logger additivity * modified audit/data logger patterns: added MDC, removed thread and logger class/method
1 parent 511e933 commit 5b44462

File tree

21 files changed

+337
-81
lines changed

21 files changed

+337
-81
lines changed

dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/ProcessPluginApiImpl.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import ca.uhn.fhir.context.FhirContext;
1010
import dev.dsf.bpe.v2.config.ProxyConfig;
1111
import dev.dsf.bpe.v2.service.CryptoService;
12+
import dev.dsf.bpe.v2.service.DataLogger;
1213
import dev.dsf.bpe.v2.service.DsfClientProvider;
1314
import dev.dsf.bpe.v2.service.EndpointProvider;
1415
import dev.dsf.bpe.v2.service.FhirClientProvider;
@@ -31,7 +32,6 @@ public class ProcessPluginApiImpl implements ProcessPluginApi, InitializingBean
3132
private final FhirClientProvider fhirClientProvider;
3233
private final OidcClientProvider oidcClientProvider;
3334
private final MailService mailService;
34-
3535
private final MimetypeService mimetypeService;
3636
private final ObjectMapper objectMapper;
3737
private final OrganizationProvider organizationProvider;
@@ -41,14 +41,15 @@ public class ProcessPluginApiImpl implements ProcessPluginApi, InitializingBean
4141
private final TaskHelper taskHelper;
4242
private final CryptoService cryptoService;
4343
private final TargetProvider targetProvider;
44+
private final DataLogger dataLogger;
4445

4546
public ProcessPluginApiImpl(ProxyConfig proxyConfig, EndpointProvider endpointProvider, FhirContext fhirContext,
4647
DsfClientProvider dsfClientProvider, FhirClientProvider fhirClientProvider,
4748
OidcClientProvider oidcClientProvider, MailService mailService, MimetypeService mimetypeService,
4849
ObjectMapper objectMapper, OrganizationProvider organizationProvider,
4950
ProcessAuthorizationHelper processAuthorizationHelper,
5051
QuestionnaireResponseHelper questionnaireResponseHelper, ReadAccessHelper readAccessHelper,
51-
TaskHelper taskHelper, CryptoService cryptoService, TargetProvider targetProvider)
52+
TaskHelper taskHelper, CryptoService cryptoService, TargetProvider targetProvider, DataLogger dataLogger)
5253
{
5354
this.proxyConfig = proxyConfig;
5455
this.endpointProvider = endpointProvider;
@@ -66,6 +67,7 @@ public ProcessPluginApiImpl(ProxyConfig proxyConfig, EndpointProvider endpointPr
6667
this.taskHelper = taskHelper;
6768
this.cryptoService = cryptoService;
6869
this.targetProvider = targetProvider;
70+
this.dataLogger = dataLogger;
6971
}
7072

7173
@Override
@@ -86,6 +88,7 @@ public void afterPropertiesSet() throws Exception
8688
Objects.requireNonNull(taskHelper, "taskHelper");
8789
Objects.requireNonNull(cryptoService, "cryptoService");
8890
Objects.requireNonNull(targetProvider, "targetProvider");
91+
Objects.requireNonNull(dataLogger, "dataLogger");
8992
}
9093

9194
@Override
@@ -183,4 +186,10 @@ public TargetProvider getTargetProvider()
183186
{
184187
return targetProvider;
185188
}
189+
190+
@Override
191+
public DataLogger getDataLogger()
192+
{
193+
return dataLogger;
194+
}
186195
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package dev.dsf.bpe.v2.service;
2+
3+
import org.hl7.fhir.r4.model.Resource;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
6+
7+
import ca.uhn.fhir.context.FhirContext;
8+
9+
public class DataLoggerImpl implements DataLogger
10+
{
11+
private static final Logger logger = LoggerFactory.getLogger("dsf-data-logger");
12+
13+
private final FhirContext fhirContext;
14+
15+
public DataLoggerImpl(FhirContext fhirContext)
16+
{
17+
this.fhirContext = fhirContext;
18+
}
19+
20+
public void log(String message, Resource resource)
21+
{
22+
if (message != null)
23+
logger.debug("{}: {}", message, asString(resource));
24+
}
25+
26+
@Override
27+
public void log(String message, Object object)
28+
{
29+
if (message != null)
30+
logger.debug("{}: {}", message, String.valueOf(object));
31+
}
32+
33+
private String asString(Resource resource)
34+
{
35+
return resource == null ? "null" : fhirContext.newJsonParser().encodeResourceToString(resource);
36+
}
37+
38+
@Override
39+
public boolean isEnabled()
40+
{
41+
return logger.isDebugEnabled();
42+
}
43+
}

dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/spring/ApiServiceConfig.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
import dev.dsf.bpe.v2.plugin.ProcessPluginFactoryImpl;
4040
import dev.dsf.bpe.v2.service.CryptoService;
4141
import dev.dsf.bpe.v2.service.CryptoServiceImpl;
42+
import dev.dsf.bpe.v2.service.DataLogger;
43+
import dev.dsf.bpe.v2.service.DataLoggerImpl;
4244
import dev.dsf.bpe.v2.service.DsfClientProvider;
4345
import dev.dsf.bpe.v2.service.DsfClientProviderImpl;
4446
import dev.dsf.bpe.v2.service.EndpointProvider;
@@ -101,7 +103,7 @@ public ProcessPluginApi processPluginApiV2()
101103
return new ProcessPluginApiImpl(proxyConfigDelegate(), endpointProvider(), fhirContext(), dsfClientProvider(),
102104
fhirClientProvider(), oidcClientProvider(), mailService(), mimetypeService(), objectMapper(),
103105
organizationProvider(), processAuthorizationHelper(), questionnaireResponseHelper(), readAccessHelper(),
104-
taskHelper(), cryptoService(), targetProvider());
106+
taskHelper(), cryptoService(), targetProvider(), dataLogger());
105107
}
106108

107109
@Bean
@@ -293,4 +295,10 @@ public TargetProvider targetProvider()
293295
{
294296
return new TargetProviderImpl(dsfClientProvider(), dsfClientConfig.getLocalConfig().getBaseUrl());
295297
}
298+
299+
@Bean
300+
public DataLogger dataLogger()
301+
{
302+
return new DataLoggerImpl(fhirContext());
303+
}
296304
}

dsf-bpe/dsf-bpe-process-api-v2/src/main/java/dev/dsf/bpe/v2/ProcessPluginApi.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import ca.uhn.fhir.context.FhirContext;
99
import dev.dsf.bpe.v2.config.ProxyConfig;
1010
import dev.dsf.bpe.v2.service.CryptoService;
11+
import dev.dsf.bpe.v2.service.DataLogger;
1112
import dev.dsf.bpe.v2.service.DsfClientProvider;
1213
import dev.dsf.bpe.v2.service.EndpointProvider;
1314
import dev.dsf.bpe.v2.service.FhirClientProvider;
@@ -61,4 +62,6 @@ public interface ProcessPluginApi
6162
CryptoService getCryptoService();
6263

6364
TargetProvider getTargetProvider();
65+
66+
DataLogger getDataLogger();
6467
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package dev.dsf.bpe.v2.service;
2+
3+
import org.hl7.fhir.r4.model.Resource;
4+
5+
/**
6+
* Logs data to the <code>log/bpe-data.log</code> file if enabled via environment variable
7+
* (<code>DEV_DSF_LOG_DATA: true</code>) or property (<code>dev.dsf.log.data=true</code>)
8+
*/
9+
public interface DataLogger
10+
{
11+
/**
12+
* If data logging is enabled, logs message and object with debug level. The FHIR resource is serialized as json.
13+
* Does nothing if the given <b>message</b> is <code>null</code>.
14+
*
15+
* @param message
16+
* not <code>null</code>
17+
* @param resource
18+
* may be <code>null</code>
19+
* @see #isEnabled()
20+
*/
21+
void log(String message, Resource resource);
22+
23+
/**
24+
* If data logging is enabled, logs message and object with debug level. The object is serialized by calling
25+
* {@link String#valueOf(Object)}. Does nothing if the given <b>message</b> is <code>null</code>.
26+
*
27+
* @param message
28+
* not <code>null</code>
29+
* @param object
30+
* may be <code>null</code>
31+
* @see #isEnabled()
32+
*/
33+
void log(String message, Object object);
34+
35+
/**
36+
* @return <code>true</code> if data logging is enabled
37+
*/
38+
boolean isEnabled();
39+
}

dsf-bpe/dsf-bpe-server-jetty/src/main/java/dev/dsf/bpe/BpeJettyServer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55

66
import dev.dsf.bpe.config.BpeDbMigratorConfig;
77
import dev.dsf.bpe.config.BpeHttpJettyConfig;
8+
import dev.dsf.bpe.logging.BpeLog4jInitializer;
89
import dev.dsf.common.db.migration.DbMigrator;
910
import dev.dsf.common.jetty.JettyServer;
10-
import dev.dsf.common.logging.Log4jInitializer;
1111

1212
public final class BpeJettyServer
1313
{
@@ -16,7 +16,7 @@ public final class BpeJettyServer
1616
SLF4JBridgeHandler.removeHandlersForRootLogger();
1717
SLF4JBridgeHandler.install();
1818

19-
new Log4jInitializer("bpe").initializeLog4j();
19+
new BpeLog4jInitializer().initializeLog4j();
2020
}
2121

2222
private BpeJettyServer()

dsf-bpe/dsf-bpe-server-jetty/src/main/java/dev/dsf/bpe/BpeJettyServerHttps.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55

66
import dev.dsf.bpe.config.BpeDbMigratorConfig;
77
import dev.dsf.bpe.config.BpeHttpsJettyConfig;
8+
import dev.dsf.bpe.logging.BpeLog4jInitializer;
89
import dev.dsf.common.db.migration.DbMigrator;
910
import dev.dsf.common.jetty.JettyServer;
10-
import dev.dsf.common.logging.Log4jInitializer;
1111

1212
public final class BpeJettyServerHttps
1313
{
@@ -16,7 +16,7 @@ public final class BpeJettyServerHttps
1616
SLF4JBridgeHandler.removeHandlersForRootLogger();
1717
SLF4JBridgeHandler.install();
1818

19-
new Log4jInitializer("bpe").initializeLog4j();
19+
new BpeLog4jInitializer().initializeLog4j();
2020
}
2121

2222
private BpeJettyServerHttps()
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package dev.dsf.bpe.logging;
2+
3+
import java.util.EnumSet;
4+
5+
import org.apache.logging.log4j.Level;
6+
import org.apache.logging.log4j.core.Appender;
7+
import org.apache.logging.log4j.core.LoggerContext;
8+
import org.apache.logging.log4j.core.appender.ConsoleAppender;
9+
import org.apache.logging.log4j.core.appender.ConsoleAppender.Target;
10+
import org.apache.logging.log4j.core.appender.RollingFileAppender;
11+
import org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
12+
import org.apache.logging.log4j.core.appender.rolling.OnStartupTriggeringPolicy;
13+
import org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
14+
import org.apache.logging.log4j.core.layout.PatternLayout;
15+
16+
import dev.dsf.common.logging.Log4jConfiguration;
17+
18+
public class BpeLog4jConfiguration extends Log4jConfiguration
19+
{
20+
private static final PatternLayout DATA_LAYOUT = PatternLayout.newBuilder().withPattern("%d%notEmpty{ %X} %m%n")
21+
.build();
22+
23+
public static enum Data
24+
{
25+
OUT(Target.SYSTEM_OUT), ERROR(Target.SYSTEM_ERR), FILE(null), OFF(null);
26+
27+
private final Target target;
28+
29+
private Data(Target target)
30+
{
31+
this.target = target;
32+
}
33+
34+
public Target getTarget()
35+
{
36+
return target;
37+
}
38+
}
39+
40+
public BpeLog4jConfiguration(LoggerContext loggerContext, String name, String fileNamePart,
41+
Log4jLayout consoleLayout, Level consoleLevel, Log4jLayout fileLayout, Level fileLevel, Data data)
42+
{
43+
super(loggerContext, name, fileNamePart, consoleLayout, consoleLevel, fileLayout, fileLevel);
44+
45+
if (EnumSet.of(Data.OUT, Data.ERROR, Data.FILE).contains(data))
46+
{
47+
Appender dataAppender = Data.FILE.equals(data) ? createFileAppender(fileNamePart)
48+
: createConsoleAppender(data);
49+
50+
addAppender(dataAppender);
51+
addLogger("dsf-data-logger", Level.DEBUG, dataAppender, false);
52+
}
53+
else
54+
addLogger("dsf-data-logger", Level.OFF);
55+
}
56+
57+
private Appender createFileAppender(String fileNamePart)
58+
{
59+
return RollingFileAppender.newBuilder().setName("DATA").withFileName("log/" + fileNamePart + "-data.log")
60+
.withFilePattern("log/" + fileNamePart + "-data_%d{yyyy-MM-dd}_%i.log.gz").setIgnoreExceptions(false)
61+
.setLayout(DATA_LAYOUT)
62+
.withPolicy(CompositeTriggeringPolicy.createPolicy(OnStartupTriggeringPolicy.createPolicy(1),
63+
TimeBasedTriggeringPolicy.newBuilder().build()))
64+
.build();
65+
}
66+
67+
private Appender createConsoleAppender(Data data)
68+
{
69+
return ConsoleAppender.newBuilder().setName("DATA").setTarget(data.getTarget()).setLayout(DATA_LAYOUT).build();
70+
}
71+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package dev.dsf.bpe.logging;
2+
3+
import dev.dsf.bpe.logging.BpeLog4jConfiguration.Data;
4+
import dev.dsf.common.logging.Log4jConfigurationFactory;
5+
import dev.dsf.common.logging.Log4jInitializer;
6+
7+
public class BpeLog4jInitializer extends Log4jInitializer
8+
{
9+
public static final String DATA_OUT = "SYS_OUT";
10+
public static final String DATA_ERROR = "SYS_ERROR";
11+
public static final String DATA_FILE = "FILE";
12+
public static final String DATA_OFF = "OFF";
13+
14+
public static final String LOG_DATA = "dev.dsf.log.data";
15+
16+
private final Data data;
17+
18+
public BpeLog4jInitializer()
19+
{
20+
data = getData(LOG_DATA, DATA_FILE);
21+
}
22+
23+
@Override
24+
protected Log4jConfigurationFactory createLog4jConfigurationFactory()
25+
{
26+
return new Log4jConfigurationFactory((loggerContext, name) -> new BpeLog4jConfiguration(loggerContext, name,
27+
"bpe", consoleLayout, consoleLevel, fileLayout, fileLevel, data));
28+
}
29+
30+
private Data getData(String parameter, String defaultValue)
31+
{
32+
String value = getValue(parameter, defaultValue);
33+
34+
if (DATA_OUT.equalsIgnoreCase(value))
35+
return Data.OUT;
36+
else if (DATA_ERROR.equalsIgnoreCase(value))
37+
return Data.ERROR;
38+
else if (DATA_FILE.equalsIgnoreCase(value))
39+
return Data.FILE;
40+
else if (DATA_OFF.equalsIgnoreCase(value))
41+
return Data.OFF;
42+
else
43+
throw new IllegalArgumentException("Data '" + value + "' for " + parameter + " not supported");
44+
}
45+
}

dsf-bpe/dsf-bpe-server/src/test/java/dev/dsf/bpe/integration/PluginV2IntegrationTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,4 +245,10 @@ public void startTargetProviderTest() throws Exception
245245
{
246246
executePluginTest(createTestTask("TargetProviderTest"));
247247
}
248+
249+
@Test
250+
public void startSensitiveDataLoggerTest() throws Exception
251+
{
252+
executePluginTest(createTestTask("DataLoggerTest"));
253+
}
248254
}

0 commit comments

Comments
 (0)