|
1 | 1 | package com.sap.hcp.cf.logging.servlet.dynlog;
|
2 | 2 |
|
| 3 | +import java.security.interfaces.RSAPublicKey; |
3 | 4 | import java.util.Arrays;
|
4 | 5 | import java.util.List;
|
5 | 6 |
|
6 |
| -import javax.servlet.http.HttpServletRequest; |
7 |
| - |
8 | 7 | import org.slf4j.Logger;
|
9 | 8 | import org.slf4j.LoggerFactory;
|
10 | 9 | import org.slf4j.MDC;
|
|
17 | 16 | * HTTP-request-header. If this token is provided and does contain a correct
|
18 | 17 | * signature, valid timestamps and a log-level-value, the log-level for the
|
19 | 18 | * thread triggered by this request will be changed to the provided value.
|
| 19 | + * |
| 20 | + * You can extend this processor to extract custom claims from the JWT. Override |
| 21 | + * {@link DynamicLogLevelProcessor#processJWT(DecodedJWT)} for this. |
20 | 22 | */
|
21 | 23 | public class DynamicLogLevelProcessor {
|
22 | 24 |
|
23 | 25 | private final static Logger LOGGER = LoggerFactory.getLogger(DynamicLogLevelProcessor.class);
|
24 | 26 | private static final List<String> ALLOWED_DYNAMIC_LOGLEVELS = Arrays.asList("TRACE", "DEBUG", "INFO", "WARN",
|
25 | 27 | "ERROR");
|
26 | 28 | private final TokenDecoder tokenDecoder;
|
27 |
| - private final DynLogEnvironment dynLogEnvironment; |
28 | 29 |
|
29 |
| - public DynamicLogLevelProcessor(DynLogEnvironment dynLogEnvironment) { |
30 |
| - this.dynLogEnvironment = dynLogEnvironment; |
31 |
| - this.tokenDecoder = new TokenDecoder(dynLogEnvironment.getRsaPublicKey()); |
| 30 | + /** |
| 31 | + * @deprecated Use |
| 32 | + * {@link DynamicLogLevelProcessor#DynamicLogLevelProcessor(RSAPublicKey)} |
| 33 | + * instead. |
| 34 | + * @param dynLogConfig |
| 35 | + * the {@link DynLogConfiguration} to read the public RSA key for |
| 36 | + * JWT validation from. |
| 37 | + */ |
| 38 | + @Deprecated |
| 39 | + public DynamicLogLevelProcessor(DynLogConfiguration dynLogConfig) { |
| 40 | + this(dynLogConfig.getRsaPublicKey()); |
| 41 | + } |
| 42 | + |
| 43 | + public DynamicLogLevelProcessor(RSAPublicKey publicJwtKey) { |
| 44 | + this.tokenDecoder = new TokenDecoder(publicJwtKey); |
32 | 45 | }
|
33 | 46 |
|
34 |
| - public void copyDynamicLogLevelToMDC(HttpServletRequest httpRequest) { |
35 |
| - String logLevelToken = httpRequest.getHeader(dynLogEnvironment.getDynLogHeaderKey()); |
| 47 | + /** |
| 48 | + * Decodes and validate the JWT. Configures the dynamic log levels by |
| 49 | + * setting the corresponding fields in the MDC. |
| 50 | + * |
| 51 | + * @param logLevelToken |
| 52 | + * the HTTP Header containing the JWT for dynamic log levels |
| 53 | + */ |
| 54 | + public void copyDynamicLogLevelToMDC(String logLevelToken) { |
36 | 55 | if (logLevelToken == null) {
|
37 | 56 | return;
|
38 | 57 | } else {
|
39 | 58 | try {
|
40 | 59 | DecodedJWT jwt = tokenDecoder.validateAndDecodeToken(logLevelToken);
|
41 |
| - String dynamicLogLevel = jwt.getClaim("level").asString(); |
42 |
| - String packages = jwt.getClaim("packages").asString(); |
43 |
| - if (ALLOWED_DYNAMIC_LOGLEVELS.contains(dynamicLogLevel)) { |
44 |
| - MDC.put(DynamicLogLevelHelper.MDC_DYNAMIC_LOG_LEVEL_KEY, dynamicLogLevel); |
45 |
| - MDC.put(DynamicLogLevelHelper.MDC_DYNAMIC_LOG_LEVEL_PREFIXES, packages); |
46 |
| - } else { |
47 |
| - throw new DynamicLogLevelException("Dynamic Log-Level [" + dynamicLogLevel + |
48 |
| - "] provided in header is not valid. Allowed Values are " + |
49 |
| - ALLOWED_DYNAMIC_LOGLEVELS.toString()); |
50 |
| - } |
51 |
| - } catch (DynamicLogLevelException e) { |
52 |
| - LOGGER.warn("DynamicLogLevelProcessor could not write dynamic log level to MDC", e); |
| 60 | + processJWT(jwt); |
| 61 | + } catch (DynamicLogLevelException cause) { |
| 62 | + LOGGER.warn("DynamicLogLevelProcessor could not write dynamic log level to MDC", cause); |
53 | 63 | }
|
54 | 64 | }
|
55 | 65 | }
|
56 | 66 |
|
| 67 | + /** |
| 68 | + * Extracts the relevant claims for dynamic log level configuration from the |
| 69 | + * decoded token. In case of faulty content, i.e. unknown log level a |
| 70 | + * {@link DynamicLogLevelException} is thrown. You can override this method |
| 71 | + * to implement own interaction with the JWT, e.g. extraction and validation |
| 72 | + * of additional claims. |
| 73 | + * |
| 74 | + * @param jwt |
| 75 | + * the decoded JWT from the HTTP header |
| 76 | + * @throws DynamicLogLevelException |
| 77 | + * if validation of JWT claims fail |
| 78 | + */ |
| 79 | + protected void processJWT(DecodedJWT jwt) throws DynamicLogLevelException { |
| 80 | + String dynamicLogLevel = jwt.getClaim("level").asString(); |
| 81 | + String packages = jwt.getClaim("packages").asString(); |
| 82 | + if (ALLOWED_DYNAMIC_LOGLEVELS.contains(dynamicLogLevel)) { |
| 83 | + MDC.put(DynamicLogLevelHelper.MDC_DYNAMIC_LOG_LEVEL_KEY, dynamicLogLevel); |
| 84 | + MDC.put(DynamicLogLevelHelper.MDC_DYNAMIC_LOG_LEVEL_PREFIXES, packages); |
| 85 | + } else { |
| 86 | + throw new DynamicLogLevelException("Dynamic Log-Level [" + dynamicLogLevel + |
| 87 | + "] provided in header is not valid. Allowed Values are " + |
| 88 | + ALLOWED_DYNAMIC_LOGLEVELS.toString()); |
| 89 | + } |
| 90 | + } |
| 91 | + |
| 92 | + /** |
| 93 | + * Resets the current dynamic log level configuration by removing the |
| 94 | + * corresponding fields from the MDC. This needs to be called to remove the |
| 95 | + * changed log level configuration. |
| 96 | + */ |
57 | 97 | public void removeDynamicLogLevelFromMDC() {
|
58 | 98 | MDC.remove(DynamicLogLevelHelper.MDC_DYNAMIC_LOG_LEVEL_KEY);
|
| 99 | + MDC.remove(DynamicLogLevelHelper.MDC_DYNAMIC_LOG_LEVEL_PREFIXES); |
59 | 100 | }
|
60 | 101 | }
|
0 commit comments