diff --git a/CHANGELOG.md b/CHANGELOG.md index fc482569ff0640cd4b12021185448c9836d834b0..bdedc677864430fc61ca4c06e86574c6e0765fcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added ### +* Configuration options `REST_RESPONSE_LOG_FORMAT` and + `GRPC_RESPONSE_LOG_FORMAT` which control the format and information included + in the log message of any response of the respective API. See + `conf/core/server.conf` for more information. + ### Changed ### ### Deprecated ### diff --git a/conf/core/log4j2-default.properties b/conf/core/log4j2-default.properties index 5983f8e33d51729c70cd3d685fe299aa13e8f27c..39f5f0ead11bb5ccfa9e39d3007d40ee8fa3077c 100644 --- a/conf/core/log4j2-default.properties +++ b/conf/core/log4j2-default.properties @@ -8,6 +8,10 @@ verbose = true property.LOG_DIR = log property.REQUEST_TIME_LOGGER_LEVEL = OFF +# the root logger has level "WARN" but we want to log the GRPC traffic in INFO level: +logger.grpc_response_log.name = org.caosdb.server.grpc.LoggingInterceptor +logger.grpc_response_log.level = INFO + ## appenders # stderr appender.stderr.type = Console diff --git a/conf/core/server.conf b/conf/core/server.conf index c030d6eb63d61ad2d9adc6a174877b1006396537..5df6c40ca04a9c6f22d03f61c937ab5fbeab565f 100644 --- a/conf/core/server.conf +++ b/conf/core/server.conf @@ -100,6 +100,21 @@ GRPC_SERVER_PORT_HTTPS=8443 # HTTP port of the grpc end-point GRPC_SERVER_PORT_HTTP= +# -------------------------------------------------- +# Response Log formatting (this cannot be configured by the logging frame work +# and thus has to be configured here). +# -------------------------------------------------- + +# Logging format of the GRPC API. +# Known keys: user-agent, local-address, remote-address, method. +# 'OFF' turns off the logging. +GRPC_RESPONSE_LOG_FORMAT={method} {local-address} {remote-address} {user-agent} +# Logging format of the REST API. +# Known keys: see column "Variable name" at https://javadocs.restlet.talend.com/2.4/jse/api/index.html?org/restlet/util/Resolver.html +# 'OFF' turns off the logging. +# Leaving this empty means using restlet's default settings. +REST_RESPONSE_LOG_FORMAT= + # -------------------------------------------------- # HTTPS options # -------------------------------------------------- @@ -229,4 +244,4 @@ ENTITY_VERSIONING_ENABLED=true # Enabling the state machine extension -# EXT_STATE_ENTITY=ENABLE \ No newline at end of file +# EXT_STATE_ENTITY=ENABLE diff --git a/src/main/java/org/caosdb/server/CaosDBServer.java b/src/main/java/org/caosdb/server/CaosDBServer.java index 9daabaed65aa39a9be868567581588625aba7a53..05fb9485fdbd7b2a86b62e9b8ad18af5069f88c2 100644 --- a/src/main/java/org/caosdb/server/CaosDBServer.java +++ b/src/main/java/org/caosdb/server/CaosDBServer.java @@ -894,6 +894,13 @@ class CaosDBComponent extends Component { public CaosDBComponent() { super(); + String responseLogFormat = + CaosDBServer.getServerProperty(ServerProperties.KEY_REST_RESPONSE_LOG_FORMAT); + if ("OFF".equalsIgnoreCase(responseLogFormat)) { + getLogService().setEnabled(false); + } else if (responseLogFormat != null && !responseLogFormat.isEmpty()) { + getLogService().setResponseLogFormat(responseLogFormat); + } setName(CaosDBServer.getServerProperty(ServerProperties.KEY_SERVER_NAME)); setOwner(CaosDBServer.getServerProperty(ServerProperties.KEY_SERVER_OWNER)); } diff --git a/src/main/java/org/caosdb/server/ServerProperties.java b/src/main/java/org/caosdb/server/ServerProperties.java index d58250242f691498288d765dd252986eda7fb09f..93a0c7473be1c31565e4b159ba55e01d557687e7 100644 --- a/src/main/java/org/caosdb/server/ServerProperties.java +++ b/src/main/java/org/caosdb/server/ServerProperties.java @@ -150,6 +150,8 @@ public class ServerProperties extends Properties implements Observable { public static final String KEY_PASSWORD_STRENGTH_REGEX = "PASSWORD_VALID_REGEX"; public static final String KEY_PASSWORD_WEAK_MESSAGE = "PASSWORD_INVALID_MESSAGE"; + public static final String KEY_REST_RESPONSE_LOG_FORMAT = "REST_RESPONSE_LOG_FORMAT"; + public static final String KEY_GRPC_RESPONSE_LOG_FORMAT = "GRPC_RESPONSE_LOG_FORMAT"; /** * Read the config files and initialize the server properties. diff --git a/src/main/java/org/caosdb/server/grpc/LoggingInterceptor.java b/src/main/java/org/caosdb/server/grpc/LoggingInterceptor.java index 9edd35090659e908ecf7f3fb502d34c36ac7e829..4e52485d4af4357b90a560baee6095c3b14683ae 100644 --- a/src/main/java/org/caosdb/server/grpc/LoggingInterceptor.java +++ b/src/main/java/org/caosdb/server/grpc/LoggingInterceptor.java @@ -1,5 +1,6 @@ package org.caosdb.server.grpc; +import io.grpc.Attributes.Key; import io.grpc.Context; import io.grpc.Contexts; import io.grpc.Metadata; @@ -7,18 +8,70 @@ import io.grpc.ServerCall; import io.grpc.ServerCall.Listener; import io.grpc.ServerCallHandler; import io.grpc.ServerInterceptor; +import java.net.SocketAddress; +import org.caosdb.server.CaosDBServer; +import org.caosdb.server.ServerProperties; +import org.restlet.routing.Template; +import org.restlet.util.Resolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +class CallResolver<ReqT, RespT> extends Resolver<String> { + + private ServerCall<ReqT, RespT> call; + private Metadata headers; + + public static final Metadata.Key<String> KEY_USER_AGENT = + Metadata.Key.of("user-agent", Metadata.ASCII_STRING_MARSHALLER); + public static final Key<SocketAddress> KEY_LOCAL_ADDRESS = io.grpc.Grpc.TRANSPORT_ATTR_LOCAL_ADDR; + public static final Key<SocketAddress> KEY_REMOTE_ADDRESS = + io.grpc.Grpc.TRANSPORT_ATTR_REMOTE_ADDR; + + public CallResolver( + ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) { + this.call = call; + this.headers = headers; + } + + @Override + public String resolve(String name) { + switch (name) { + case "user-agent": + return headers.get(KEY_USER_AGENT); + case "remote-address": + return call.getAttributes().get(KEY_REMOTE_ADDRESS).toString(); + case "local-address": + return call.getAttributes().get(KEY_LOCAL_ADDRESS).toString(); + case "method": + return call.getMethodDescriptor().getFullMethodName(); + default: + break; + } + return null; + } +} + public class LoggingInterceptor implements ServerInterceptor { + private Template template; + + public LoggingInterceptor() { + String format = CaosDBServer.getServerProperty(ServerProperties.KEY_GRPC_RESPONSE_LOG_FORMAT); + if ("OFF".equalsIgnoreCase(format)) { + this.template = null; + } else if (format != null) { + this.template = new Template(format); + } + } + private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class.getName()); @Override public <ReqT, RespT> Listener<ReqT> interceptCall( ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) { - - logger.info(call.getMethodDescriptor().getFullMethodName() + " - " + call.getAttributes()); + if (template != null) { + logger.info(template.format(new CallResolver<ReqT, RespT>(call, headers, next))); + } return Contexts.interceptCall(Context.current(), call, headers, next); } } diff --git a/src/main/java/org/caosdb/server/logging/log4j/CustomConfigurationFactory.java b/src/main/java/org/caosdb/server/logging/log4j/CustomConfigurationFactory.java index 62722317f882dffae4168808514a6d972ae8bfe6..4416227f9672a9b3be3ffb34306e78de04a20a2f 100644 --- a/src/main/java/org/caosdb/server/logging/log4j/CustomConfigurationFactory.java +++ b/src/main/java/org/caosdb/server/logging/log4j/CustomConfigurationFactory.java @@ -54,7 +54,7 @@ public class CustomConfigurationFactory extends PropertiesConfigurationFactory { LOGGER.debug("Reconfiguration is done by {}", getClass().toString()); List<String> sources = getConfigFiles(); - if (sources.size() > 1) { + if (sources.size() > 0) { final List<AbstractConfiguration> configs = new ArrayList<>(); for (final String sourceLocation : sources) { LOGGER.debug("Reconfigure with {}", sourceLocation);