From 5467c24568ea7b1b022efc2da1038b9ce3a53adb Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Thu, 12 Jan 2023 20:22:37 +0100 Subject: [PATCH 01/33] OSP-55 - RequestResponseLogger memoria tuning --- .../DefaultLoggerClientResponseFilter.java | 2 +- .../coffee/rest/log/BaseRestLogger.java | 58 ++++++++-- .../rest/log/RequestResponseLogger.java | 46 +++++++- .../stream/RequestLoggerInputStream.java | 102 ++++++++++++++++++ 4 files changed, 193 insertions(+), 15 deletions(-) create mode 100644 coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java diff --git a/coffee-module/coffee-module-mp/coffee-module-mp-restclient/src/main/java/hu/icellmobilsoft/coffee/module/mp/restclient/provider/DefaultLoggerClientResponseFilter.java b/coffee-module/coffee-module-mp/coffee-module-mp-restclient/src/main/java/hu/icellmobilsoft/coffee/module/mp/restclient/provider/DefaultLoggerClientResponseFilter.java index bd6373822..fb592e594 100644 --- a/coffee-module/coffee-module-mp/coffee-module-mp-restclient/src/main/java/hu/icellmobilsoft/coffee/module/mp/restclient/provider/DefaultLoggerClientResponseFilter.java +++ b/coffee-module/coffee-module-mp/coffee-module-mp-restclient/src/main/java/hu/icellmobilsoft/coffee/module/mp/restclient/provider/DefaultLoggerClientResponseFilter.java @@ -171,7 +171,7 @@ private int getMaxResponseEntityLogSize(ClientRequestContext requestContext, Cli if (maxResponseEntityLogSize != LogSpecifier.NO_LOG && // byte-code betoltesi fajlokat ne loggoljuk ki egeszben Objects.equals(responseContext.getMediaType(), MediaType.APPLICATION_OCTET_STREAM_TYPE)) { - maxResponseEntityLogSize = RequestResponseLogger.BYTECODE_MAX_LOG; + maxResponseEntityLogSize = RequestResponseLogger.ENTITY_MAX_LOG; } return maxResponseEntityLogSize; diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java index cc29fdd66..62c50f90b 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java @@ -43,6 +43,7 @@ import hu.icellmobilsoft.coffee.rest.log.annotation.enumeration.LogSpecifierTarget; import hu.icellmobilsoft.coffee.rest.utils.RestLoggerUtil; import hu.icellmobilsoft.coffee.se.logging.mdc.MDC; +import hu.icellmobilsoft.coffee.tool.utils.stream.RequestLoggerInputStream; import hu.icellmobilsoft.coffee.tool.utils.string.RandomUtil; /** @@ -74,7 +75,8 @@ public abstract class BaseRestLogger implements ContainerRequestFilter, WriterIn public void filter(ContainerRequestContext requestContext) throws IOException { MDC.clear(); MDC.put(LogConstants.LOG_SERVICE_NAME, baseApplicationContainer.getCoffeeAppName()); - processRequest(requestContext); + // processRequest(requestContext); + processRequestNew(requestContext); } /** {@inheritDoc} */ @@ -94,17 +96,53 @@ protected String processRequest(ContainerRequestContext requestContext) { if (RestLoggerUtil.logDisabled(requestContext, LogSpecifierTarget.REQUEST)) { return null; } + Runtime runtime = Runtime.getRuntime(); + long freeMemoryBefore = runtime.maxMemory() - runtime.totalMemory() + runtime.freeMemory(); + log.info("freeMemoryBefore = {0}", freeMemoryBefore); - StringBuffer message = new StringBuffer(); - printRequestLine(message, requestContext); - printRequestHeaders(message, requestContext); + StringBuilder message = new StringBuilder(); + appendRequestLine(message, requestContext); + appendRequestHeaders(message, requestContext); printRequestEntity(message, requestContext); + long freeMemoryAfter = runtime.maxMemory() - runtime.totalMemory() + runtime.freeMemory(); + log.info("freeMemoryAfter = {0}", freeMemoryAfter); String messageString = message.toString(); log.info(message.toString()); return messageString; } + /** + * Processes HTTP request. + * + * @param requestContext + * context + */ + protected void processRequestNew(ContainerRequestContext requestContext) { + if (RestLoggerUtil.logDisabled(requestContext, LogSpecifierTarget.REQUEST)) { + return; + } + + Runtime runtime = Runtime.getRuntime(); + long freeMemoryBefore = runtime.maxMemory() - runtime.totalMemory() + runtime.freeMemory(); + log.info("freeMemoryBefore = {0}", freeMemoryBefore); + + StringBuilder message = new StringBuilder(); + appendRequestLine(message, requestContext); + appendRequestHeaders(message, requestContext); + + int maxRequestEntityLogSize = requestResponseLogger.getMaxRequestEntityLogSize(requestContext); + + RequestLoggerInputStream requestLoggerInputStream = new RequestLoggerInputStream(requestContext.getEntityStream(), maxRequestEntityLogSize, + RequestResponseLogger.REQUEST_PREFIX, message); + + // a saját InputStream-et állítjuk be a context-be, hogy majd az entity stream olvasáskor tudjuk log-olni a request-et + requestContext.setEntityStream(requestLoggerInputStream); + + long freeMemoryAfter = runtime.maxMemory() - runtime.totalMemory() + runtime.freeMemory(); + log.info("freeMemoryAfter = {0}", freeMemoryAfter); + } + /** * Processes HTTP response. * @@ -163,7 +201,7 @@ protected String processResponse(WriterInterceptorContext context) throws IOExce public abstract String sessionKey(); /** - * Prints request headers from {@link ContainerRequestContext} and appends given {@link StringBuffer} with the print result. + * Prints request headers from {@link ContainerRequestContext} and appends given {@link StringBuilder} with the print result. * * @param b * request message @@ -171,7 +209,7 @@ protected String processResponse(WriterInterceptorContext context) throws IOExce * context * @see RequestResponseLogger#printRequestHeaders(java.util.Map) */ - protected void printRequestHeaders(StringBuffer b, ContainerRequestContext requestContext) { + protected void appendRequestHeaders(StringBuilder b, ContainerRequestContext requestContext) { b.append(requestResponseLogger.printRequestHeaders(requestContext.getHeaders())); String sessionId = null; if (requestContext.getHeaders().containsKey(sessionKey())) { @@ -181,7 +219,7 @@ protected void printRequestHeaders(StringBuffer b, ContainerRequestContext reque } /** - * Prints http path info from {@link ContainerRequestContext} and appends given {@link StringBuffer} with the print result. + * Prints http path info from {@link ContainerRequestContext} and appends given {@link StringBuilder} with the print result. * * @param b * request message @@ -189,12 +227,12 @@ protected void printRequestHeaders(StringBuffer b, ContainerRequestContext reque * context * @see RequestResponseLogger#printRequestLine(ContainerRequestContext) */ - protected void printRequestLine(StringBuffer b, ContainerRequestContext requestContext) { + protected void appendRequestLine(StringBuilder b, ContainerRequestContext requestContext) { b.append(requestResponseLogger.printRequestLine(requestContext)); } /** - * Prints http entity from {@link ContainerRequestContext} and appends given {@link StringBuffer} with the print result. + * Prints http entity from {@link ContainerRequestContext} and appends given {@link StringBuilder} with the print result. * * @param b * request message @@ -202,7 +240,7 @@ protected void printRequestLine(StringBuffer b, ContainerRequestContext requestC * context * @see RequestResponseLogger#printRequestEntity(ContainerRequestContext) */ - protected void printRequestEntity(StringBuffer b, ContainerRequestContext requestContext) { + protected void printRequestEntity(StringBuilder b, ContainerRequestContext requestContext) { b.append(requestResponseLogger.printRequestEntity(requestContext)); } diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java index 609a9cacd..8e68a2c29 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java @@ -69,8 +69,8 @@ public class RequestResponseLogger { /** Constant RESPONSE_PREFIX="< " */ public static final String RESPONSE_PREFIX = "< "; - /** Constant BYTECODE_MAX_LOG=5000 */ - public static final int BYTECODE_MAX_LOG = 5000; + /** Constant ENTITY_MAX_LOG=5000 */ + public static final int ENTITY_MAX_LOG = 5000; /** Constant SKIP_MEDIATYPE_SUBTYPE_PDF="pdf" */ public static final String SKIP_MEDIATYPE_SUBTYPE_PDF = "pdf"; @@ -248,6 +248,22 @@ public String printEntity(byte[] entity, Integer maxLogSize, String prefix) thro return prefix + "entity: [" + maskedText + "]\n"; } + /** + * Prints request entity to {@link String}. Masks password. + * + * @param requestText + * entity string + * @param prefix + * prefix for log + * @return entity {@code String} + * @throws IOException + * if cannot be read + */ + public String printEntityNew(String requestText, String prefix) { + String maskedText = StringHelper.maskValueInXmlJson(requestText); + return prefix + "entity: [" + maskedText + "]\n"; + } + private String entityToString(byte[] entity, Integer maxLogSize) { if (entity == null) { return null; @@ -285,7 +301,7 @@ public String printRequestEntity(ContainerRequestContext requestContext) { if (maxRequestEntityLogSize != LogSpecifier.NO_LOG && // byte-code betoltesi fajlokat ne loggoljuk ki egeszben Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_OCTET_STREAM_TYPE)) { - maxRequestEntityLogSize = RequestResponseLogger.BYTECODE_MAX_LOG; + maxRequestEntityLogSize = RequestResponseLogger.ENTITY_MAX_LOG; } // vissza irjuk a kiolvasott streamet @@ -298,6 +314,28 @@ public String printRequestEntity(ContainerRequestContext requestContext) { } } + /** + * Returns the maximum entity log size + * + * @param requestContext + * context + * + * @return the maximum log size of the entity + */ + protected int getMaxRequestEntityLogSize(ContainerRequestContext requestContext) { + int maxRequestEntityLogSize = RestLoggerUtil.getMaxEntityLogSize(requestContext, LogSpecifierTarget.REQUEST); + if (maxRequestEntityLogSize != LogSpecifier.NO_LOG && + // byte-code betoltesi fajlokat, json-t és xml-t ne loggoljuk ki egeszben + Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_OCTET_STREAM_TYPE) + || Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_JSON_TYPE) + || Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_XML_TYPE)) { + maxRequestEntityLogSize = RequestResponseLogger.ENTITY_MAX_LOG; + + } + + return maxRequestEntityLogSize; + } + /** * Prints http entity from {@link HttpServletRequest}. * @@ -318,7 +356,7 @@ public String printRequestEntity(HttpServletRequest servletRequest) { // byte-code betoltesi fajlokat ne loggoljuk ki egeszben boolean logLimit = Objects.equals(servletRequest.getContentType(), MediaType.APPLICATION_OCTET_STREAM); - return printRequestEntity(requestEntity, logLimit ? RequestResponseLogger.BYTECODE_MAX_LOG : null); + return printRequestEntity(requestEntity, logLimit ? RequestResponseLogger.ENTITY_MAX_LOG : null); } catch (IllegalStateException e) { log.info("Inputstream is already readed from servletRequest: " + e.getLocalizedMessage(), e); } catch (IOException e) { diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java new file mode 100644 index 000000000..efa408b62 --- /dev/null +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java @@ -0,0 +1,102 @@ +/*- + * #%L + * Coffee + * %% + * Copyright (C) 2020 - 2023 i-Cell Mobilsoft Zrt. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package hu.icellmobilsoft.coffee.tool.utils.stream; + +import java.io.IOException; +import java.io.InputStream; + +import javax.enterprise.inject.Vetoed; + +import hu.icellmobilsoft.coffee.cdi.logger.AppLogger; +import hu.icellmobilsoft.coffee.cdi.logger.LogProducer; +import hu.icellmobilsoft.coffee.tool.utils.string.StringHelper; + +/** + * Custom {@link InputStream} for logging request with entity + * + * @author mate.biro + * @since 1.13.0 + */ +@Vetoed +public class RequestLoggerInputStream extends InputStream { + + private final InputStream inputStream; + private final String requestPrefix; + private final StringBuilder entity = new StringBuilder(); + private final StringBuilder message; + private int logReadLimit; + private boolean firstReadCycle = true; + + /** + * Constructor + * + * @param inputStream + * original inputStream + * @param logReadLimit + * original inputStream + * @param requestPrefix + * original inputStream + * @param message + * original inputStream + */ + public RequestLoggerInputStream(InputStream inputStream, int logReadLimit, String requestPrefix, StringBuilder message) { + this.inputStream = inputStream; + this.logReadLimit = logReadLimit; + this.requestPrefix = requestPrefix; + this.message = message; + } + + /** {@inheritDoc} */ + @Override + public int read() throws IOException { + int streamData = inputStream.read(); + + buildEntity(streamData); + logRequestWithEntity(streamData); + + return streamData; + + } + + private void buildEntity(int streamData) { + // logoláshoz gyűjtjük a stream tartalmát amíg van, vagy még nem értük el a limitet + if (!firstReadCycle || streamData == -1 && logReadLimit == 0) { + return; + } + entity.append((char) streamData); + logReadLimit--; + } + + private void logRequestWithEntity(int streamData) { + // ha a stream végére értünk vagy elértük a limitet, akkor logolunk + if (!firstReadCycle || streamData != -1 && logReadLimit != 0) { + return; + } + String maskedEntity = getMaskedEntity(entity.toString(), requestPrefix); + message.append(maskedEntity); + LogProducer.logToAppLogger((AppLogger appLogger) -> appLogger.info(message.toString()), RequestLoggerInputStream.class); + firstReadCycle = false; + } + + private String getMaskedEntity(String requestText, String prefix) { + String maskedText = StringHelper.maskValueInXmlJson(requestText); + return prefix + "entity: [" + maskedText + "]\n"; + } +} From 1f712886ecb0dc9a244dd4d2e0be79437c9d3c8f Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Mon, 16 Jan 2023 12:13:20 +0100 Subject: [PATCH 02/33] OSP-55 - RequestResponseLogger memoria tuning --- .../coffee/rest/log/BaseRestLogger.java | 97 ++++--------------- .../stream/RequestLoggerInputStream.java | 15 ++- .../ResponseEntityCollectorOutputStream.java | 69 +++++++++++++ 3 files changed, 100 insertions(+), 81 deletions(-) create mode 100644 coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java index 62c50f90b..7d4a2e03c 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java @@ -44,6 +44,7 @@ import hu.icellmobilsoft.coffee.rest.utils.RestLoggerUtil; import hu.icellmobilsoft.coffee.se.logging.mdc.MDC; import hu.icellmobilsoft.coffee.tool.utils.stream.RequestLoggerInputStream; +import hu.icellmobilsoft.coffee.tool.utils.stream.ResponseEntityCollectorOutputStream; import hu.icellmobilsoft.coffee.tool.utils.string.RandomUtil; /** @@ -75,8 +76,7 @@ public abstract class BaseRestLogger implements ContainerRequestFilter, WriterIn public void filter(ContainerRequestContext requestContext) throws IOException { MDC.clear(); MDC.put(LogConstants.LOG_SERVICE_NAME, baseApplicationContainer.getCoffeeAppName()); - // processRequest(requestContext); - processRequestNew(requestContext); + processRequest(requestContext); } /** {@inheritDoc} */ @@ -90,43 +90,12 @@ public void aroundWriteTo(WriterInterceptorContext context) throws IOException { * * @param requestContext * context - * @return HTTP request message or null if logging is disabled */ - protected String processRequest(ContainerRequestContext requestContext) { - if (RestLoggerUtil.logDisabled(requestContext, LogSpecifierTarget.REQUEST)) { - return null; - } - Runtime runtime = Runtime.getRuntime(); - long freeMemoryBefore = runtime.maxMemory() - runtime.totalMemory() + runtime.freeMemory(); - log.info("freeMemoryBefore = {0}", freeMemoryBefore); - - StringBuilder message = new StringBuilder(); - appendRequestLine(message, requestContext); - appendRequestHeaders(message, requestContext); - printRequestEntity(message, requestContext); - long freeMemoryAfter = runtime.maxMemory() - runtime.totalMemory() + runtime.freeMemory(); - log.info("freeMemoryAfter = {0}", freeMemoryAfter); - - String messageString = message.toString(); - log.info(message.toString()); - return messageString; - } - - /** - * Processes HTTP request. - * - * @param requestContext - * context - */ - protected void processRequestNew(ContainerRequestContext requestContext) { + protected void processRequest(ContainerRequestContext requestContext) { if (RestLoggerUtil.logDisabled(requestContext, LogSpecifierTarget.REQUEST)) { return; } - Runtime runtime = Runtime.getRuntime(); - long freeMemoryBefore = runtime.maxMemory() - runtime.totalMemory() + runtime.freeMemory(); - log.info("freeMemoryBefore = {0}", freeMemoryBefore); - StringBuilder message = new StringBuilder(); appendRequestLine(message, requestContext); appendRequestHeaders(message, requestContext); @@ -136,58 +105,45 @@ protected void processRequestNew(ContainerRequestContext requestContext) { RequestLoggerInputStream requestLoggerInputStream = new RequestLoggerInputStream(requestContext.getEntityStream(), maxRequestEntityLogSize, RequestResponseLogger.REQUEST_PREFIX, message); - // a saját InputStream-et állítjuk be a context-be, hogy majd az entity stream olvasáskor tudjuk log-olni a request-et + // a saját InputStream-et állítjuk be a context-be, ami majd az entity stream olvasáskor log-olja a request-et requestContext.setEntityStream(requestLoggerInputStream); - - long freeMemoryAfter = runtime.maxMemory() - runtime.totalMemory() + runtime.freeMemory(); - log.info("freeMemoryAfter = {0}", freeMemoryAfter); } /** * Processes HTTP response. - * + * * @param context * context - * @return HTTP response message or null if logging is disabled * @throws IOException * if response cannot be processed. */ - protected String processResponse(WriterInterceptorContext context) throws IOException { + protected void processResponse(WriterInterceptorContext context) throws IOException { if (RestLoggerUtil.logDisabled(context, LogSpecifierTarget.RESPONSE)) { context.proceed(); - return null; + return; } - StringBuffer message = new StringBuffer(); + StringBuilder message = new StringBuilder(); try { - printResponseLine(message, context); printResponseHeaders(message, context); OutputStream originalStream = context.getOutputStream(); - byte[] entityCopy = new byte[0]; + byte[] entity = new byte[0]; int maxResponseEntityLogSize = RestLoggerUtil.getMaxEntityLogSize(context, LogSpecifierTarget.RESPONSE); if (maxResponseEntityLogSize != LogSpecifier.NO_LOG) { - hu.icellmobilsoft.coffee.tool.utils.stream.OutputStreamCopier osc = new hu.icellmobilsoft.coffee.tool.utils.stream.OutputStreamCopier( - originalStream); - context.setOutputStream(osc); - // elegessuk a stream-et, kozben masoljuk a tartalmat - try { - context.proceed(); - } finally { - // IS: kerdeses erdemes-e vissza irni az eredeti stream-et... - context.setOutputStream(originalStream); - } - entityCopy = osc.getCopy(); + ResponseEntityCollectorOutputStream responseEntityCollectorOutputStream = new ResponseEntityCollectorOutputStream(originalStream); + context.setOutputStream(responseEntityCollectorOutputStream); + context.proceed(); + entity = responseEntityCollectorOutputStream.getEntityText().getBytes(); } else { context.proceed(); } - printResponseEntity(message, context, entityCopy); + printResponseEntity(message, context, entity); } finally { log.info(message.toString()); } - return message.toString(); } /** @@ -232,20 +188,7 @@ protected void appendRequestLine(StringBuilder b, ContainerRequestContext reques } /** - * Prints http entity from {@link ContainerRequestContext} and appends given {@link StringBuilder} with the print result. - * - * @param b - * request message - * @param requestContext - * context - * @see RequestResponseLogger#printRequestEntity(ContainerRequestContext) - */ - protected void printRequestEntity(StringBuilder b, ContainerRequestContext requestContext) { - b.append(requestResponseLogger.printRequestEntity(requestContext)); - } - - /** - * Prints response URL line and appends given {@link StringBuffer} with the print result. + * Prints response URL line and appends given {@link StringBuilder} with the print result. * * @param b * response message @@ -253,7 +196,7 @@ protected void printRequestEntity(StringBuilder b, ContainerRequestContext reque * context * @see RequestResponseLogger#printResponseLine(String, int, String, String) */ - protected void printResponseLine(StringBuffer b, WriterInterceptorContext context) { + protected void printResponseLine(StringBuilder b, WriterInterceptorContext context) { String fullPath = uriInfo.getAbsolutePath().toASCIIString(); int status = httpServletResponse.getStatus(); Status statusEnum = Status.fromStatusCode(status); @@ -263,7 +206,7 @@ protected void printResponseLine(StringBuffer b, WriterInterceptorContext contex } /** - * Prints response header values and appends given {@link StringBuffer} with the print result. + * Prints response header values and appends given {@link StringBuilder} with the print result. * * @param b * response message @@ -271,12 +214,12 @@ protected void printResponseLine(StringBuffer b, WriterInterceptorContext contex * context * @see RequestResponseLogger#printResponseHeaders(java.util.Map) */ - protected void printResponseHeaders(StringBuffer b, WriterInterceptorContext context) { + protected void printResponseHeaders(StringBuilder b, WriterInterceptorContext context) { b.append(requestResponseLogger.printResponseHeaders(context.getHeaders())); } /** - * Prints response from {@link WriterInterceptorContext} and appends given {@link StringBuffer} with the print result. + * Prints response from {@link WriterInterceptorContext} and appends given {@link StringBuilder} with the print result. * * @param b * response message @@ -286,7 +229,7 @@ protected void printResponseHeaders(StringBuffer b, WriterInterceptorContext con * entity * @see RequestResponseLogger#printResponseEntity(String, WriterInterceptorContext, byte[]) */ - protected void printResponseEntity(StringBuffer b, WriterInterceptorContext context, byte[] entityCopy) { + protected void printResponseEntity(StringBuilder b, WriterInterceptorContext context, byte[] entityCopy) { b.append(requestResponseLogger.printResponseEntity(uriInfo.getAbsolutePath().toASCIIString(), context, entityCopy)); } } diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java index efa408b62..88ab298ca 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java @@ -50,11 +50,11 @@ public class RequestLoggerInputStream extends InputStream { * @param inputStream * original inputStream * @param logReadLimit - * original inputStream + * read limit * @param requestPrefix - * original inputStream + * request log prefix * @param message - * original inputStream + * log message */ public RequestLoggerInputStream(InputStream inputStream, int logReadLimit, String requestPrefix, StringBuilder message) { this.inputStream = inputStream; @@ -63,7 +63,14 @@ public RequestLoggerInputStream(InputStream inputStream, int logReadLimit, Strin this.message = message; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + * + * Extra functionality: On first read cycle it appends the read request entity data from the original {@link InputStream} to an internal + * {@link StringBuilder} until a given limit is reached (or until the end of stream if limit is higher). Then logs the given request message with + * the appended request entity. + * + */ @Override public int read() throws IOException { int streamData = inputStream.read(); diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java new file mode 100644 index 000000000..eff9f5938 --- /dev/null +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java @@ -0,0 +1,69 @@ +/*- + * #%L + * Coffee + * %% + * Copyright (C) 2020 - 2023 i-Cell Mobilsoft Zrt. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package hu.icellmobilsoft.coffee.tool.utils.stream; + +import java.io.IOException; +import java.io.OutputStream; + +import javax.enterprise.inject.Vetoed; + +/** + * Custom {@link OutputStream} for collecting response entity + * + * @author mate.biro + * @since 1.13.0 + */ +@Vetoed +public class ResponseEntityCollectorOutputStream extends OutputStream { + + private final OutputStream outputStream; + private final StringBuilder entity = new StringBuilder(); + + /** + * Constructor + * + * @param outputStream + * original outputStream what we want to copy + */ + public ResponseEntityCollectorOutputStream(OutputStream outputStream) { + this.outputStream = outputStream; + + } + + /** + * {@inheritDoc} + * + * Extra functionality: It appends the response entity data written to the original {@link OutputStream} to an internal {@link StringBuilder}. + */ + @Override + public void write(int b) throws IOException { + entity.append((char) b); + outputStream.write(b); + } + + /** + * Returns the entity in {@link String} format. + * + * @return Entity text + */ + public String getEntityText() { + return entity.toString(); + } +} From 922f0c8329bf181f9c6110d9ec2682ccb77fa5b9 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Mon, 16 Jan 2023 13:59:40 +0100 Subject: [PATCH 03/33] OSP-55 - RequestResponseLogger memoria tuning --- .../coffee/rest/log/RequestResponseLogger.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java index 8e68a2c29..125806849 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java @@ -248,22 +248,6 @@ public String printEntity(byte[] entity, Integer maxLogSize, String prefix) thro return prefix + "entity: [" + maskedText + "]\n"; } - /** - * Prints request entity to {@link String}. Masks password. - * - * @param requestText - * entity string - * @param prefix - * prefix for log - * @return entity {@code String} - * @throws IOException - * if cannot be read - */ - public String printEntityNew(String requestText, String prefix) { - String maskedText = StringHelper.maskValueInXmlJson(requestText); - return prefix + "entity: [" + maskedText + "]\n"; - } - private String entityToString(byte[] entity, Integer maxLogSize) { if (entity == null) { return null; From 113a052ee9f1238ec87cad1bf02758904c1b12fe Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Mon, 16 Jan 2023 14:17:46 +0100 Subject: [PATCH 04/33] OSP-55 - RequestResponseLogger memoria tuning --- .../icellmobilsoft/coffee/rest/log/RequestResponseLogger.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java index 125806849..41f292ebb 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java @@ -312,7 +312,8 @@ protected int getMaxRequestEntityLogSize(ContainerRequestContext requestContext) // byte-code betoltesi fajlokat, json-t és xml-t ne loggoljuk ki egeszben Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_OCTET_STREAM_TYPE) || Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_JSON_TYPE) - || Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_XML_TYPE)) { + || Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_XML_TYPE) + || Objects.equals(requestContext.getMediaType(), MediaType.TEXT_XML_TYPE)) { maxRequestEntityLogSize = RequestResponseLogger.ENTITY_MAX_LOG; } From a5f4a874a1a525614f6cf0264b05b4176f94dece Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Mon, 16 Jan 2023 14:25:02 +0100 Subject: [PATCH 05/33] OSP-55 - RequestResponseLogger memoria tuning adoc --- docs/common/core/coffee-rest.adoc | 2 +- docs/migration/migration1120to1130.adoc | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/common/core/coffee-rest.adoc b/docs/common/core/coffee-rest.adoc index 1dee329c6..67f40bade 100644 --- a/docs/common/core/coffee-rest.adoc +++ b/docs/common/core/coffee-rest.adoc @@ -113,7 +113,7 @@ Jelenleg a LogSpecifier a következő esetekre van felkészítve: * a végponton a request-response logolása kikapcsolható a `LogSpecifier` annotáció `noLog` kapcsolójával. * a végponton a kilogolt body méretét a `LogSpecifier` annotáció `maxEntityLogSize` mezőjével lehet korlátozni. -IMPORTANT: ha a `maxEntityLogSize` `LogSpecifier.NO_LOG`-tól *eltérő* értékre van állítva, akkor a REST endpoint-hoz érkező `application/octet-stream` mediaType esetében csak a kérés első 5000 karaktere íródik ki. +IMPORTANT: ha a `maxEntityLogSize` `LogSpecifier.NO_LOG`-tól *eltérő* értékre van állítva, akkor a REST endpoint-hoz érkező `application/octet-stream`, `application/json`, `application/xml` és `text/xml` mediaType-ok esetében csak a kérés első 5000 karaktere íródik ki. .LogSpecifier példa [source,java] diff --git a/docs/migration/migration1120to1130.adoc b/docs/migration/migration1120to1130.adoc index 732d8f5fb..6d8474a8f 100644 --- a/docs/migration/migration1120to1130.adoc +++ b/docs/migration/migration1120to1130.adoc @@ -160,3 +160,11 @@ public class MyBean { Ezzel együtt a ProjectStage fajtái is lecsökkentek, és már csak Production, Development és Test lehetséges. Régi deltaspikeos alap projekt stage-ek bekerültek a Testbe, kivéve a Development és Productiont ami azonos néven maradt. Lásd `hu.icellmobilsoft.coffee.rest.projectstage.ProjectStageEnum`. Az eddig használt `org.apache.deltaspike.ProjectStage` konfiguráció használata megmaradt, és visszafelé a deltaspike által támogatott értékek is feldolgozásra kerülnek az enum értékeibe. + +=== coffee-rest + +* A `RequestResponseLogger` osztályban A `BYTECODE_MAX_LOG` konstans átvevezésre került `ENTITY_MAX_LOG`-ra, mivel a feltétel, ami alapján a request body log mérete korlátozva van kiegészült a meglévő `application/octet-stream` mellett `application/json`, `application/xml` és `text/xml` mediaType-okkal. + +==== Átállás + +* A `BYTECODE_MAX_LOG` konstans helyett `ENTITY_MAX_LOG`-ot kell használni. \ No newline at end of file From f8534b092d4903b5ede2eed244d6b201afab9d4a Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Mon, 16 Jan 2023 14:33:33 +0100 Subject: [PATCH 06/33] OSP-55 - RequestResponseLogger memoria tuning adoc --- docs/migration/migration1120to1130.adoc | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/migration/migration1120to1130.adoc b/docs/migration/migration1120to1130.adoc index 6d8474a8f..d303f2c52 100644 --- a/docs/migration/migration1120to1130.adoc +++ b/docs/migration/migration1120to1130.adoc @@ -136,6 +136,8 @@ A változtatások nem eredményeznek átállási munkálatokat, visszafelé komp * Deltaspike álltal nyújtott ProjectStage leváltásra került egy coffee-ba implementált egyszerűsített változatra. * BaseApplicationContainer-ből a COFFEE_APP_NAME etcd kulcs átkerült az IConfigKey interface-be, ahol így dokumentálódik is. +* A `BaseRestLogger` osztály optimalizáláson esett át, aminek eredményeképpen az alkalmazások kevesebb memóriát használnak fel a request és response body log-olás során. +* A `RequestResponseLogger` osztályban A `BYTECODE_MAX_LOG` konstans átvevezésre került `ENTITY_MAX_LOG`-ra, mivel a feltétel, ami alapján a request body log mérete korlátozva van kiegészült a meglévő `application/octet-stream` mellett `application/json`, `application/xml` és `text/xml` mediaType-okkal. ==== Átállás @@ -161,10 +163,4 @@ Ezzel együtt a ProjectStage fajtái is lecsökkentek, és már csak Production, Az eddig használt `org.apache.deltaspike.ProjectStage` konfiguráció használata megmaradt, és visszafelé a deltaspike által támogatott értékek is feldolgozásra kerülnek az enum értékeibe. -=== coffee-rest - -* A `RequestResponseLogger` osztályban A `BYTECODE_MAX_LOG` konstans átvevezésre került `ENTITY_MAX_LOG`-ra, mivel a feltétel, ami alapján a request body log mérete korlátozva van kiegészült a meglévő `application/octet-stream` mellett `application/json`, `application/xml` és `text/xml` mediaType-okkal. - -==== Átállás - -* A `BYTECODE_MAX_LOG` konstans helyett `ENTITY_MAX_LOG`-ot kell használni. \ No newline at end of file +* A `BYTECODE_MAX_LOG` konstans helyett `ENTITY_MAX_LOG`-ot kell használni. From cacd874b226ed6330f2a5acabefbd454cdd3c2fc Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Mon, 16 Jan 2023 15:14:27 +0100 Subject: [PATCH 07/33] OSP-55 - RequestResponseLogger memoria tuning javadoc fix --- .../coffee/tool/utils/stream/OutputStreamCopier.java | 2 +- .../tool/utils/stream/ResponseEntityCollectorOutputStream.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/OutputStreamCopier.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/OutputStreamCopier.java index f0ef53fbc..30ce496b4 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/OutputStreamCopier.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/OutputStreamCopier.java @@ -58,7 +58,7 @@ public class OutputStreamCopier extends OutputStream { * Constructor * * @param outputStream - * original outputStream what we want to copy + * original outputStream */ public OutputStreamCopier(OutputStream outputStream) { this.outputStream = outputStream; diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java index eff9f5938..2a624cc35 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java @@ -40,7 +40,7 @@ public class ResponseEntityCollectorOutputStream extends OutputStream { * Constructor * * @param outputStream - * original outputStream what we want to copy + * original outputStream */ public ResponseEntityCollectorOutputStream(OutputStream outputStream) { this.outputStream = outputStream; From faab11b72ba5af0220286cfdc433620cb9f83308 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Mon, 16 Jan 2023 15:30:46 +0100 Subject: [PATCH 08/33] OSP-55 - RequestResponseLogger memoria tuning unused method --- .../rest/log/RequestResponseLogger.java | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java index 41f292ebb..0a31a7a6e 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java @@ -264,40 +264,6 @@ private String entityToString(byte[] entity, Integer maxLogSize) { return new String(requestEntityPart, StandardCharsets.UTF_8); } - /** - * Prints http entity from {@link ContainerRequestContext}. - * - * @param requestContext - * context - * @return HTTP entity or null if invalid parameter or exception when reading the entity - */ - public String printRequestEntity(ContainerRequestContext requestContext) { - if (requestContext == null) { - return null; - } - ByteArrayOutputStream out = new ByteArrayOutputStream(); - InputStream in = requestContext.getEntityStream(); - try { - IOUtils.copy(in, out); - - byte[] requestEntity = out.toByteArray(); - int maxRequestEntityLogSize = RestLoggerUtil.getMaxEntityLogSize(requestContext, LogSpecifierTarget.REQUEST); - if (maxRequestEntityLogSize != LogSpecifier.NO_LOG && - // byte-code betoltesi fajlokat ne loggoljuk ki egeszben - Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_OCTET_STREAM_TYPE)) { - maxRequestEntityLogSize = RequestResponseLogger.ENTITY_MAX_LOG; - - } - // vissza irjuk a kiolvasott streamet - requestContext.setEntityStream(new ByteArrayInputStream(requestEntity)); - - return printRequestEntity(requestEntity, maxRequestEntityLogSize); - } catch (IOException e) { - log.error("Error in logging request entity: " + e.getLocalizedMessage(), e); - return null; - } - } - /** * Returns the maximum entity log size * From f387cb5a28b877f16c2d2ea2265b23f017ecce4b Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Wed, 18 Jan 2023 10:16:41 +0100 Subject: [PATCH 09/33] OSP-55 - sonatype-lift fixes --- .../icellmobilsoft/coffee/rest/log/BaseRestLogger.java | 10 ++++++---- .../coffee/rest/log/RequestResponseLogger.java | 9 ++++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java index 7d4a2e03c..9cf61ebc1 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.OutputStream; +import java.nio.charset.StandardCharsets; import jakarta.inject.Inject; import jakarta.servlet.http.HttpServletResponse; @@ -135,7 +136,7 @@ protected void processResponse(WriterInterceptorContext context) throws IOExcept ResponseEntityCollectorOutputStream responseEntityCollectorOutputStream = new ResponseEntityCollectorOutputStream(originalStream); context.setOutputStream(responseEntityCollectorOutputStream); context.proceed(); - entity = responseEntityCollectorOutputStream.getEntityText().getBytes(); + entity = responseEntityCollectorOutputStream.getEntityText().getBytes(StandardCharsets.UTF_8); } else { context.proceed(); } @@ -166,10 +167,11 @@ protected void processResponse(WriterInterceptorContext context) throws IOExcept * @see RequestResponseLogger#printRequestHeaders(java.util.Map) */ protected void appendRequestHeaders(StringBuilder b, ContainerRequestContext requestContext) { - b.append(requestResponseLogger.printRequestHeaders(requestContext.getHeaders())); + MultivaluedMap headers = requestContext.getHeaders(); + b.append(requestResponseLogger.printRequestHeaders(headers)); String sessionId = null; - if (requestContext.getHeaders().containsKey(sessionKey())) { - sessionId = requestContext.getHeaders().get(sessionKey()).get(0); + if (headers != null && headers.containsKey(sessionKey())) { + sessionId = headers.get(sessionKey()).get(0); } MDC.put(LogConstants.LOG_SESSION_ID, StringUtils.defaultIfBlank(sessionId, RandomUtil.generateId())); } diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java index 0a31a7a6e..390059a7e 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java @@ -276,12 +276,11 @@ protected int getMaxRequestEntityLogSize(ContainerRequestContext requestContext) int maxRequestEntityLogSize = RestLoggerUtil.getMaxEntityLogSize(requestContext, LogSpecifierTarget.REQUEST); if (maxRequestEntityLogSize != LogSpecifier.NO_LOG && // byte-code betoltesi fajlokat, json-t és xml-t ne loggoljuk ki egeszben - Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_OCTET_STREAM_TYPE) - || Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_JSON_TYPE) - || Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_XML_TYPE) - || Objects.equals(requestContext.getMediaType(), MediaType.TEXT_XML_TYPE)) { + (Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_OCTET_STREAM_TYPE) + || Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_JSON_TYPE) + || Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_XML_TYPE) + || Objects.equals(requestContext.getMediaType(), MediaType.TEXT_XML_TYPE))) { maxRequestEntityLogSize = RequestResponseLogger.ENTITY_MAX_LOG; - } return maxRequestEntityLogSize; From ce3f81f5e863bb295edc87b8313a11253436b5cf Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Mon, 16 Jan 2023 20:29:07 +0100 Subject: [PATCH 10/33] OSP-55 - sonatype-lift fixes --- .../coffee/tool/utils/stream/RequestLoggerInputStream.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java index 88ab298ca..b84deafd4 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java @@ -84,7 +84,7 @@ public int read() throws IOException { private void buildEntity(int streamData) { // logoláshoz gyűjtjük a stream tartalmát amíg van, vagy még nem értük el a limitet - if (!firstReadCycle || streamData == -1 && logReadLimit == 0) { + if (!firstReadCycle || (streamData == -1 && logReadLimit == 0)) { return; } entity.append((char) streamData); @@ -93,7 +93,7 @@ private void buildEntity(int streamData) { private void logRequestWithEntity(int streamData) { // ha a stream végére értünk vagy elértük a limitet, akkor logolunk - if (!firstReadCycle || streamData != -1 && logReadLimit != 0) { + if (!firstReadCycle || (streamData != -1 && logReadLimit != 0)) { return; } String maskedEntity = getMaskedEntity(entity.toString(), requestPrefix); From e4075f6ab4c7ad5d2f532af4d5fa6d9919fced18 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Mon, 16 Jan 2023 20:31:23 +0100 Subject: [PATCH 11/33] OSP-55 - sonatype-lift fixes --- .../coffee/tool/utils/stream/RequestLoggerInputStream.java | 1 + 1 file changed, 1 insertion(+) diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java index b84deafd4..d9bab1454 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java @@ -35,6 +35,7 @@ * @since 1.13.0 */ @Vetoed +@SuppressWarnings("InputStreamSlowMultibyteRead") public class RequestLoggerInputStream extends InputStream { private final InputStream inputStream; From 85a14a66d99a855d6bb7c3ecc29034ff57fbd672 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Tue, 17 Jan 2023 07:56:54 +0100 Subject: [PATCH 12/33] OSP-55 - RequestResponseLogger memoria tuning comment --- .../java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java | 1 + 1 file changed, 1 insertion(+) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java index 9cf61ebc1..08ea84563 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java @@ -134,6 +134,7 @@ protected void processResponse(WriterInterceptorContext context) throws IOExcept int maxResponseEntityLogSize = RestLoggerUtil.getMaxEntityLogSize(context, LogSpecifierTarget.RESPONSE); if (maxResponseEntityLogSize != LogSpecifier.NO_LOG) { ResponseEntityCollectorOutputStream responseEntityCollectorOutputStream = new ResponseEntityCollectorOutputStream(originalStream); + // a saját OutputStream-et állítjuk be a context-be, ami majd az entity stream-be írásakor gyűjti azt a log-olás számára context.setOutputStream(responseEntityCollectorOutputStream); context.proceed(); entity = responseEntityCollectorOutputStream.getEntityText().getBytes(StandardCharsets.UTF_8); From 8906687db7b9ec29c1be64e801e3a99412a42bea Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Tue, 17 Jan 2023 15:09:43 +0100 Subject: [PATCH 13/33] OSP-55 - RequestResponseLogger memoria tuning author, since, javadoc, unused import fixes --- .../java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java | 1 + .../icellmobilsoft/coffee/rest/log/RequestResponseLogger.java | 2 +- .../coffee/tool/utils/stream/OutputStreamCopier.java | 2 +- .../coffee/tool/utils/stream/RequestLoggerInputStream.java | 2 +- .../tool/utils/stream/ResponseEntityCollectorOutputStream.java | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java index 08ea84563..17b49b78f 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java @@ -52,6 +52,7 @@ * Base class for REST logging * * @author ischeffer + * @author mate.biro * @since 1.0.0 */ public abstract class BaseRestLogger implements ContainerRequestFilter, WriterInterceptor { diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java index 390059a7e..a92ae1508 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java @@ -19,7 +19,6 @@ */ package hu.icellmobilsoft.coffee.rest.log; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -57,6 +56,7 @@ * Request - Response logger class * * @author imre.scheffer + * @author mate.biro * @since 1.0.0 */ @Dependent diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/OutputStreamCopier.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/OutputStreamCopier.java index 30ce496b4..f0ef53fbc 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/OutputStreamCopier.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/OutputStreamCopier.java @@ -58,7 +58,7 @@ public class OutputStreamCopier extends OutputStream { * Constructor * * @param outputStream - * original outputStream + * original outputStream what we want to copy */ public OutputStreamCopier(OutputStream outputStream) { this.outputStream = outputStream; diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java index d9bab1454..13f308c25 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java @@ -32,7 +32,7 @@ * Custom {@link InputStream} for logging request with entity * * @author mate.biro - * @since 1.13.0 + * @since 1.14.0 */ @Vetoed @SuppressWarnings("InputStreamSlowMultibyteRead") diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java index 2a624cc35..6f6119aec 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java @@ -28,7 +28,7 @@ * Custom {@link OutputStream} for collecting response entity * * @author mate.biro - * @since 1.13.0 + * @since 1.14.0 */ @Vetoed public class ResponseEntityCollectorOutputStream extends OutputStream { From a05f8522d695c29101f910ec2ecca8ee04385320 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Tue, 17 Jan 2023 15:15:55 +0100 Subject: [PATCH 14/33] OSP-55 - RequestResponseLogger memoria tuning remove empty lines --- .../coffee/tool/utils/stream/RequestLoggerInputStream.java | 1 - .../tool/utils/stream/ResponseEntityCollectorOutputStream.java | 1 - 2 files changed, 2 deletions(-) diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java index 13f308c25..9205029ff 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java @@ -80,7 +80,6 @@ public int read() throws IOException { logRequestWithEntity(streamData); return streamData; - } private void buildEntity(int streamData) { diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java index 6f6119aec..18417afaf 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java @@ -44,7 +44,6 @@ public class ResponseEntityCollectorOutputStream extends OutputStream { */ public ResponseEntityCollectorOutputStream(OutputStream outputStream) { this.outputStream = outputStream; - } /** From f18d796a010af970cc76d907fed838d71beeddc4 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Tue, 17 Jan 2023 17:34:51 +0100 Subject: [PATCH 15/33] OSP-55 - RequestResponseLogger memoria tuning jakarta --- .../java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java | 1 + .../coffee/tool/utils/stream/RequestLoggerInputStream.java | 2 +- .../tool/utils/stream/ResponseEntityCollectorOutputStream.java | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java index 17b49b78f..d2443b5c8 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java @@ -29,6 +29,7 @@ import jakarta.ws.rs.container.ContainerRequestFilter; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.Response.Status; import jakarta.ws.rs.core.UriInfo; import jakarta.ws.rs.ext.WriterInterceptor; diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java index 9205029ff..34ba895df 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java @@ -22,7 +22,7 @@ import java.io.IOException; import java.io.InputStream; -import javax.enterprise.inject.Vetoed; +import jakarta.enterprise.inject.Vetoed; import hu.icellmobilsoft.coffee.cdi.logger.AppLogger; import hu.icellmobilsoft.coffee.cdi.logger.LogProducer; diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java index 18417afaf..2c31e2a6a 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java @@ -22,7 +22,7 @@ import java.io.IOException; import java.io.OutputStream; -import javax.enterprise.inject.Vetoed; +import jakarta.enterprise.inject.Vetoed; /** * Custom {@link OutputStream} for collecting response entity From b01df54afe5cef1468f2b07c2e6ff0ae144f06bf Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Tue, 17 Jan 2023 19:58:49 +0100 Subject: [PATCH 16/33] OSP-55 - RequestResponseLogger memoria tuning fix --- .../coffee/tool/utils/stream/RequestLoggerInputStream.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java index 34ba895df..5b32a7918 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java @@ -83,8 +83,8 @@ public int read() throws IOException { } private void buildEntity(int streamData) { - // logoláshoz gyűjtjük a stream tartalmát amíg van, vagy még nem értük el a limitet - if (!firstReadCycle || (streamData == -1 && logReadLimit == 0)) { + // logoláshoz gyűjtjük a stream tartalmát amíg van, és még nem értük el a limitet + if (!firstReadCycle || streamData == -1 || logReadLimit == 0) { return; } entity.append((char) streamData); From 236b25c2424bb73ccbb701f4a16f7e78e8122014 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Tue, 17 Jan 2023 20:25:25 +0100 Subject: [PATCH 17/33] OSP-55 - RequestResponseLogger memoria tuning media type with charset fix --- .../coffee/rest/log/RequestResponseLogger.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java index a92ae1508..a42bd852c 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java @@ -274,12 +274,22 @@ private String entityToString(byte[] entity, Integer maxLogSize) { */ protected int getMaxRequestEntityLogSize(ContainerRequestContext requestContext) { int maxRequestEntityLogSize = RestLoggerUtil.getMaxEntityLogSize(requestContext, LogSpecifierTarget.REQUEST); + + boolean isApplicationOctetStream = Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_OCTET_STREAM_TYPE); + boolean isApplicationJson = Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_JSON_TYPE); + boolean isApplicationXml = Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_XML_TYPE); + boolean isTextXml = Objects.equals(requestContext.getMediaType(), MediaType.TEXT_XML_TYPE); + boolean isApplicationJsonWithCharset = Objects.equals(requestContext.getMediaType(), new MediaType(MediaType.APPLICATION_JSON_TYPE.getType(), + MediaType.APPLICATION_JSON_TYPE.getSubtype(), StandardCharsets.UTF_8.displayName())); + boolean isApplicationXmlWithCharset = Objects.equals(requestContext.getMediaType(), new MediaType(MediaType.APPLICATION_XML_TYPE.getType(), + MediaType.APPLICATION_XML_TYPE.getSubtype(), StandardCharsets.UTF_8.displayName())); + boolean isTextXmlWithCharset = Objects.equals(requestContext.getMediaType(), + new MediaType(MediaType.TEXT_XML_TYPE.getType(), MediaType.TEXT_XML_TYPE.getSubtype(), StandardCharsets.UTF_8.displayName())); + if (maxRequestEntityLogSize != LogSpecifier.NO_LOG && // byte-code betoltesi fajlokat, json-t és xml-t ne loggoljuk ki egeszben - (Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_OCTET_STREAM_TYPE) - || Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_JSON_TYPE) - || Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_XML_TYPE) - || Objects.equals(requestContext.getMediaType(), MediaType.TEXT_XML_TYPE))) { + (isApplicationOctetStream || isApplicationJson || isApplicationJsonWithCharset || isApplicationXmlWithCharset || isApplicationXml + || isTextXml || isTextXmlWithCharset)) { maxRequestEntityLogSize = RequestResponseLogger.ENTITY_MAX_LOG; } From daed1e660c55c3b4152d6af354d54e7be47493f0 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Wed, 18 Jan 2023 11:08:41 +0100 Subject: [PATCH 18/33] OSP-55 - RequestResponseLogger memoria tuning media type with charset fix --- .../rest/log/RequestResponseLogger.java | 18 +++++--------- .../coffee/rest/utils/RestLoggerUtil.java | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java index a42bd852c..1e58e5b2c 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java @@ -275,21 +275,15 @@ private String entityToString(byte[] entity, Integer maxLogSize) { protected int getMaxRequestEntityLogSize(ContainerRequestContext requestContext) { int maxRequestEntityLogSize = RestLoggerUtil.getMaxEntityLogSize(requestContext, LogSpecifierTarget.REQUEST); - boolean isApplicationOctetStream = Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_OCTET_STREAM_TYPE); - boolean isApplicationJson = Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_JSON_TYPE); - boolean isApplicationXml = Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_XML_TYPE); - boolean isTextXml = Objects.equals(requestContext.getMediaType(), MediaType.TEXT_XML_TYPE); - boolean isApplicationJsonWithCharset = Objects.equals(requestContext.getMediaType(), new MediaType(MediaType.APPLICATION_JSON_TYPE.getType(), - MediaType.APPLICATION_JSON_TYPE.getSubtype(), StandardCharsets.UTF_8.displayName())); - boolean isApplicationXmlWithCharset = Objects.equals(requestContext.getMediaType(), new MediaType(MediaType.APPLICATION_XML_TYPE.getType(), - MediaType.APPLICATION_XML_TYPE.getSubtype(), StandardCharsets.UTF_8.displayName())); - boolean isTextXmlWithCharset = Objects.equals(requestContext.getMediaType(), - new MediaType(MediaType.TEXT_XML_TYPE.getType(), MediaType.TEXT_XML_TYPE.getSubtype(), StandardCharsets.UTF_8.displayName())); + boolean isApplicationOctetStream = RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), + MediaType.APPLICATION_OCTET_STREAM_TYPE); + boolean isApplicationJson = RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), MediaType.APPLICATION_JSON_TYPE); + boolean isApplicationXml = RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), MediaType.APPLICATION_XML_TYPE); + boolean isTextXml = RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), MediaType.TEXT_XML_TYPE); if (maxRequestEntityLogSize != LogSpecifier.NO_LOG && // byte-code betoltesi fajlokat, json-t és xml-t ne loggoljuk ki egeszben - (isApplicationOctetStream || isApplicationJson || isApplicationJsonWithCharset || isApplicationXmlWithCharset || isApplicationXml - || isTextXml || isTextXmlWithCharset)) { + (isApplicationOctetStream || isApplicationJson || isApplicationXml || isTextXml)) { maxRequestEntityLogSize = RequestResponseLogger.ENTITY_MAX_LOG; } diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/utils/RestLoggerUtil.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/utils/RestLoggerUtil.java index 9999f7942..8e3b798b9 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/utils/RestLoggerUtil.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/utils/RestLoggerUtil.java @@ -22,8 +22,11 @@ import java.lang.annotation.Annotation; import java.util.Arrays; +import org.apache.commons.lang3.StringUtils; + import jakarta.ws.rs.client.ClientRequestContext; import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.ext.WriterInterceptorContext; import hu.icellmobilsoft.coffee.rest.log.annotation.LogSpecifier; @@ -219,4 +222,25 @@ public static boolean logDisabled(LogSpecifierTarget target, LogSpecifier... log return false; } + /** + * Returns if {@link MediaType}s are the same irrespective of charset + * + * @param mediaType1 + * {@link MediaType} to compare + * @param mediaType2 + * {@link MediaType} to compare + * @return if {@code MediaType}s are the same + */ + public static boolean isSameMediaTypeWithoutCharset(MediaType mediaType1, MediaType mediaType2) { + if (mediaType1 == null || mediaType2 == null) { + return false; + } + + String type1 = mediaType1.getType(); + String subtype1 = mediaType1.getSubtype(); + String type2 = mediaType2.getType(); + String subtype2 = mediaType2.getSubtype(); + + return (StringUtils.equals(type1, type2) && StringUtils.equals(subtype1, subtype2)); + } } From a979632e8aac48db67a8d51509d4d4e70d019cd6 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Wed, 18 Jan 2023 12:59:35 +0100 Subject: [PATCH 19/33] OSP-55 - RequestResponseLogger memoria tuning media type with charset fix --- .../coffee/rest/log/RequestResponseLogger.java | 5 +++-- docs/common/core/coffee-rest.adoc | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java index 1e58e5b2c..324f7f78f 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java @@ -277,13 +277,14 @@ protected int getMaxRequestEntityLogSize(ContainerRequestContext requestContext) boolean isApplicationOctetStream = RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), MediaType.APPLICATION_OCTET_STREAM_TYPE); + boolean isMultipartFormData = RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), MediaType.MULTIPART_FORM_DATA_TYPE); boolean isApplicationJson = RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), MediaType.APPLICATION_JSON_TYPE); boolean isApplicationXml = RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), MediaType.APPLICATION_XML_TYPE); boolean isTextXml = RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), MediaType.TEXT_XML_TYPE); - if (maxRequestEntityLogSize != LogSpecifier.NO_LOG && + if (maxRequestEntityLogSize > RequestResponseLogger.ENTITY_MAX_LOG && // byte-code betoltesi fajlokat, json-t és xml-t ne loggoljuk ki egeszben - (isApplicationOctetStream || isApplicationJson || isApplicationXml || isTextXml)) { + (isApplicationOctetStream || isMultipartFormData || isApplicationJson || isApplicationXml || isTextXml)) { maxRequestEntityLogSize = RequestResponseLogger.ENTITY_MAX_LOG; } diff --git a/docs/common/core/coffee-rest.adoc b/docs/common/core/coffee-rest.adoc index 67f40bade..b8368242e 100644 --- a/docs/common/core/coffee-rest.adoc +++ b/docs/common/core/coffee-rest.adoc @@ -113,7 +113,7 @@ Jelenleg a LogSpecifier a következő esetekre van felkészítve: * a végponton a request-response logolása kikapcsolható a `LogSpecifier` annotáció `noLog` kapcsolójával. * a végponton a kilogolt body méretét a `LogSpecifier` annotáció `maxEntityLogSize` mezőjével lehet korlátozni. -IMPORTANT: ha a `maxEntityLogSize` `LogSpecifier.NO_LOG`-tól *eltérő* értékre van állítva, akkor a REST endpoint-hoz érkező `application/octet-stream`, `application/json`, `application/xml` és `text/xml` mediaType-ok esetében csak a kérés első 5000 karaktere íródik ki. +IMPORTANT: ha a `maxEntityLogSize` a `RequestResponseLogger.ENTITY_MAX_LOG = 5000`-nél nagyobb értékre van állítva, akkor a REST endpoint-hoz érkező `application/octet-stream`, `multipart/form-data`, `application/json`, `application/xml` és `text/xml` mediaType-ok esetében csak a kérés első 5000 karaktere íródik ki. .LogSpecifier példa [source,java] From 7fa625f0c4915b6195b73443b1a12c144c608a23 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Wed, 18 Jan 2023 13:08:00 +0100 Subject: [PATCH 20/33] OSP-55 - RequestResponseLogger memoria tuning comment fix --- .../icellmobilsoft/coffee/rest/log/RequestResponseLogger.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java index 324f7f78f..8e8e2d7eb 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java @@ -283,7 +283,7 @@ protected int getMaxRequestEntityLogSize(ContainerRequestContext requestContext) boolean isTextXml = RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), MediaType.TEXT_XML_TYPE); if (maxRequestEntityLogSize > RequestResponseLogger.ENTITY_MAX_LOG && - // byte-code betoltesi fajlokat, json-t és xml-t ne loggoljuk ki egeszben + // byte-code betoltesi fajlokat, multipart-ot, json-t és xml-t ne loggoljuk ki egeszben (isApplicationOctetStream || isMultipartFormData || isApplicationJson || isApplicationXml || isTextXml)) { maxRequestEntityLogSize = RequestResponseLogger.ENTITY_MAX_LOG; } From 27fe62b5857e6012c2bc3038f6b0cfb7ed4d11cd Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Wed, 18 Jan 2023 14:14:07 +0100 Subject: [PATCH 21/33] OSP-55 - sonatype-lift fixes --- .../hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java | 7 ++++--- .../coffee/rest/log/RequestResponseLogger.java | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java index d2443b5c8..b4f10e247 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java @@ -99,13 +99,13 @@ protected void processRequest(ContainerRequestContext requestContext) { return; } - StringBuilder message = new StringBuilder(); + var message = new StringBuilder(); appendRequestLine(message, requestContext); appendRequestHeaders(message, requestContext); int maxRequestEntityLogSize = requestResponseLogger.getMaxRequestEntityLogSize(requestContext); - RequestLoggerInputStream requestLoggerInputStream = new RequestLoggerInputStream(requestContext.getEntityStream(), maxRequestEntityLogSize, + var requestLoggerInputStream = new RequestLoggerInputStream(requestContext.getEntityStream(), maxRequestEntityLogSize, RequestResponseLogger.REQUEST_PREFIX, message); // a saját InputStream-et állítjuk be a context-be, ami majd az entity stream olvasáskor log-olja a request-et @@ -120,6 +120,7 @@ protected void processRequest(ContainerRequestContext requestContext) { * @throws IOException * if response cannot be processed. */ + @SuppressWarnings("Var") protected void processResponse(WriterInterceptorContext context) throws IOException { if (RestLoggerUtil.logDisabled(context, LogSpecifierTarget.RESPONSE)) { context.proceed(); @@ -135,7 +136,7 @@ protected void processResponse(WriterInterceptorContext context) throws IOExcept byte[] entity = new byte[0]; int maxResponseEntityLogSize = RestLoggerUtil.getMaxEntityLogSize(context, LogSpecifierTarget.RESPONSE); if (maxResponseEntityLogSize != LogSpecifier.NO_LOG) { - ResponseEntityCollectorOutputStream responseEntityCollectorOutputStream = new ResponseEntityCollectorOutputStream(originalStream); + var responseEntityCollectorOutputStream = new ResponseEntityCollectorOutputStream(originalStream); // a saját OutputStream-et állítjuk be a context-be, ami majd az entity stream-be írásakor gyűjti azt a log-olás számára context.setOutputStream(responseEntityCollectorOutputStream); context.proceed(); diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java index 8e8e2d7eb..33d8d63cd 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java @@ -272,6 +272,7 @@ private String entityToString(byte[] entity, Integer maxLogSize) { * * @return the maximum log size of the entity */ + @SuppressWarnings("Var") protected int getMaxRequestEntityLogSize(ContainerRequestContext requestContext) { int maxRequestEntityLogSize = RestLoggerUtil.getMaxEntityLogSize(requestContext, LogSpecifierTarget.REQUEST); From fc00000b7fccf9373185df2e8020a50cad5cb014 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Mon, 23 Jan 2023 13:10:57 +0100 Subject: [PATCH 22/33] OSP-55 - RequestResponseLogger memoria tuning review fix --- .../rest/log/RequestResponseLogger.java | 12 +++------ .../coffee/rest/utils/RestLoggerUtil.java | 27 ++++++++++++++++--- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java index 33d8d63cd..3e6091b58 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java @@ -276,16 +276,10 @@ private String entityToString(byte[] entity, Integer maxLogSize) { protected int getMaxRequestEntityLogSize(ContainerRequestContext requestContext) { int maxRequestEntityLogSize = RestLoggerUtil.getMaxEntityLogSize(requestContext, LogSpecifierTarget.REQUEST); - boolean isApplicationOctetStream = RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), - MediaType.APPLICATION_OCTET_STREAM_TYPE); - boolean isMultipartFormData = RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), MediaType.MULTIPART_FORM_DATA_TYPE); - boolean isApplicationJson = RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), MediaType.APPLICATION_JSON_TYPE); - boolean isApplicationXml = RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), MediaType.APPLICATION_XML_TYPE); - boolean isTextXml = RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), MediaType.TEXT_XML_TYPE); - - if (maxRequestEntityLogSize > RequestResponseLogger.ENTITY_MAX_LOG && + if (maxRequestEntityLogSize != LogSpecifier.NO_LOG && // byte-code betoltesi fajlokat, multipart-ot, json-t és xml-t ne loggoljuk ki egeszben - (isApplicationOctetStream || isMultipartFormData || isApplicationJson || isApplicationXml || isTextXml)) { + RestLoggerUtil.isLogSizeLimited(requestContext, MediaType.APPLICATION_OCTET_STREAM_TYPE, MediaType.MULTIPART_FORM_DATA_TYPE, + MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_XML_TYPE, MediaType.TEXT_XML_TYPE)) { maxRequestEntityLogSize = RequestResponseLogger.ENTITY_MAX_LOG; } diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/utils/RestLoggerUtil.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/utils/RestLoggerUtil.java index 8e3b798b9..7f5cea94f 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/utils/RestLoggerUtil.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/utils/RestLoggerUtil.java @@ -223,15 +223,36 @@ public static boolean logDisabled(LogSpecifierTarget target, LogSpecifier... log } /** - * Returns if {@link MediaType}s are the same irrespective of charset + * Returns true if the {@link MediaType} of the request context matches one of the given ones + * + * @param requestContext + * context + * @param mediaTypes + * {@link MediaType}s to compare + * @return true if there is a matching {@code MediaType} + */ + public static boolean isLogSizeLimited(ContainerRequestContext requestContext, MediaType... mediaTypes) { + if (requestContext == null || mediaTypes == null) { + return false; + } + for (MediaType mediaType : mediaTypes) { + if (RestLoggerUtil.isSameMediaTypeWithoutCharset(requestContext.getMediaType(), mediaType)) { + return true; + } + } + return false; + } + + /** + * Returns true if {@link MediaType}s are the same irrespective of charset * * @param mediaType1 * {@link MediaType} to compare * @param mediaType2 * {@link MediaType} to compare - * @return if {@code MediaType}s are the same + * @return true if {@code MediaType}s are the same */ - public static boolean isSameMediaTypeWithoutCharset(MediaType mediaType1, MediaType mediaType2) { + private static boolean isSameMediaTypeWithoutCharset(MediaType mediaType1, MediaType mediaType2) { if (mediaType1 == null || mediaType2 == null) { return false; } From dbd630089cf9b650d2ab1c3ed1682ca589081ab5 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Mon, 23 Jan 2023 13:16:34 +0100 Subject: [PATCH 23/33] OSP-55 - RequestResponseLogger memoria tuning adoc fix --- docs/common/core/coffee-rest.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/common/core/coffee-rest.adoc b/docs/common/core/coffee-rest.adoc index b8368242e..67ebc3437 100644 --- a/docs/common/core/coffee-rest.adoc +++ b/docs/common/core/coffee-rest.adoc @@ -113,7 +113,7 @@ Jelenleg a LogSpecifier a következő esetekre van felkészítve: * a végponton a request-response logolása kikapcsolható a `LogSpecifier` annotáció `noLog` kapcsolójával. * a végponton a kilogolt body méretét a `LogSpecifier` annotáció `maxEntityLogSize` mezőjével lehet korlátozni. -IMPORTANT: ha a `maxEntityLogSize` a `RequestResponseLogger.ENTITY_MAX_LOG = 5000`-nél nagyobb értékre van állítva, akkor a REST endpoint-hoz érkező `application/octet-stream`, `multipart/form-data`, `application/json`, `application/xml` és `text/xml` mediaType-ok esetében csak a kérés első 5000 karaktere íródik ki. +IMPORTANT: ha a `maxEntityLogSize` a `LogSpecifier.NO_LOG`-tól *eltérő* értékre van állítva, akkor a REST endpoint-hoz érkező `application/octet-stream`, `multipart/form-data`, `application/json`, `application/xml` és `text/xml` mediaType-ok esetében csak a kérés első 5000 karaktere íródik ki. .LogSpecifier példa [source,java] From 3c01a9993d8580b80e9c6746431feb8044c93e7c Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Mon, 23 Jan 2023 17:56:06 +0100 Subject: [PATCH 24/33] OSP-55 - RequestResponseLogger memoria tuning review fix --- .../coffee/rest/log/BaseRestLogger.java | 2 +- .../ResponseEntityCollectorOutputStream.java | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java index b4f10e247..8982ba9b3 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java @@ -136,7 +136,7 @@ protected void processResponse(WriterInterceptorContext context) throws IOExcept byte[] entity = new byte[0]; int maxResponseEntityLogSize = RestLoggerUtil.getMaxEntityLogSize(context, LogSpecifierTarget.RESPONSE); if (maxResponseEntityLogSize != LogSpecifier.NO_LOG) { - var responseEntityCollectorOutputStream = new ResponseEntityCollectorOutputStream(originalStream); + var responseEntityCollectorOutputStream = new ResponseEntityCollectorOutputStream(originalStream, maxResponseEntityLogSize); // a saját OutputStream-et állítjuk be a context-be, ami majd az entity stream-be írásakor gyűjti azt a log-olás számára context.setOutputStream(responseEntityCollectorOutputStream); context.proceed(); diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java index 2c31e2a6a..a5b2da84e 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java @@ -35,25 +35,33 @@ public class ResponseEntityCollectorOutputStream extends OutputStream { private final OutputStream outputStream; private final StringBuilder entity = new StringBuilder(); + private int collectLimit; /** * Constructor * * @param outputStream * original outputStream + * @param collectLimit + * collect limit */ - public ResponseEntityCollectorOutputStream(OutputStream outputStream) { + public ResponseEntityCollectorOutputStream(OutputStream outputStream, int collectLimit) { this.outputStream = outputStream; + this.collectLimit = collectLimit; } /** * {@inheritDoc} * - * Extra functionality: It appends the response entity data written to the original {@link OutputStream} to an internal {@link StringBuilder}. + * Extra functionality: It appends the response entity data written to the original {@link OutputStream} to an internal {@link StringBuilder} + * until the given limit has been reached. */ @Override public void write(int b) throws IOException { - entity.append((char) b); + if (collectLimit != 0) { + entity.append((char) b); + collectLimit--; + } outputStream.write(b); } From 834c1fb2e9c7c0c572129a809dc54ccc71d7a471 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Mon, 23 Jan 2023 20:01:34 +0100 Subject: [PATCH 25/33] OSP-55 - RequestResponseLogger memoria tuning review fix --- .../coffee/rest/log/BaseRestLogger.java | 5 ++++- .../stream/RequestLoggerInputStream.java | 20 ++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java index 8982ba9b3..ed09ba7eb 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.charset.StandardCharsets; +import java.util.function.Consumer; import jakarta.inject.Inject; import jakarta.servlet.http.HttpServletResponse; @@ -38,6 +39,7 @@ import org.apache.commons.lang3.StringUtils; import hu.icellmobilsoft.coffee.cdi.logger.AppLogger; +import hu.icellmobilsoft.coffee.cdi.logger.LogProducer; import hu.icellmobilsoft.coffee.cdi.logger.ThisLogger; import hu.icellmobilsoft.coffee.dto.common.LogConstants; import hu.icellmobilsoft.coffee.rest.cdi.BaseApplicationContainer; @@ -105,8 +107,9 @@ protected void processRequest(ContainerRequestContext requestContext) { int maxRequestEntityLogSize = requestResponseLogger.getMaxRequestEntityLogSize(requestContext); + Consumer appLoggerConsumer = (AppLogger appLogger) -> appLogger.info(message.toString()); var requestLoggerInputStream = new RequestLoggerInputStream(requestContext.getEntityStream(), maxRequestEntityLogSize, - RequestResponseLogger.REQUEST_PREFIX, message); + RequestResponseLogger.REQUEST_PREFIX, message, LogProducer::logToAppLogger, appLoggerConsumer, BaseRestLogger.class); // a saját InputStream-et állítjuk be a context-be, ami majd az entity stream olvasáskor log-olja a request-et requestContext.setEntityStream(requestLoggerInputStream); diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java index 5b32a7918..460d6c154 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java @@ -21,11 +21,12 @@ import java.io.IOException; import java.io.InputStream; +import java.util.function.BiConsumer; +import java.util.function.Consumer; import jakarta.enterprise.inject.Vetoed; import hu.icellmobilsoft.coffee.cdi.logger.AppLogger; -import hu.icellmobilsoft.coffee.cdi.logger.LogProducer; import hu.icellmobilsoft.coffee.tool.utils.string.StringHelper; /** @@ -42,6 +43,9 @@ public class RequestLoggerInputStream extends InputStream { private final String requestPrefix; private final StringBuilder entity = new StringBuilder(); private final StringBuilder message; + private final BiConsumer, Class> logger; + private final Consumer loggerConsumer; + private final Class clazz; private int logReadLimit; private boolean firstReadCycle = true; @@ -56,12 +60,22 @@ public class RequestLoggerInputStream extends InputStream { * request log prefix * @param message * log message + * @param logger + * the function handling {@link AppLogger} + * @param loggerConsumer + * the function doing the logging + * @param clazz + * class for logging */ - public RequestLoggerInputStream(InputStream inputStream, int logReadLimit, String requestPrefix, StringBuilder message) { + public RequestLoggerInputStream(InputStream inputStream, int logReadLimit, String requestPrefix, StringBuilder message, + BiConsumer, Class> logger, Consumer loggerConsumer, Class clazz) { this.inputStream = inputStream; this.logReadLimit = logReadLimit; this.requestPrefix = requestPrefix; this.message = message; + this.logger = logger; + this.loggerConsumer = loggerConsumer; + this.clazz = clazz; } /** @@ -98,7 +112,7 @@ private void logRequestWithEntity(int streamData) { } String maskedEntity = getMaskedEntity(entity.toString(), requestPrefix); message.append(maskedEntity); - LogProducer.logToAppLogger((AppLogger appLogger) -> appLogger.info(message.toString()), RequestLoggerInputStream.class); + logger.accept(loggerConsumer, clazz); firstReadCycle = false; } From 36ed56827f0434fa65754b951ce07ebe72808f9b Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Thu, 2 Nov 2023 14:19:46 +0100 Subject: [PATCH 26/33] OSP-55 - RequestResponseLogger memoria tuning --- docs/en/common/core/coffee-rest.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/common/core/coffee-rest.adoc b/docs/en/common/core/coffee-rest.adoc index 73005db3e..405387091 100644 --- a/docs/en/common/core/coffee-rest.adoc +++ b/docs/en/common/core/coffee-rest.adoc @@ -252,7 +252,7 @@ Activating `PublicCatalogResolver` is done in the classic CDI way: xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/javaee/beans_1_1.xsd" version="1.1" bean-discovery-mode="all"> - . + hu.icellmobilsoft.coffee.rest.validation.catalog.PublicCatalogResolver From 2ee8a0f5d67cfc99ff572df8af9bb5d3baf7c074 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Wed, 8 Nov 2023 12:56:12 +0100 Subject: [PATCH 27/33] OSP-55 - RequestResponseLogger memoria tuning --- .../DefaultLoggerClientResponseFilter.java | 2 +- .../coffee/rest/log/BaseRestLogger.java | 102 ++-- .../rest/log/RequestResponseLogger.java | 46 +- .../optimized/BaseRestLoggerOptimized.java | 245 ++++++++++ .../RequestResponseLoggerOptimized.java | 459 ++++++++++++++++++ .../coffee/rest/utils/RestLoggerUtil.java | 87 +++- .../tool/utils/stream/LoggingEvent.java | 50 ++ .../tool/utils/stream/LoggingObserver.java | 51 ++ .../tool/utils/stream/LoggingPublisher.java | 47 ++ .../stream/RequestLoggerInputStream.java | 92 ++-- .../ResponseEntityCollectorOutputStream.java | 35 +- docs/hu/common/core/coffee-rest.adoc | 43 +- docs/hu/migration.adoc | 1 + docs/hu/migration/migration230to240.adoc | 12 + docs/hu/migration/v1/migration1120to1130.adoc | 4 - 15 files changed, 1127 insertions(+), 149 deletions(-) create mode 100644 coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/BaseRestLoggerOptimized.java create mode 100644 coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/RequestResponseLoggerOptimized.java create mode 100644 coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingEvent.java create mode 100644 coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingObserver.java create mode 100644 coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingPublisher.java create mode 100644 docs/hu/migration/migration230to240.adoc diff --git a/coffee-module/coffee-module-mp/coffee-module-mp-restclient/src/main/java/hu/icellmobilsoft/coffee/module/mp/restclient/provider/DefaultLoggerClientResponseFilter.java b/coffee-module/coffee-module-mp/coffee-module-mp-restclient/src/main/java/hu/icellmobilsoft/coffee/module/mp/restclient/provider/DefaultLoggerClientResponseFilter.java index eae42b079..128dbf9b3 100644 --- a/coffee-module/coffee-module-mp/coffee-module-mp-restclient/src/main/java/hu/icellmobilsoft/coffee/module/mp/restclient/provider/DefaultLoggerClientResponseFilter.java +++ b/coffee-module/coffee-module-mp/coffee-module-mp-restclient/src/main/java/hu/icellmobilsoft/coffee/module/mp/restclient/provider/DefaultLoggerClientResponseFilter.java @@ -178,7 +178,7 @@ private int getMaxResponseEntityLogSize(ClientRequestContext requestContext, Cli if (maxResponseEntityLogSize != LogSpecifier.NO_LOG && // byte-code betoltesi fajlokat ne loggoljuk ki egeszben Objects.equals(responseContext.getMediaType(), MediaType.APPLICATION_OCTET_STREAM_TYPE)) { - maxResponseEntityLogSize = RequestResponseLogger.ENTITY_MAX_LOG; + maxResponseEntityLogSize = RequestResponseLogger.BYTECODE_MAX_LOG; } return maxResponseEntityLogSize; diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java index 72e8b2a8f..a88882250 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/BaseRestLogger.java @@ -21,8 +21,6 @@ import java.io.IOException; import java.io.OutputStream; -import java.nio.charset.StandardCharsets; -import java.util.function.Consumer; import jakarta.inject.Inject; import jakarta.servlet.http.HttpServletResponse; @@ -30,7 +28,6 @@ import jakarta.ws.rs.container.ContainerRequestFilter; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.Response.Status; import jakarta.ws.rs.core.UriInfo; import jakarta.ws.rs.ext.WriterInterceptor; @@ -39,7 +36,6 @@ import org.apache.commons.lang3.StringUtils; import hu.icellmobilsoft.coffee.cdi.logger.AppLogger; -import hu.icellmobilsoft.coffee.cdi.logger.LogProducer; import hu.icellmobilsoft.coffee.cdi.logger.ThisLogger; import hu.icellmobilsoft.coffee.dto.common.LogConstants; import hu.icellmobilsoft.coffee.rest.cdi.BaseApplicationContainer; @@ -47,15 +43,12 @@ import hu.icellmobilsoft.coffee.rest.log.annotation.enumeration.LogSpecifierTarget; import hu.icellmobilsoft.coffee.rest.utils.RestLoggerUtil; import hu.icellmobilsoft.coffee.se.logging.mdc.MDC; -import hu.icellmobilsoft.coffee.tool.utils.stream.RequestLoggerInputStream; -import hu.icellmobilsoft.coffee.tool.utils.stream.ResponseEntityCollectorOutputStream; import hu.icellmobilsoft.coffee.tool.utils.string.RandomUtil; /** * Base class for REST logging * * @author ischeffer - * @author mate.biro * @since 1.0.0 */ public abstract class BaseRestLogger implements ContainerRequestFilter, WriterInterceptor { @@ -102,63 +95,68 @@ public void aroundWriteTo(WriterInterceptorContext context) throws IOException { * * @param requestContext * context + * @return HTTP request message or null if logging is disabled */ - protected void processRequest(ContainerRequestContext requestContext) { + protected String processRequest(ContainerRequestContext requestContext) { if (RestLoggerUtil.logDisabled(requestContext, LogSpecifierTarget.REQUEST)) { - return; + return null; } - var message = new StringBuilder(); - appendRequestLine(message, requestContext); - appendRequestHeaders(message, requestContext); + StringBuffer message = new StringBuffer(); + printRequestLine(message, requestContext); + printRequestHeaders(message, requestContext); + printRequestEntity(message, requestContext); - int maxRequestEntityLogSize = requestResponseLogger.getMaxRequestEntityLogSize(requestContext); - - Consumer appLoggerConsumer = (AppLogger appLogger) -> appLogger.info(message.toString()); - var requestLoggerInputStream = new RequestLoggerInputStream(requestContext.getEntityStream(), maxRequestEntityLogSize, - RequestResponseLogger.REQUEST_PREFIX, message, LogProducer::logToAppLogger, appLoggerConsumer, BaseRestLogger.class); - - // a saját InputStream-et állítjuk be a context-be, ami majd az entity stream olvasáskor log-olja a request-et - requestContext.setEntityStream(requestLoggerInputStream); + String messageString = message.toString(); + log.info(message.toString()); + return messageString; } /** * Processes HTTP response. - * + * * @param context * context + * @return HTTP response message or null if logging is disabled * @throws IOException * if response cannot be processed. */ - @SuppressWarnings("Var") - protected void processResponse(WriterInterceptorContext context) throws IOException { + protected String processResponse(WriterInterceptorContext context) throws IOException { if (RestLoggerUtil.logDisabled(context, LogSpecifierTarget.RESPONSE)) { context.proceed(); - return; + return null; } - StringBuilder message = new StringBuilder(); + StringBuffer message = new StringBuffer(); try { + printResponseLine(message, context); printResponseHeaders(message, context); OutputStream originalStream = context.getOutputStream(); - byte[] entity = new byte[0]; + byte[] entityCopy = new byte[0]; int maxResponseEntityLogSize = RestLoggerUtil.getMaxEntityLogSize(context, LogSpecifierTarget.RESPONSE); if (maxResponseEntityLogSize != LogSpecifier.NO_LOG) { - var responseEntityCollectorOutputStream = new ResponseEntityCollectorOutputStream(originalStream, maxResponseEntityLogSize); - // a saját OutputStream-et állítjuk be a context-be, ami majd az entity stream-be írásakor gyűjti azt a log-olás számára - context.setOutputStream(responseEntityCollectorOutputStream); - context.proceed(); - entity = responseEntityCollectorOutputStream.getEntityText().getBytes(StandardCharsets.UTF_8); + hu.icellmobilsoft.coffee.tool.utils.stream.OutputStreamCopier osc = new hu.icellmobilsoft.coffee.tool.utils.stream.OutputStreamCopier( + originalStream); + context.setOutputStream(osc); + // elegessuk a stream-et, kozben masoljuk a tartalmat + try { + context.proceed(); + } finally { + // IS: kerdeses erdemes-e vissza irni az eredeti stream-et... + context.setOutputStream(originalStream); + } + entityCopy = osc.getCopy(); } else { context.proceed(); } - printResponseEntity(message, context, entity); + printResponseEntity(message, context, entityCopy); } finally { log.info(message.toString()); } + return message.toString(); } /** @@ -172,7 +170,7 @@ protected void processResponse(WriterInterceptorContext context) throws IOExcept public abstract String sessionKey(); /** - * Prints request headers from {@link ContainerRequestContext} and appends given {@link StringBuilder} with the print result. + * Prints request headers from {@link ContainerRequestContext} and appends given {@link StringBuffer} with the print result. * * @param b * request message @@ -180,18 +178,17 @@ protected void processResponse(WriterInterceptorContext context) throws IOExcept * context * @see RequestResponseLogger#printRequestHeaders(java.util.Map) */ - protected void appendRequestHeaders(StringBuilder b, ContainerRequestContext requestContext) { - MultivaluedMap headers = requestContext.getHeaders(); - b.append(requestResponseLogger.printRequestHeaders(headers)); + protected void printRequestHeaders(StringBuffer b, ContainerRequestContext requestContext) { + b.append(requestResponseLogger.printRequestHeaders(requestContext.getHeaders())); String sessionId = null; - if (headers != null && headers.containsKey(sessionKey())) { - sessionId = headers.get(sessionKey()).get(0); + if (requestContext.getHeaders().containsKey(sessionKey())) { + sessionId = requestContext.getHeaders().get(sessionKey()).get(0); } MDC.put(LogConstants.LOG_SESSION_ID, StringUtils.defaultIfBlank(sessionId, RandomUtil.generateId())); } /** - * Prints http path info from {@link ContainerRequestContext} and appends given {@link StringBuilder} with the print result. + * Prints http path info from {@link ContainerRequestContext} and appends given {@link StringBuffer} with the print result. * * @param b * request message @@ -199,12 +196,25 @@ protected void appendRequestHeaders(StringBuilder b, ContainerRequestContext req * context * @see RequestResponseLogger#printRequestLine(ContainerRequestContext) */ - protected void appendRequestLine(StringBuilder b, ContainerRequestContext requestContext) { + protected void printRequestLine(StringBuffer b, ContainerRequestContext requestContext) { b.append(requestResponseLogger.printRequestLine(requestContext)); } /** - * Prints response URL line and appends given {@link StringBuilder} with the print result. + * Prints http entity from {@link ContainerRequestContext} and appends given {@link StringBuffer} with the print result. + * + * @param b + * request message + * @param requestContext + * context + * @see RequestResponseLogger#printRequestEntity(ContainerRequestContext) + */ + protected void printRequestEntity(StringBuffer b, ContainerRequestContext requestContext) { + b.append(requestResponseLogger.printRequestEntity(requestContext)); + } + + /** + * Prints response URL line and appends given {@link StringBuffer} with the print result. * * @param b * response message @@ -212,7 +222,7 @@ protected void appendRequestLine(StringBuilder b, ContainerRequestContext reques * context * @see RequestResponseLogger#printResponseLine(String, int, String, String) */ - protected void printResponseLine(StringBuilder b, WriterInterceptorContext context) { + protected void printResponseLine(StringBuffer b, WriterInterceptorContext context) { String fullPath = uriInfo.getAbsolutePath().toASCIIString(); int status = httpServletResponse.getStatus(); Status statusEnum = Status.fromStatusCode(status); @@ -222,7 +232,7 @@ protected void printResponseLine(StringBuilder b, WriterInterceptorContext conte } /** - * Prints response header values and appends given {@link StringBuilder} with the print result. + * Prints response header values and appends given {@link StringBuffer} with the print result. * * @param b * response message @@ -230,12 +240,12 @@ protected void printResponseLine(StringBuilder b, WriterInterceptorContext conte * context * @see RequestResponseLogger#printResponseHeaders(java.util.Map) */ - protected void printResponseHeaders(StringBuilder b, WriterInterceptorContext context) { + protected void printResponseHeaders(StringBuffer b, WriterInterceptorContext context) { b.append(requestResponseLogger.printResponseHeaders(context.getHeaders())); } /** - * Prints response from {@link WriterInterceptorContext} and appends given {@link StringBuilder} with the print result. + * Prints response from {@link WriterInterceptorContext} and appends given {@link StringBuffer} with the print result. * * @param b * response message @@ -245,7 +255,7 @@ protected void printResponseHeaders(StringBuilder b, WriterInterceptorContext co * entity * @see RequestResponseLogger#printResponseEntity(String, WriterInterceptorContext, byte[]) */ - protected void printResponseEntity(StringBuilder b, WriterInterceptorContext context, byte[] entityCopy) { + protected void printResponseEntity(StringBuffer b, WriterInterceptorContext context, byte[] entityCopy) { b.append(requestResponseLogger.printResponseEntity(uriInfo.getAbsolutePath().toASCIIString(), context, entityCopy)); } } diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java index e241c83cc..377d7d24c 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/RequestResponseLogger.java @@ -19,6 +19,7 @@ */ package hu.icellmobilsoft.coffee.rest.log; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -56,7 +57,6 @@ * Request - Response logger class * * @author imre.scheffer - * @author mate.biro * @since 1.0.0 */ @Dependent @@ -69,8 +69,8 @@ public class RequestResponseLogger { /** Constant RESPONSE_PREFIX="< " */ public static final String RESPONSE_PREFIX = "< "; - /** Constant ENTITY_MAX_LOG=5000 */ - public static final int ENTITY_MAX_LOG = 5000; + /** Constant BYTECODE_MAX_LOG=5000 */ + public static final int BYTECODE_MAX_LOG = 5000; /** Constant SKIP_MEDIATYPE_SUBTYPE_PDF="pdf" */ public static final String SKIP_MEDIATYPE_SUBTYPE_PDF = "pdf"; @@ -272,25 +272,37 @@ private String entityToString(byte[] entity, Integer maxLogSize) { } /** - * Returns the maximum entity log size + * Prints http entity from {@link ContainerRequestContext}. * * @param requestContext * context - * - * @return the maximum log size of the entity + * @return HTTP entity or null if invalid parameter or exception when reading the entity */ - @SuppressWarnings("Var") - protected int getMaxRequestEntityLogSize(ContainerRequestContext requestContext) { - int maxRequestEntityLogSize = RestLoggerUtil.getMaxEntityLogSize(requestContext, LogSpecifierTarget.REQUEST); - - if (maxRequestEntityLogSize != LogSpecifier.NO_LOG && - // byte-code betoltesi fajlokat, multipart-ot, json-t és xml-t ne loggoljuk ki egeszben - RestLoggerUtil.isLogSizeLimited(requestContext, MediaType.APPLICATION_OCTET_STREAM_TYPE, MediaType.MULTIPART_FORM_DATA_TYPE, - MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_XML_TYPE, MediaType.TEXT_XML_TYPE)) { - maxRequestEntityLogSize = RequestResponseLogger.ENTITY_MAX_LOG; + public String printRequestEntity(ContainerRequestContext requestContext) { + if (requestContext == null) { + return null; } + ByteArrayOutputStream out = new ByteArrayOutputStream(); + InputStream in = requestContext.getEntityStream(); + try { + IOUtils.copy(in, out); - return maxRequestEntityLogSize; + byte[] requestEntity = out.toByteArray(); + int maxRequestEntityLogSize = RestLoggerUtil.getMaxEntityLogSize(requestContext, LogSpecifierTarget.REQUEST); + if (maxRequestEntityLogSize != LogSpecifier.NO_LOG && + // byte-code betoltesi fajlokat ne loggoljuk ki egeszben + Objects.equals(requestContext.getMediaType(), MediaType.APPLICATION_OCTET_STREAM_TYPE)) { + maxRequestEntityLogSize = RequestResponseLogger.BYTECODE_MAX_LOG; + + } + // vissza irjuk a kiolvasott streamet + requestContext.setEntityStream(new ByteArrayInputStream(requestEntity)); + + return printRequestEntity(requestEntity, maxRequestEntityLogSize); + } catch (IOException e) { + log.error("Error in logging request entity: " + e.getLocalizedMessage(), e); + return null; + } } /** @@ -313,7 +325,7 @@ public String printRequestEntity(HttpServletRequest servletRequest) { // byte-code betoltesi fajlokat ne loggoljuk ki egeszben boolean logLimit = Objects.equals(servletRequest.getContentType(), MediaType.APPLICATION_OCTET_STREAM); - return printRequestEntity(requestEntity, logLimit ? RequestResponseLogger.ENTITY_MAX_LOG : null); + return printRequestEntity(requestEntity, logLimit ? RequestResponseLogger.BYTECODE_MAX_LOG : null); } catch (IllegalStateException e) { log.info("Inputstream is already readed from servletRequest: " + e.getLocalizedMessage(), e); } catch (IOException e) { diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/BaseRestLoggerOptimized.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/BaseRestLoggerOptimized.java new file mode 100644 index 000000000..b0742b6b9 --- /dev/null +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/BaseRestLoggerOptimized.java @@ -0,0 +1,245 @@ +/*- + * #%L + * Coffee + * %% + * Copyright (C) 2020 - 2023 i-Cell Mobilsoft Zrt. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package hu.icellmobilsoft.coffee.rest.log.optimized; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; + +import jakarta.inject.Inject; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.container.ContainerRequestFilter; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.core.Response.Status; +import jakarta.ws.rs.core.UriInfo; +import jakarta.ws.rs.ext.WriterInterceptor; +import jakarta.ws.rs.ext.WriterInterceptorContext; + +import org.apache.commons.lang3.StringUtils; + +import hu.icellmobilsoft.coffee.cdi.logger.AppLogger; +import hu.icellmobilsoft.coffee.cdi.logger.ThisLogger; +import hu.icellmobilsoft.coffee.dto.common.LogConstants; +import hu.icellmobilsoft.coffee.rest.cdi.BaseApplicationContainer; +import hu.icellmobilsoft.coffee.rest.log.RequestResponseLogger; +import hu.icellmobilsoft.coffee.rest.log.annotation.LogSpecifier; +import hu.icellmobilsoft.coffee.rest.log.annotation.enumeration.LogSpecifierTarget; +import hu.icellmobilsoft.coffee.rest.utils.RestLoggerUtil; +import hu.icellmobilsoft.coffee.se.logging.mdc.MDC; +import hu.icellmobilsoft.coffee.tool.utils.stream.RequestLoggerInputStream; +import hu.icellmobilsoft.coffee.tool.utils.stream.ResponseEntityCollectorOutputStream; +import hu.icellmobilsoft.coffee.tool.utils.string.RandomUtil; + +/** + * Base class for REST logging + * + * @author ischeffer + * @author mate.biro + * @since 2.4.0 + */ +public abstract class BaseRestLoggerOptimized implements ContainerRequestFilter, WriterInterceptor { + + @Inject + @ThisLogger + private AppLogger log; + + @Inject + private BaseApplicationContainer baseApplicationContainer; + + @Inject + private RequestResponseLoggerOptimized requestResponseLogger; + + @Context + private UriInfo uriInfo; + + @Context + private HttpServletResponse httpServletResponse; + + /** {@inheritDoc} */ + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + MDC.clear(); + MDC.put(LogConstants.LOG_SERVICE_NAME, baseApplicationContainer.getCoffeeAppName()); + processRequest(requestContext); + } + + /** {@inheritDoc} */ + @Override + public void aroundWriteTo(WriterInterceptorContext context) throws IOException { + processResponse(context); + } + + /** + * Processes HTTP request. + * + * @param requestContext + * context + */ + protected void processRequest(ContainerRequestContext requestContext) { + if (RestLoggerUtil.logDisabled(requestContext, LogSpecifierTarget.REQUEST)) { + return; + } + + var logMessage = new StringBuilder(); + appendRequestLine(logMessage, requestContext); + appendRequestHeaders(logMessage, requestContext); + + int maxRequestEntityLogSize = requestResponseLogger.getMaxRequestEntityLogSize(requestContext); + + var requestLoggerInputStream = new RequestLoggerInputStream( + requestContext.getEntityStream(), + maxRequestEntityLogSize, + RequestResponseLogger.REQUEST_PREFIX, + logMessage); + + // a saját InputStream-et állítjuk be a context-be, ami majd az entity stream olvasáskor log-olja a request-et + requestContext.setEntityStream(requestLoggerInputStream); + } + + /** + * Processes HTTP response. + * + * @param context + * context + * @throws IOException + * if response cannot be processed. + */ + @SuppressWarnings("Var") + protected void processResponse(WriterInterceptorContext context) throws IOException { + if (RestLoggerUtil.logDisabled(context, LogSpecifierTarget.RESPONSE)) { + context.proceed(); + return; + } + + StringBuilder message = new StringBuilder(); + try { + printResponseLine(message, context); + printResponseHeaders(message, context); + + OutputStream originalResponseStream = context.getOutputStream(); + byte[] entity = new byte[0]; + int maxResponseEntityLogSize = requestResponseLogger.getMaxResponseEntityLogSize(context); + if (maxResponseEntityLogSize != LogSpecifier.NO_LOG) { + var responseEntityCollectorOutputStream = new ResponseEntityCollectorOutputStream(originalResponseStream, maxResponseEntityLogSize); + // a saját OutputStream-et állítjuk be a context-be, ami majd az entity stream-be írásakor gyűjti azt a log-olás számára + context.setOutputStream(responseEntityCollectorOutputStream); + context.proceed(); + entity = responseEntityCollectorOutputStream.getEntityText().getBytes(StandardCharsets.UTF_8); + } else { + context.proceed(); + } + + printResponseEntity(message, context, entity); + } finally { + log.info(message.toString()); + } + } + + /** + * HTTP headerben szereplo session kulcs neve. Ezt a kulcsot fogja a logger keresni a http headerekből, aminek az értékét fel használja a + * MDC.put(LogConstants.LOG_SESSION_ID, ertek) részben.
+ *
+ * Folyamat azonosítás, Graylog loggolásban van nagy értelme + * + * @return session key + */ + public abstract String sessionKey(); + + /** + * Prints request headers from {@link ContainerRequestContext} and appends given {@link StringBuilder} with the print result. + * + * @param b + * request message + * @param requestContext + * context + * @see RequestResponseLoggerOptimized#printRequestHeaders(java.util.Map) + */ + protected void appendRequestHeaders(StringBuilder b, ContainerRequestContext requestContext) { + MultivaluedMap headers = requestContext.getHeaders(); + b.append(requestResponseLogger.printRequestHeaders(headers)); + String sessionId = null; + if (headers != null && headers.containsKey(sessionKey())) { + sessionId = headers.get(sessionKey()).get(0); + } + MDC.put(LogConstants.LOG_SESSION_ID, StringUtils.defaultIfBlank(sessionId, RandomUtil.generateId())); + } + + /** + * Prints http path info from {@link ContainerRequestContext} and appends given {@link StringBuilder} with the print result. + * + * @param b + * request message + * @param requestContext + * context + * @see RequestResponseLoggerOptimized#printRequestLine(ContainerRequestContext) + */ + protected void appendRequestLine(StringBuilder b, ContainerRequestContext requestContext) { + b.append(requestResponseLogger.printRequestLine(requestContext)); + } + + /** + * Prints response URL line and appends given {@link StringBuilder} with the print result. + * + * @param b + * response message + * @param context + * context + * @see RequestResponseLoggerOptimized#printResponseLine(String, int, String, String) + */ + protected void printResponseLine(StringBuilder b, WriterInterceptorContext context) { + String fullPath = uriInfo.getAbsolutePath().toASCIIString(); + int status = httpServletResponse.getStatus(); + Status statusEnum = Status.fromStatusCode(status); + String statusInfo = statusEnum != null ? statusEnum.getReasonPhrase() : null; + MediaType mediaType = context.getMediaType(); + b.append(requestResponseLogger.printResponseLine(fullPath, status, String.valueOf(statusInfo), String.valueOf(mediaType))); + } + + /** + * Prints response header values and appends given {@link StringBuilder} with the print result. + * + * @param b + * response message + * @param context + * context + * @see RequestResponseLoggerOptimized#printResponseHeaders(java.util.Map) + */ + protected void printResponseHeaders(StringBuilder b, WriterInterceptorContext context) { + b.append(requestResponseLogger.printResponseHeaders(context.getHeaders())); + } + + /** + * Prints response from {@link WriterInterceptorContext} and appends given {@link StringBuilder} with the print result. + * + * @param b + * response message + * @param context + * context + * @param entityCopy + * entity + * @see RequestResponseLoggerOptimized#printResponseEntity(String, WriterInterceptorContext, byte[]) + */ + protected void printResponseEntity(StringBuilder b, WriterInterceptorContext context, byte[] entityCopy) { + b.append(requestResponseLogger.printResponseEntity(uriInfo.getAbsolutePath().toASCIIString(), context, entityCopy)); + } +} diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/RequestResponseLoggerOptimized.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/RequestResponseLoggerOptimized.java new file mode 100644 index 000000000..4a3b674cb --- /dev/null +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/RequestResponseLoggerOptimized.java @@ -0,0 +1,459 @@ +/*- + * #%L + * Coffee + * %% + * Copyright (C) 2020 - 2023 i-Cell Mobilsoft Zrt. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package hu.icellmobilsoft.coffee.rest.log.optimized; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import jakarta.enterprise.context.Dependent; +import jakarta.inject.Inject; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.container.ContainerResponseContext; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.UriInfo; +import jakarta.ws.rs.ext.WriterInterceptorContext; + +import org.apache.commons.lang3.StringUtils; + +import hu.icellmobilsoft.coffee.cdi.logger.AppLogger; +import hu.icellmobilsoft.coffee.cdi.logger.ThisLogger; +import hu.icellmobilsoft.coffee.rest.log.annotation.LogSpecifier; +import hu.icellmobilsoft.coffee.rest.log.annotation.enumeration.LogSpecifierTarget; +import hu.icellmobilsoft.coffee.rest.utils.RestLoggerUtil; +import hu.icellmobilsoft.coffee.tool.gson.JsonUtil; +import hu.icellmobilsoft.coffee.tool.utils.marshalling.MarshallingUtil; +import hu.icellmobilsoft.coffee.tool.utils.string.StringHelper; + +/** + * Request - Response logger class + * + * @author imre.scheffer + * @author mate.biro + * @since 2.4.0 + */ +@Dependent +public class RequestResponseLoggerOptimized { + + /** Constant NOTIFICATION_PREFIX="* " */ + public static final String NOTIFICATION_PREFIX = "* "; + /** Constant REQUEST_PREFIX="> " */ + public static final String REQUEST_PREFIX = "> "; + /** Constant RESPONSE_PREFIX="< " */ + public static final String RESPONSE_PREFIX = "< "; + + /** Constant ENTITY_MAX_LOG=5000 */ + public static final int ENTITY_MAX_LOG = 5000; + + /** Constant SKIP_MEDIATYPE_SUBTYPE_PDF="pdf" */ + public static final String SKIP_MEDIATYPE_SUBTYPE_PDF = "pdf"; + /** Constant SKIP_MEDIATYPE_SUBTYPE_CSV="csv" */ + public static final String SKIP_MEDIATYPE_SUBTYPE_CSV = "csv"; + /** Constant SKIP_MEDIATYPE_SUBTYPE_SHEET="sheet" */ + public static final String SKIP_MEDIATYPE_SUBTYPE_SHEET = "sheet"; + /** Constant SKIP_PATH_POSTFIX_WADL=".wadl" */ + public static final String SKIP_PATH_POSTFIX_WADL = ".wadl"; + /** Constant SKIP_PATH_POSTFIX_XSD=".xsd" */ + public static final String SKIP_PATH_POSTFIX_XSD = ".xsd"; + + @Inject + @ThisLogger + private AppLogger log; + + /** + * Prints request headers to {@link String}. Masks password. + * + * @param headerValues + * http header key and list of values + * @return HTTP request header or null if invalid parameter + */ + protected String printRequestHeaders(Map> headerValues) { + StringBuffer sb = new StringBuffer(); + sb.append(REQUEST_PREFIX).append("-- Header parameters:").append('\n'); + if (headerValues == null) { + return sb.toString(); + } + for (Map.Entry> param : headerValues.entrySet()) { + for (String value : param.getValue()) { + String key = param.getKey(); + sb.append(REQUEST_PREFIX).append(key).append(": ").append(StringHelper.maskPropertyValue(key, value)).append('\n'); + } + } + sb.append(REQUEST_PREFIX).append('\n'); + return sb.toString(); + } + + /** + * Prints http headers info from {@link ContainerRequestContext}. + * + * @param requestContext + * context + * @return HTTP headers info or null if invalid parameter + */ + public String printRequestHeaders(ContainerRequestContext requestContext) { + if (requestContext == null) { + return null; + } + return printRequestHeaders(requestContext.getHeaders()); + } + + /** + * Prints http headers info from {@link HttpServletRequest}. + * + * @param servletRequest + * request + * @return HTTP headers info or null if invalid parameter + */ + public String printRequestHeaders(HttpServletRequest servletRequest) { + if (servletRequest == null) { + return null; + } + Map> map = new HashMap<>(); + + Enumeration headerNames = servletRequest.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String key = headerNames.nextElement(); + map.put(key, Collections.list(servletRequest.getHeaders(key))); + } + return printRequestHeaders(map); + } + + /** + * Prints http request url line. + * + * @param method + * POST, GET, PUT, ... + * @param fullPath + * full url path + * @param pathParameters + * path parameters + * @param queryParameters + * query parameters + * @return HTTP request URL line + */ + protected String printRequestLine(String method, String fullPath, Map> pathParameters, + Map> queryParameters) { + StringBuffer sb = new StringBuffer(); + sb.append(NOTIFICATION_PREFIX).append("Server in-bound request").append('\n'); + sb.append(REQUEST_PREFIX).append(method).append(" ").append(fullPath).append('\n'); + sb.append(REQUEST_PREFIX).append("-- Path parameters:").append('\n'); + if (pathParameters != null) { + for (Map.Entry> param : pathParameters.entrySet()) { + sb.append(REQUEST_PREFIX).append(param.getKey()).append(": ").append(param.getValue()).append('\n'); + } + } + sb.append(REQUEST_PREFIX).append("-- Query parameters:").append('\n'); + if (queryParameters != null) { + for (Map.Entry> param : queryParameters.entrySet()) { + sb.append(REQUEST_PREFIX).append(param.getKey()).append(": ").append(param.getValue()).append('\n'); + } + } + return sb.toString(); + } + + /** + * Print http path info from {@link HttpServletRequest}. + * + * @param servletRequest + * context + * @return HTTP path info or null if invalid parameter + */ + public String printRequestLine(HttpServletRequest servletRequest) { + if (servletRequest == null) { + return null; + } + Map> queryParameters = new HashMap<>(); + for (Map.Entry param : servletRequest.getParameterMap().entrySet()) { + queryParameters.put(param.getKey(), Arrays.asList(param.getValue())); + } + // HttpServletRequest nem tudja a path parametereket kiolvasni, ezert emptyMap-ot adunk be + return printRequestLine(servletRequest.getMethod(), servletRequest.getRequestURL().toString(), Collections.emptyMap(), queryParameters); + } + + /** + * Prints http path info from {@link ContainerRequestContext}. + * + * @param requestContext + * context + * @return HTTP path info or null if invalid parameter + */ + public String printRequestLine(ContainerRequestContext requestContext) { + if (requestContext == null) { + return null; + } + UriInfo uriInfo = requestContext.getUriInfo(); + return printRequestLine( + requestContext.getMethod(), + uriInfo.getAbsolutePath().toASCIIString(), + uriInfo.getPathParameters(), + uriInfo.getQueryParameters()); + } + + /** + * Prints request entity to {@link String}. Masks password. + * + * @param entity + * entity + * @param maxLogSize + * max size for log + * @throws IOException + * if cannot be read + * @return request entity + * @see #printEntity(byte[], Integer, String) + */ + public String printRequestEntity(byte[] entity, Integer maxLogSize) throws IOException { + return printEntity(entity, maxLogSize, REQUEST_PREFIX); + } + + /** + * Prints request entity to {@link String}. Masks password. + * + * @param entity + * entity + * @param maxLogSize + * max size for log + * @param prefix + * prefix for log + * @return entity {@code String} + * @throws IOException + * if cannot be read + */ + public String printEntity(byte[] entity, Integer maxLogSize, String prefix) throws IOException { + String requestText = entityToString(entity, maxLogSize); + String maskedText = StringHelper.maskValueInXmlJson(requestText); + return prefix + "entity: [" + maskedText + "]\n"; + } + + private String entityToString(byte[] entity, Integer maxLogSize) { + if (entity == null) { + return null; + } + if (entity.length == 0) { + return ""; + } + // input parameter szerint korlatozzuk a logot + byte[] requestEntityPart = entity; + if (maxLogSize != null && maxLogSize >= LogSpecifier.NO_LOG && entity.length > maxLogSize.intValue()) { + requestEntityPart = Arrays.copyOf(entity, maxLogSize); + } + + return new String(requestEntityPart, StandardCharsets.UTF_8); + } + + /** + * Returns the maximum request entity log size + * + * @param requestContext + * context + * + * @return the maximum log size of the entity + */ + protected int getMaxRequestEntityLogSize(ContainerRequestContext requestContext) { + // ha octet-stream vagy multipart és nincs LogSpecifier annotáció, akkor korlátozunk + if (RestLoggerUtil.isLogSizeLimited(requestContext, MediaType.APPLICATION_OCTET_STREAM_TYPE, MediaType.MULTIPART_FORM_DATA_TYPE) + && !RestLoggerUtil.isLogSpecifierPresent(requestContext)) { + return RequestResponseLoggerOptimized.ENTITY_MAX_LOG; + } + + // különben annotációban meghatározott maxEntityLogSize (ha nincs annotáció, akkor unlimit) + return RestLoggerUtil.getMaxEntityLogSize(requestContext, LogSpecifierTarget.REQUEST); + } + + /** + * Returns the maximum response entity log size + * + * @param context + * {@link WriterInterceptorContext} + * + * @return the maximum log size of the entity + */ + protected int getMaxResponseEntityLogSize(WriterInterceptorContext context) { + // ha octet-stream vagy multipart és nincs LogSpecifier annotáció, akkor korlátozunk + if (RestLoggerUtil.isLogSizeLimited(context, MediaType.APPLICATION_OCTET_STREAM_TYPE, MediaType.MULTIPART_FORM_DATA_TYPE) + && !RestLoggerUtil.isLogSpecifierPresent(context)) { + return RequestResponseLoggerOptimized.ENTITY_MAX_LOG; + } + + // különben annotációban meghatározott maxEntityLogSize (ha nincs annotáció, akkor unlimit) + return RestLoggerUtil.getMaxEntityLogSize(context, LogSpecifierTarget.RESPONSE); + } + + /** + * Prints response URL line. + * + * @param fullPath + * full url path from request + * @param httpStatus + * 400, 401, 500, ... + * @param statusInfo + * OK, ERROR + * @param mediaType + * application/json, text/xml, ... + * @return response URL line + */ + protected String printResponseLine(String fullPath, int httpStatus, String statusInfo, String mediaType) { + StringBuffer sb = new StringBuffer(); + sb.append(RESPONSE_PREFIX).append("Server response from [").append(fullPath).append("]:\n"); + sb.append(RESPONSE_PREFIX).append("Status: [").append(httpStatus).append("], [").append(statusInfo).append("]\n"); + sb.append(RESPONSE_PREFIX).append("Media type: [").append(mediaType).append("]\n"); + return sb.toString(); + } + + /** + * Prints response URL line. + * + * @param requestContext + * request context + * @param responseContext + * response context + * @return response URL line + * @see #printResponseLine(String, int, String, String) + */ + public String printResponseLine(ContainerRequestContext requestContext, ContainerResponseContext responseContext) { + if (requestContext == null || responseContext == null) { + return null; + } + return printResponseLine( + requestContext.getUriInfo().getAbsolutePath().toASCIIString(), + responseContext.getStatus(), + String.valueOf(responseContext.getStatusInfo()), + String.valueOf(responseContext.getMediaType())); + } + + /** + * Prints response header values. + * + * @param headerValues + * {@link Map} of header values + * @return header parameter values + */ + public String printResponseHeaders(Map> headerValues) { + StringBuffer sb = new StringBuffer(); + sb.append(RESPONSE_PREFIX).append("-- Header parameters:").append('\n'); + if (headerValues == null) { + return sb.toString(); + } + for (Map.Entry> param : headerValues.entrySet()) { + sb.append(RESPONSE_PREFIX).append(param.getKey()).append(": ").append(param.getValue()).append('\n'); + } + return sb.toString(); + } + + /** + * Prints response entity object. Tries to print as String or json object. + * + * @param entity + * entity to log + * @param mediaType + * media type of entity if relevant + * @return entity in string + */ + protected String printResponseEntity(Object entity, MediaType mediaType) { + return printEntity(entity, RequestResponseLoggerOptimized.RESPONSE_PREFIX, false, mediaType); + } + + /** + * Prints entity object. Tries to print as String or json object. + * + * @param entity + * entity to log + * @param prefix + * log prefix + * @param maskingNeeded + * is masking sensitive data needed + * @param mediaType + * media type of entity if relevant + * @return entity in string + */ + public String printEntity(Object entity, String prefix, boolean maskingNeeded, MediaType mediaType) { + if (entity == null) { + return null; + } + StringBuffer sb = new StringBuffer(); + String entityText; + if (entity instanceof String) { + entityText = (String) entity; + } else if (mediaType != null && MediaType.APPLICATION_JSON_TYPE.getSubtype().equals(mediaType.getSubtype())) { + entityText = JsonUtil.toJson(entity); + } else if (mediaType != null && (MediaType.APPLICATION_XML_TYPE.getSubtype().equals(mediaType.getSubtype()) // + || MediaType.APPLICATION_ATOM_XML_TYPE.getSubtype().equals(mediaType.getSubtype()))) { + entityText = MarshallingUtil.marshall(entity); + } else { + entityText = entity.toString(); + } + + if (maskingNeeded) { + entityText = StringHelper.maskValueInXmlJson(entityText); + } + + sb.append(prefix).append("entity: [").append(entityText).append("]\n"); + return sb.toString(); + } + + /** + * Skipping default specified url and mediaType for entity logging. + * + * @param fullPath + * URL path to skip + * @param mediaType + * media type to skip + * @return if entity logging is skipped + */ + protected boolean skipLoggingForPathOrMediaType(String fullPath, MediaType mediaType) { + return mediaType != null && (StringUtils.containsIgnoreCase(mediaType.getSubtype(), SKIP_MEDIATYPE_SUBTYPE_PDF) + || StringUtils.containsIgnoreCase(mediaType.getSubtype(), SKIP_MEDIATYPE_SUBTYPE_CSV) + || StringUtils.containsIgnoreCase(mediaType.getSubtype(), SKIP_MEDIATYPE_SUBTYPE_SHEET) + || StringUtils.containsIgnoreCase(fullPath, SKIP_PATH_POSTFIX_WADL) + || StringUtils.containsIgnoreCase(fullPath, SKIP_PATH_POSTFIX_XSD)); + } + + /** + * Print response from {@link WriterInterceptorContext}. Printing is disabled in some stream situation. + * + * @param fullPath + * URL path + * @param writerInterceptorContext + * context + * @param entityCopy + * entity + * @return response + */ + public String printResponseEntity(String fullPath, WriterInterceptorContext writerInterceptorContext, byte[] entityCopy) { + StringBuffer sb = new StringBuffer(); + if (writerInterceptorContext == null) { + return sb.toString(); + } + MediaType mediaType = writerInterceptorContext.getMediaType(); + if (skipLoggingForPathOrMediaType(fullPath, mediaType)) { + sb.append(RequestResponseLoggerOptimized.RESPONSE_PREFIX) + .append("Response outputstream logging disabled, because MediaType: [" + mediaType + "]\n"); + } else { + String responseText = new String(entityCopy, StandardCharsets.UTF_8); + sb.append(printResponseEntity(responseText, mediaType)); + } + return sb.toString(); + } +} diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/utils/RestLoggerUtil.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/utils/RestLoggerUtil.java index 6141c153c..ed16de77e 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/utils/RestLoggerUtil.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/utils/RestLoggerUtil.java @@ -22,13 +22,13 @@ import java.lang.annotation.Annotation; import java.util.Arrays; -import org.apache.commons.lang3.StringUtils; - import jakarta.ws.rs.client.ClientRequestContext; import jakarta.ws.rs.container.ContainerRequestContext; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.ext.WriterInterceptorContext; +import org.apache.commons.lang3.StringUtils; + import hu.icellmobilsoft.coffee.rest.log.annotation.LogSpecifier; import hu.icellmobilsoft.coffee.rest.log.annotation.LogSpecifiers; import hu.icellmobilsoft.coffee.rest.log.annotation.enumeration.LogSpecifierTarget; @@ -250,6 +250,27 @@ public static boolean isLogSizeLimited(ContainerRequestContext requestContext, M return false; } + /** + * Returns true if the {@link MediaType} of the request context matches one of the given ones + * + * @param context + * {@link WriterInterceptorContext} + * @param mediaTypes + * {@link MediaType}s to compare + * @return true if there is a matching {@code MediaType} + */ + public static boolean isLogSizeLimited(WriterInterceptorContext context, MediaType... mediaTypes) { + if (context == null || mediaTypes == null) { + return false; + } + for (MediaType mediaType : mediaTypes) { + if (RestLoggerUtil.isSameMediaTypeWithoutCharset(context.getMediaType(), mediaType)) { + return true; + } + } + return false; + } + /** * Returns true if {@link MediaType}s are the same irrespective of charset * @@ -271,4 +292,66 @@ private static boolean isSameMediaTypeWithoutCharset(MediaType mediaType1, Media return (StringUtils.equals(type1, type2) && StringUtils.equals(subtype1, subtype2)); } + + /** + * Checks if {@link LogSpecifier} annotation is present. + * + * @param requestContext + * context + * @return if {@link LogSpecifier} annotation is present + */ + public static boolean isLogSpecifierPresent(ContainerRequestContext requestContext) { + if (requestContext == null) { + return false; + } + LogSpecifiers logSpecifiers = RequestUtil.getAnnotation(requestContext, LogSpecifiers.class); + if (logSpecifiers != null) { + return isLogSpecifierPresent(logSpecifiers.value()); + } else { + LogSpecifier logSpecifier = RequestUtil.getAnnotation(requestContext, LogSpecifier.class); + return isLogSpecifierPresent(logSpecifier); + } + } + + /** + * Checks if {@link LogSpecifier} annotation is present. + * + * @param context + * {@link WriterInterceptorContext} + * @return if {@link LogSpecifier} annotation is present + */ + public static boolean isLogSpecifierPresent(WriterInterceptorContext context) { + if (context == null) { + return false; + } + Annotation[] annotations = context.getAnnotations(); + if (annotations != null) { + for (Annotation a : annotations) { + if (a instanceof LogSpecifiers) { + return isLogSpecifierPresent(((LogSpecifiers) a).value()); + } else if (a instanceof LogSpecifier) { + return isLogSpecifierPresent(((LogSpecifier) a)); + } + } + } + return false; + } + + /** + * Returns if {@link LogSpecifier} is present or not + * + * @param logSpecifiers + * {@link LogSpecifier}s to check + * @return if {@link LogSpecifier} is present + */ + public static boolean isLogSpecifierPresent(LogSpecifier... logSpecifiers) { + if (logSpecifiers != null) { + for (LogSpecifier logSpecifier : logSpecifiers) { + if (logSpecifier != null) { + return true; + } + } + } + return false; + } } diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingEvent.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingEvent.java new file mode 100644 index 000000000..3cf1495e5 --- /dev/null +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingEvent.java @@ -0,0 +1,50 @@ +/*- + * #%L + * Coffee + * %% + * Copyright (C) 2020 - 2023 i-Cell Mobilsoft Zrt. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package hu.icellmobilsoft.coffee.tool.utils.stream; + +/** + * Logging event containing the message + * + * @author mate.biro + * @since 2.4.0 + */ +public class LoggingEvent { + + private String message; + + /** + * Constructor + * + * @param message + * message to be logged + */ + public LoggingEvent(String message) { + this.message = message; + } + + /** + * Getter + * + * @return the message + */ + public String getMessage() { + return message; + } +} diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingObserver.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingObserver.java new file mode 100644 index 000000000..062af42e3 --- /dev/null +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingObserver.java @@ -0,0 +1,51 @@ +/*- + * #%L + * Coffee + * %% + * Copyright (C) 2020 - 2023 i-Cell Mobilsoft Zrt. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package hu.icellmobilsoft.coffee.tool.utils.stream; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; + +import hu.icellmobilsoft.coffee.cdi.logger.AppLogger; +import hu.icellmobilsoft.coffee.cdi.logger.ThisLogger; + +/** + * Observer for logging + * + * @author mate.biro + * @since 2.4.0 + */ +@ApplicationScoped +public class LoggingObserver { + + @Inject + @ThisLogger + private AppLogger log; + + /** + * Observer method that logs the message + * + * @param event + * containing the message to be logged + */ + public void observe(@Observes LoggingEvent event) { + log.info(event.getMessage()); + } +} diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingPublisher.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingPublisher.java new file mode 100644 index 000000000..38d885922 --- /dev/null +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingPublisher.java @@ -0,0 +1,47 @@ +/*- + * #%L + * Coffee + * %% + * Copyright (C) 2020 - 2023 i-Cell Mobilsoft Zrt. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package hu.icellmobilsoft.coffee.tool.utils.stream; + +import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.event.Event; +import jakarta.inject.Inject; + +/** + * Logging event publisher + * + * @author mate.biro + * @since 2.4.0 + */ +@Dependent +public class LoggingPublisher { + + @Inject + private Event loggingEvent; + + /** + * Publisher method for the logging event + * + * @param event + * containing the message to be logged + */ + public void publish(LoggingEvent event) { + loggingEvent.fire(event); + } +} diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java index 460d6c154..b9d3e12f2 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java @@ -21,103 +21,81 @@ import java.io.IOException; import java.io.InputStream; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import jakarta.enterprise.inject.Vetoed; +import jakarta.enterprise.inject.spi.CDI; -import hu.icellmobilsoft.coffee.cdi.logger.AppLogger; import hu.icellmobilsoft.coffee.tool.utils.string.StringHelper; /** * Custom {@link InputStream} for logging request with entity * * @author mate.biro - * @since 1.14.0 + * @since 1.15.0 */ -@Vetoed @SuppressWarnings("InputStreamSlowMultibyteRead") public class RequestLoggerInputStream extends InputStream { private final InputStream inputStream; private final String requestPrefix; - private final StringBuilder entity = new StringBuilder(); - private final StringBuilder message; - private final BiConsumer, Class> logger; - private final Consumer loggerConsumer; - private final Class clazz; - private int logReadLimit; - private boolean firstReadCycle = true; + private final StringBuilder entityLog = new StringBuilder(); + private final StringBuilder logMessage; + private int logCollectLimit; + private boolean isLogged = false; /** * Constructor * - * @param inputStream - * original inputStream - * @param logReadLimit + * @param requestEntityStream + * original requestEntityStream + * @param logCollectLimit * read limit * @param requestPrefix * request log prefix - * @param message + * @param logMessage * log message - * @param logger - * the function handling {@link AppLogger} - * @param loggerConsumer - * the function doing the logging - * @param clazz - * class for logging */ - public RequestLoggerInputStream(InputStream inputStream, int logReadLimit, String requestPrefix, StringBuilder message, - BiConsumer, Class> logger, Consumer loggerConsumer, Class clazz) { - this.inputStream = inputStream; - this.logReadLimit = logReadLimit; + public RequestLoggerInputStream(InputStream requestEntityStream, int logCollectLimit, String requestPrefix, StringBuilder logMessage) { + this.inputStream = requestEntityStream; + this.logCollectLimit = logCollectLimit; this.requestPrefix = requestPrefix; - this.message = message; - this.logger = logger; - this.loggerConsumer = loggerConsumer; - this.clazz = clazz; + this.logMessage = logMessage; } /** * {@inheritDoc} * - * Extra functionality: On first read cycle it appends the read request entity data from the original {@link InputStream} to an internal - * {@link StringBuilder} until a given limit is reached (or until the end of stream if limit is higher). Then logs the given request message with - * the appended request entity. + *
+ * Extra functionality: On read the request entity data is appended from the original {@link InputStream} to an internal {@link StringBuilder} + * until a given limit is reached (or until the end of stream if log limit exceeds the length of the stream). Then publishes an event to log the + * given request message with the appended request entity. * */ @Override public int read() throws IOException { int streamData = inputStream.read(); - buildEntity(streamData); - logRequestWithEntity(streamData); + if (streamData != -1 && logCollectLimit != 0) { + // logoláshoz gyűjtjük a stream tartalmát amíg van, és még nem értük el a limitet + entityLog.append((char) streamData); + logCollectLimit--; + } else if (!isLogged) { + // ha a stream végére értünk vagy elértük a limitet és még nem logoltunk, + // akkor küldünk egy eventet hogy megtörténjen a logolás + String maskedEntityLog = getMaskedEntity(entityLog.toString()); + logMessage.append(maskedEntityLog); - return streamData; - } + LoggingEvent event = new LoggingEvent(logMessage.toString()); + LoggingPublisher loggingPublisher = CDI.current().select(LoggingPublisher.class).get(); + loggingPublisher.publish(event); - private void buildEntity(int streamData) { - // logoláshoz gyűjtjük a stream tartalmát amíg van, és még nem értük el a limitet - if (!firstReadCycle || streamData == -1 || logReadLimit == 0) { - return; + isLogged = true; } - entity.append((char) streamData); - logReadLimit--; - } - private void logRequestWithEntity(int streamData) { - // ha a stream végére értünk vagy elértük a limitet, akkor logolunk - if (!firstReadCycle || (streamData != -1 && logReadLimit != 0)) { - return; - } - String maskedEntity = getMaskedEntity(entity.toString(), requestPrefix); - message.append(maskedEntity); - logger.accept(loggerConsumer, clazz); - firstReadCycle = false; + return streamData; } - private String getMaskedEntity(String requestText, String prefix) { - String maskedText = StringHelper.maskValueInXmlJson(requestText); - return prefix + "entity: [" + maskedText + "]\n"; + private String getMaskedEntity(String entityLogText) { + String maskedText = StringHelper.maskValueInXmlJson(entityLogText); + return requestPrefix + "entity: [" + maskedText + "]\n"; } } diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java index a5b2da84e..895ecd6f0 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/ResponseEntityCollectorOutputStream.java @@ -22,47 +22,46 @@ import java.io.IOException; import java.io.OutputStream; -import jakarta.enterprise.inject.Vetoed; - /** * Custom {@link OutputStream} for collecting response entity * * @author mate.biro - * @since 1.14.0 + * @since 2.4.0 */ -@Vetoed public class ResponseEntityCollectorOutputStream extends OutputStream { - private final OutputStream outputStream; - private final StringBuilder entity = new StringBuilder(); - private int collectLimit; + private final OutputStream originalResponseStream; + private final StringBuilder entityLog = new StringBuilder(); + private int logCollectLimit; /** * Constructor * - * @param outputStream - * original outputStream - * @param collectLimit + * @param originalResponseStream + * the original intercepted output stream + * @param logCollectLimit * collect limit */ - public ResponseEntityCollectorOutputStream(OutputStream outputStream, int collectLimit) { - this.outputStream = outputStream; - this.collectLimit = collectLimit; + public ResponseEntityCollectorOutputStream(OutputStream originalResponseStream, int logCollectLimit) { + this.originalResponseStream = originalResponseStream; + this.logCollectLimit = logCollectLimit; } /** * {@inheritDoc} * + *
* Extra functionality: It appends the response entity data written to the original {@link OutputStream} to an internal {@link StringBuilder} * until the given limit has been reached. */ @Override public void write(int b) throws IOException { - if (collectLimit != 0) { - entity.append((char) b); - collectLimit--; + if (logCollectLimit != 0) { + // logoláshoz gyűjtjük a stream tartalmát amíg még nem értük el a limitet + entityLog.append((char) b); + logCollectLimit--; } - outputStream.write(b); + originalResponseStream.write(b); } /** @@ -71,6 +70,6 @@ public void write(int b) throws IOException { * @return Entity text */ public String getEntityText() { - return entity.toString(); + return entityLog.toString(); } } diff --git a/docs/hu/common/core/coffee-rest.adoc b/docs/hu/common/core/coffee-rest.adoc index f28ade2e3..6fa63e95f 100644 --- a/docs/hu/common/core/coffee-rest.adoc +++ b/docs/hu/common/core/coffee-rest.adoc @@ -4,6 +4,7 @@ Modul célja a REST kommunikáció és a kezelése. Tartalmazza az apache http klienst, különböző REST loggereket és filtereket. Továbbá a nyelvesítés, REST aktivátor és Response util osztály is itt található. +[#common_core_coffee-rest_BaseRestLogger] == BaseRestLogger Az osztály célja, hogy loggolja az alkalmazásba érkező HTTP request-response kéréseket. Aktiválása kézzel történik, projekt szinten a következő minta alapján: @@ -86,6 +87,38 @@ amennyiben a projekten szükséges, úgy a regex felülírható ha valamelyik *a < entity: [{"transactionId":"2G7XOSYJ6VUEJJ09","header":{"requestId":"RID314802331803","timestamp":"2019-02-01T15:31:32.432Z","requestVersion":"1.1","headerVersion":"1.0"},"result":{"funcCode":"OK"},"software":{"softwareId":"123456789123456789","softwareName":"string","softwareOperation":"LOCAL_SOFTWARE","softwareMainVersion":"string","softwareDevName":"string","softwareDevContact":"string","softwareCountryCode":"HU","softwareDescription":"string"}] ---- +[#common_core_coffee-rest_BaseRestLoggerOptimized] +== BaseRestLoggerOptimized +Az osztály hasonlóan működik mint a <> annyi eltéréssel, hogy kevesebb memóriát használ fel azáltal, +hogy a request és response entity-ket nem a stream-ek másolásával szerzi meg a logolás számára, hanem az entity stream olvasása és írása közben gyűjti azokat. + +Aktiválása kézzel történik, projekt szinten a következő minta alapján: + +.Projektben aktiválás +[source,java] +---- +package hu.icellmobilsoft.project.common.rest.logger; +import javax.inject.Inject; +import javax.ws.rs.ext.Provider; +import hu.icellmobilsoft.coffee.cdi.logger.AppLogger; +import hu.icellmobilsoft.coffee.cdi.logger.ThisLogger; +import hu.icellmobilsoft.coffee.dto.common.LogConstants; +import hu.icellmobilsoft.coffee.rest.log.optimized.BaseRestLoggerOptimized; +@Provider // <1> +public class RestLogger extends BaseRestLoggerOptimized { + @Inject + @ThisLogger + private AppLogger log; + @Override + public String sessionKey() { // <2> + return LogConstants.LOG_SESSION_ID; + } +} +---- +<1> JAX-RS aktivátor (ez a lényeg ami aktiválja) +<2> HTTP headerben szereplő session azonosító kulcs neve + + [#common_core_coffee-rest_LogSpecifier] == LogSpecifier A REST logolás végpontonként testreszabható a `hu.icellmobilsoft.coffee.rest.log.annotation.LogSpecifier` annotációval, @@ -113,7 +146,9 @@ Jelenleg a LogSpecifier a következő esetekre van felkészítve: * a végponton a request-response logolása kikapcsolható a `LogSpecifier` annotáció `noLog` kapcsolójával. * a végponton a kilogolt body méretét a `LogSpecifier` annotáció `maxEntityLogSize` mezőjével lehet korlátozni. -IMPORTANT: ha a `maxEntityLogSize` a `LogSpecifier.NO_LOG`-tól *eltérő* értékre van állítva, akkor a REST endpoint-hoz érkező `application/octet-stream`, `multipart/form-data`, `application/json`, `application/xml` és `text/xml` mediaType-ok esetében csak a kérés első 5000 karaktere íródik ki. +IMPORTANT: ha a `maxEntityLogSize` `LogSpecifier.NO_LOG`-tól *eltérő* értékre van állítva, akkor a REST endpoint-hoz érkező `application/octet-stream` mediaType esetében csak a kérés első 5000 karaktere íródik ki. + +IMPORTANT: `BaseRestLoggerOptimized` használata esetén, ha nincsen megadva a `LogSpecifier` annotáció, akkor `application/octet-stream` és `multipart/form-data` mediaType-ok esetében a kérésben és a válaszban lévő entity első 5000 karaktere íródik csak ki. .LogSpecifier példa [source,java] @@ -121,9 +156,9 @@ IMPORTANT: ha a `maxEntityLogSize` a `LogSpecifier.NO_LOG`-tól *eltérő* ért @POST @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML, MediaType.APPLICATION_XML }) @Consumes({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML, MediaType.APPLICATION_XML }) - @LogSpecifier(target={LogSpecifierTarget.REQUEST, LogSpecifierTarget.CLIENT_REQUEST}, maxEntityLogSize = 100) //<1> - @LogSpecifier(target=LogSpecifierTarget.RESPONSE, maxEntityLogSize = 5000) //<2> - @LogSpecifier(target=LogSpecifierTarget.CLIENT_RESPONSE, noLog = true) //<3> + @LogSpecifier(target={LogSpecifierTarget.REQUEST, LogSpecifierTarget.CLIENT_REQUEST}, maxEntityLogSize = 100) //<1> + @LogSpecifier(target=LogSpecifierTarget.RESPONSE, maxEntityLogSize = 5000) //<2> + @LogSpecifier(target=LogSpecifierTarget.CLIENT_RESPONSE, noLog = true) //<3> WithoutLogResponse postWithoutLog(WithoutLogRequest withoutLogRequest) throws BaseException; ---- <1> Request entity log méretét 100 byte-ra korlátozza, REST hívások és microprofile client használatánál is diff --git a/docs/hu/migration.adoc b/docs/hu/migration.adoc index 1e5efb421..3fa440bda 100644 --- a/docs/hu/migration.adoc +++ b/docs/hu/migration.adoc @@ -9,3 +9,4 @@ include::migration/migrationTo2_0_0.adoc[leveloffset=+1] include::migration/migration200to210.adoc[leveloffset=+1] include::migration/migration210to220.adoc[leveloffset=+1] include::migration/migration220to230.adoc[leveloffset=+1] +include::migration/migration230to240.adoc[leveloffset=+1] diff --git a/docs/hu/migration/migration230to240.adoc b/docs/hu/migration/migration230to240.adoc new file mode 100644 index 000000000..f005df0f4 --- /dev/null +++ b/docs/hu/migration/migration230to240.adoc @@ -0,0 +1,12 @@ += v2.3.0 → v2.4.0 + +coff:ee v2.3.0 -> v2.4.0 migrációs leírás, újdonságok, változások leírása + +=== coffee-rest +* *RequestResponseLogger memoria tuning*: A `BaseRestLogger` osztály alapján létrejött egy optimalizált változat: <>. Segítségével az alkalmazások kevesebb memóriát használnak fel a request és response body log-olás során. +Emellett létrehozásra került a `RequestResponseLoggerOptimized` osztály is, ahol a request és response entity logolások hossza meghatározásra kerül miszerint, ha a request vagy response entity `application/octet-stream` vagy `multipart/form-data` és nem szerepel a REST interface-en LogSpecifier annotáció, akkor korlátozzuk a log méretet. +Valamint ebben a változatban a `BYTECODE_MAX_LOG` konstans átvevezésre került `ENTITY_MAX_LOG`-ra. + +==== Átállás + +* `BaseRestLoggerOptimized`-ra átállással célszerű a `BYTECODE_MAX_LOG` helyett áttérni a `ENTITY_MAX_LOG` konstansra, ha használva van, mivel idővel az előbbi kivezetésre kerülhet. diff --git a/docs/hu/migration/v1/migration1120to1130.adoc b/docs/hu/migration/v1/migration1120to1130.adoc index d303f2c52..732d8f5fb 100644 --- a/docs/hu/migration/v1/migration1120to1130.adoc +++ b/docs/hu/migration/v1/migration1120to1130.adoc @@ -136,8 +136,6 @@ A változtatások nem eredményeznek átállási munkálatokat, visszafelé komp * Deltaspike álltal nyújtott ProjectStage leváltásra került egy coffee-ba implementált egyszerűsített változatra. * BaseApplicationContainer-ből a COFFEE_APP_NAME etcd kulcs átkerült az IConfigKey interface-be, ahol így dokumentálódik is. -* A `BaseRestLogger` osztály optimalizáláson esett át, aminek eredményeképpen az alkalmazások kevesebb memóriát használnak fel a request és response body log-olás során. -* A `RequestResponseLogger` osztályban A `BYTECODE_MAX_LOG` konstans átvevezésre került `ENTITY_MAX_LOG`-ra, mivel a feltétel, ami alapján a request body log mérete korlátozva van kiegészült a meglévő `application/octet-stream` mellett `application/json`, `application/xml` és `text/xml` mediaType-okkal. ==== Átállás @@ -162,5 +160,3 @@ public class MyBean { Ezzel együtt a ProjectStage fajtái is lecsökkentek, és már csak Production, Development és Test lehetséges. Régi deltaspikeos alap projekt stage-ek bekerültek a Testbe, kivéve a Development és Productiont ami azonos néven maradt. Lásd `hu.icellmobilsoft.coffee.rest.projectstage.ProjectStageEnum`. Az eddig használt `org.apache.deltaspike.ProjectStage` konfiguráció használata megmaradt, és visszafelé a deltaspike által támogatott értékek is feldolgozásra kerülnek az enum értékeibe. - -* A `BYTECODE_MAX_LOG` konstans helyett `ENTITY_MAX_LOG`-ot kell használni. From fa3f25c5b853e4ed6329fdf04bbb84d99470599d Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Wed, 8 Nov 2023 13:36:57 +0100 Subject: [PATCH 28/33] OSP-55 - RequestResponseLogger memoria tuning --- .../coffee/tool/utils/stream/LoggingObserver.java | 7 +++++++ .../coffee/tool/utils/stream/LoggingPublisher.java | 7 +++++++ .../coffee/tool/utils/stream/RequestLoggerInputStream.java | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingObserver.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingObserver.java index 062af42e3..95f955ee9 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingObserver.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingObserver.java @@ -39,6 +39,13 @@ public class LoggingObserver { @ThisLogger private AppLogger log; + /** + * Default constructor, constructs a new object. + */ + public LoggingObserver() { + super(); + } + /** * Observer method that logs the message * diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingPublisher.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingPublisher.java index 38d885922..f9adfd66a 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingPublisher.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingPublisher.java @@ -35,6 +35,13 @@ public class LoggingPublisher { @Inject private Event loggingEvent; + /** + * Default constructor, constructs a new object. + */ + public LoggingPublisher() { + super(); + } + /** * Publisher method for the logging event * diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java index b9d3e12f2..9b1fb9dd0 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/RequestLoggerInputStream.java @@ -30,7 +30,7 @@ * Custom {@link InputStream} for logging request with entity * * @author mate.biro - * @since 1.15.0 + * @since 2.4.0 */ @SuppressWarnings("InputStreamSlowMultibyteRead") public class RequestLoggerInputStream extends InputStream { From 76733016b11fbc1c4806b0a72135a41661c91627 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Wed, 8 Nov 2023 14:07:00 +0100 Subject: [PATCH 29/33] OSP-55 - RequestResponseLogger memoria tuning --- .../coffee/rest/log/optimized/BaseRestLoggerOptimized.java | 7 +++++++ .../rest/log/optimized/RequestResponseLoggerOptimized.java | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/BaseRestLoggerOptimized.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/BaseRestLoggerOptimized.java index b0742b6b9..dee1eabf9 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/BaseRestLoggerOptimized.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/BaseRestLoggerOptimized.java @@ -75,6 +75,13 @@ public abstract class BaseRestLoggerOptimized implements ContainerRequestFilter, @Context private HttpServletResponse httpServletResponse; + /** + * Default constructor, constructs a new object. + */ + public BaseRestLoggerOptimized() { + super(); + } + /** {@inheritDoc} */ @Override public void filter(ContainerRequestContext requestContext) throws IOException { diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/RequestResponseLoggerOptimized.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/RequestResponseLoggerOptimized.java index 4a3b674cb..9749df23f 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/RequestResponseLoggerOptimized.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/RequestResponseLoggerOptimized.java @@ -83,6 +83,13 @@ public class RequestResponseLoggerOptimized { @ThisLogger private AppLogger log; + /** + * Default constructor, constructs a new object. + */ + public RequestResponseLoggerOptimized() { + super(); + } + /** * Prints request headers to {@link String}. Masks password. * From 11a4f85b3b6deece73347a0226e22e714c390f9d Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Wed, 8 Nov 2023 19:21:05 +0100 Subject: [PATCH 30/33] OSP-55 - RequestResponseLogger memoria tuning --- .../coffee/tool/utils/stream/LoggingPublisher.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingPublisher.java b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingPublisher.java index f9adfd66a..931516a7f 100644 --- a/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingPublisher.java +++ b/coffee-tool/src/main/java/hu/icellmobilsoft/coffee/tool/utils/stream/LoggingPublisher.java @@ -19,7 +19,7 @@ */ package hu.icellmobilsoft.coffee.tool.utils.stream; -import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.event.Event; import jakarta.inject.Inject; @@ -29,7 +29,7 @@ * @author mate.biro * @since 2.4.0 */ -@Dependent +@ApplicationScoped public class LoggingPublisher { @Inject From 18d30631e08cf71fe735be293755c16b94dfb4e0 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Wed, 8 Nov 2023 21:26:44 +0100 Subject: [PATCH 31/33] OSP-55 - RequestResponseLogger memoria tuning --- docs/en/common/core/coffee-rest.adoc | 37 ++++++++++++++++++++++++ docs/en/migration.adoc | 1 + docs/en/migration/migration230to240.adoc | 12 ++++++++ docs/hu/common/core/coffee-rest.adoc | 4 +++ 4 files changed, 54 insertions(+) create mode 100644 docs/en/migration/migration230to240.adoc diff --git a/docs/en/common/core/coffee-rest.adoc b/docs/en/common/core/coffee-rest.adoc index 405387091..9fe626804 100644 --- a/docs/en/common/core/coffee-rest.adoc +++ b/docs/en/common/core/coffee-rest.adoc @@ -4,6 +4,7 @@ Module designed for REST communication and management. It includes the apache http client, various REST loggers and filters. It also contains the language, REST activator and Response util class. +[#common_core_coffee-rest_BaseRestLogger] == BaseRestLogger This class is used to log HTTP request-response requests to the application. It is activated manually at the project level using the following pattern: @@ -86,6 +87,40 @@ if needed in the project, the regex can be overwritten by specifying the configu < entity: [{"transactionId":"2G7XOSYJ6VUEJJ09","header":{"requestId":"RID314802331803","timestamp":"2019-02-01T15:31:32.432Z","requestVersion":"1.1","headerVersion":"1.0"},"result":{"funcCode":"OK"},"software":{"softwareId":"123456789123456789","softwareName":"string","softwareOperation":"LOCAL_SOFTWARE","softwareMainVersion":"string","softwareDevName":"string","softwareDevContact":"string","softwareCountryCode":"HU","softwareDescription":"string"}] ---- +[#common_core_coffee-rest_BaseRestLoggerOptimized] +== BaseRestLoggerOptimized +This class works similarly as the <>. The only difference is that it uses less memory, because it doesn't copy the streams of the request and response entities for logging, but collects the entities while reading and writing them. + +It is activated manually at the project level using the following pattern: + +.activate in project +[source,java] +---- +package hu.icellmobilsoft.project.common.rest.logger; + +import javax.inject.Inject; +import javax.ws.rs.ext.Provider; +import hu.icellmobilsoft.coffee.cdi.logger.AppLogger; +import hu.icellmobilsoft.coffee.cdi.logger.ThisLogger; +import hu.icellmobilsoft.coffee.dto.common.LogConstants; +import hu.icellmobilsoft.coffee.rest.log.optimized.BaseRestLoggerOptimized; + +@Provider // <1> +public class RestLogger extends BaseRestLoggerOptimized { + + @Inject + @ThisLogger + private AppLogger log; + + @Override + public String sessionKey() { // <2> + return LogConstants.LOG_SESSION_ID; + } +} +---- +<1> JAX-RS activator (this is the thing that activates it) +<2> Session ID key name in HTTP header + [#common_core_coffee-rest_LogSpecifier] == LogSpecifier REST logging can be customized per endpoint with the `hu.icellmobilsoft.coffee.rest.log.annotation.LogSpecifier` annotation, @@ -115,6 +150,8 @@ Currently the LogSpecifier is prepared for the following cases: IMPORTANT: if `maxEntityLogSize` is set to a value *other* than `LogSpecifier.NO_LOG`, then only the first 5000 characters of the request will be written for the `application/octet-stream` mediaType received by the REST endpoint. +IMPORTANT: When using the `BaseRestLoggerOptimized` class, if the `LogSpecifier` annotation is not specified, then in the case of `application/octet-stream` és `multipart/form-data` mediaTypes, only the first 5000 characters of the request and response entities are logged. + .LogSpecifier example [source,java] ---- diff --git a/docs/en/migration.adoc b/docs/en/migration.adoc index b45c9e837..e7accd5a3 100644 --- a/docs/en/migration.adoc +++ b/docs/en/migration.adoc @@ -8,3 +8,4 @@ include::migration/migrationTo2_0_0.adoc[leveloffset=+1] include::migration/migration200to210.adoc[leveloffset=+1] include::migration/migration210to220.adoc[leveloffset=+1] include::migration/migration220to230.adoc[leveloffset=+1] +include::migration/migration230to240.adoc[leveloffset=+1] diff --git a/docs/en/migration/migration230to240.adoc b/docs/en/migration/migration230to240.adoc new file mode 100644 index 000000000..bb11a9c6e --- /dev/null +++ b/docs/en/migration/migration230to240.adoc @@ -0,0 +1,12 @@ += v2.3.0 → v2.4.0 + +coff:ee v2.3.0 -> v2.4.0 migration description, news, changes + +=== coffee-rest +* *RequestResponseLogger memory tuning*: Based on the `BaseRestLogger` class an optimized version was created: <>. With its help applications use less memory while logging request and response bodies. +In addition, the `RequestResponseLoggerOptimized` class was created as well, where the request and response entity log limits are determined according to whether the request or response entity is `application/octet-stream` vagy `multipart/form-data` and the REST interface is not annotated with the LogSpecifier then we limit the log size. +Also, in this version, the `BYTECODE_MAX_LOG` constant has been renamed to `ENTITY_MAX_LOG`. + +==== Migration + +* When switching to `BaseRestLoggerOptimized`, it is advisable to switch to the `ENTITY_MAX_LOG` constant instead of `BYTECODE_MAX_LOG`, if it is used, as the former may be deprecated over time. diff --git a/docs/hu/common/core/coffee-rest.adoc b/docs/hu/common/core/coffee-rest.adoc index 6fa63e95f..aea9ee94b 100644 --- a/docs/hu/common/core/coffee-rest.adoc +++ b/docs/hu/common/core/coffee-rest.adoc @@ -98,17 +98,21 @@ Aktiválása kézzel történik, projekt szinten a következő minta alapján: [source,java] ---- package hu.icellmobilsoft.project.common.rest.logger; + import javax.inject.Inject; import javax.ws.rs.ext.Provider; import hu.icellmobilsoft.coffee.cdi.logger.AppLogger; import hu.icellmobilsoft.coffee.cdi.logger.ThisLogger; import hu.icellmobilsoft.coffee.dto.common.LogConstants; import hu.icellmobilsoft.coffee.rest.log.optimized.BaseRestLoggerOptimized; + @Provider // <1> public class RestLogger extends BaseRestLoggerOptimized { + @Inject @ThisLogger private AppLogger log; + @Override public String sessionKey() { // <2> return LogConstants.LOG_SESSION_ID; From 6b0a1367ddfaea51a39c816139eaa4f69fa737a5 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Fri, 24 Nov 2023 13:59:15 +0100 Subject: [PATCH 32/33] OSP-55 - RequestResponseLogger memoria tuning --- ...oggerOptimized.java => BaseRestLogger.java} | 18 +++++++++--------- ...timized.java => RequestResponseLogger.java} | 14 ++++++++------ docs/en/common/core/coffee-rest.adoc | 2 +- docs/hu/common/core/coffee-rest.adoc | 2 +- 4 files changed, 19 insertions(+), 17 deletions(-) rename coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/{BaseRestLoggerOptimized.java => BaseRestLogger.java} (92%) rename coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/{RequestResponseLoggerOptimized.java => RequestResponseLogger.java} (97%) diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/BaseRestLoggerOptimized.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/BaseRestLogger.java similarity index 92% rename from coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/BaseRestLoggerOptimized.java rename to coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/BaseRestLogger.java index dee1eabf9..ee213b0d7 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/BaseRestLoggerOptimized.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/BaseRestLogger.java @@ -24,6 +24,7 @@ import java.nio.charset.StandardCharsets; import jakarta.inject.Inject; +import jakarta.inject.Named; import jakarta.servlet.http.HttpServletResponse; import jakarta.ws.rs.container.ContainerRequestContext; import jakarta.ws.rs.container.ContainerRequestFilter; @@ -41,7 +42,6 @@ import hu.icellmobilsoft.coffee.cdi.logger.ThisLogger; import hu.icellmobilsoft.coffee.dto.common.LogConstants; import hu.icellmobilsoft.coffee.rest.cdi.BaseApplicationContainer; -import hu.icellmobilsoft.coffee.rest.log.RequestResponseLogger; import hu.icellmobilsoft.coffee.rest.log.annotation.LogSpecifier; import hu.icellmobilsoft.coffee.rest.log.annotation.enumeration.LogSpecifierTarget; import hu.icellmobilsoft.coffee.rest.utils.RestLoggerUtil; @@ -57,7 +57,7 @@ * @author mate.biro * @since 2.4.0 */ -public abstract class BaseRestLoggerOptimized implements ContainerRequestFilter, WriterInterceptor { +public abstract class BaseRestLogger implements ContainerRequestFilter, WriterInterceptor { @Inject @ThisLogger @@ -67,7 +67,7 @@ public abstract class BaseRestLoggerOptimized implements ContainerRequestFilter, private BaseApplicationContainer baseApplicationContainer; @Inject - private RequestResponseLoggerOptimized requestResponseLogger; + private @Named("optimized_RequestResponseLogger") RequestResponseLogger requestResponseLogger; @Context private UriInfo uriInfo; @@ -78,7 +78,7 @@ public abstract class BaseRestLoggerOptimized implements ContainerRequestFilter, /** * Default constructor, constructs a new object. */ - public BaseRestLoggerOptimized() { + public BaseRestLogger() { super(); } @@ -179,7 +179,7 @@ protected void processResponse(WriterInterceptorContext context) throws IOExcept * request message * @param requestContext * context - * @see RequestResponseLoggerOptimized#printRequestHeaders(java.util.Map) + * @see RequestResponseLogger#printRequestHeaders(java.util.Map) */ protected void appendRequestHeaders(StringBuilder b, ContainerRequestContext requestContext) { MultivaluedMap headers = requestContext.getHeaders(); @@ -198,7 +198,7 @@ protected void appendRequestHeaders(StringBuilder b, ContainerRequestContext req * request message * @param requestContext * context - * @see RequestResponseLoggerOptimized#printRequestLine(ContainerRequestContext) + * @see RequestResponseLogger#printRequestLine(ContainerRequestContext) */ protected void appendRequestLine(StringBuilder b, ContainerRequestContext requestContext) { b.append(requestResponseLogger.printRequestLine(requestContext)); @@ -211,7 +211,7 @@ protected void appendRequestLine(StringBuilder b, ContainerRequestContext reques * response message * @param context * context - * @see RequestResponseLoggerOptimized#printResponseLine(String, int, String, String) + * @see RequestResponseLogger#printResponseLine(String, int, String, String) */ protected void printResponseLine(StringBuilder b, WriterInterceptorContext context) { String fullPath = uriInfo.getAbsolutePath().toASCIIString(); @@ -229,7 +229,7 @@ protected void printResponseLine(StringBuilder b, WriterInterceptorContext conte * response message * @param context * context - * @see RequestResponseLoggerOptimized#printResponseHeaders(java.util.Map) + * @see RequestResponseLogger#printResponseHeaders(java.util.Map) */ protected void printResponseHeaders(StringBuilder b, WriterInterceptorContext context) { b.append(requestResponseLogger.printResponseHeaders(context.getHeaders())); @@ -244,7 +244,7 @@ protected void printResponseHeaders(StringBuilder b, WriterInterceptorContext co * context * @param entityCopy * entity - * @see RequestResponseLoggerOptimized#printResponseEntity(String, WriterInterceptorContext, byte[]) + * @see RequestResponseLogger#printResponseEntity(String, WriterInterceptorContext, byte[]) */ protected void printResponseEntity(StringBuilder b, WriterInterceptorContext context, byte[] entityCopy) { b.append(requestResponseLogger.printResponseEntity(uriInfo.getAbsolutePath().toASCIIString(), context, entityCopy)); diff --git a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/RequestResponseLoggerOptimized.java b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/RequestResponseLogger.java similarity index 97% rename from coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/RequestResponseLoggerOptimized.java rename to coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/RequestResponseLogger.java index 9749df23f..7a54c69b8 100644 --- a/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/RequestResponseLoggerOptimized.java +++ b/coffee-rest/src/main/java/hu/icellmobilsoft/coffee/rest/log/optimized/RequestResponseLogger.java @@ -30,6 +30,7 @@ import jakarta.enterprise.context.Dependent; import jakarta.inject.Inject; +import jakarta.inject.Named; import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.container.ContainerRequestContext; import jakarta.ws.rs.container.ContainerResponseContext; @@ -56,7 +57,8 @@ * @since 2.4.0 */ @Dependent -public class RequestResponseLoggerOptimized { +@Named("optimized_RequestResponseLogger") +public class RequestResponseLogger { /** Constant NOTIFICATION_PREFIX="* " */ public static final String NOTIFICATION_PREFIX = "* "; @@ -86,7 +88,7 @@ public class RequestResponseLoggerOptimized { /** * Default constructor, constructs a new object. */ - public RequestResponseLoggerOptimized() { + public RequestResponseLogger() { super(); } @@ -282,7 +284,7 @@ protected int getMaxRequestEntityLogSize(ContainerRequestContext requestContext) // ha octet-stream vagy multipart és nincs LogSpecifier annotáció, akkor korlátozunk if (RestLoggerUtil.isLogSizeLimited(requestContext, MediaType.APPLICATION_OCTET_STREAM_TYPE, MediaType.MULTIPART_FORM_DATA_TYPE) && !RestLoggerUtil.isLogSpecifierPresent(requestContext)) { - return RequestResponseLoggerOptimized.ENTITY_MAX_LOG; + return RequestResponseLogger.ENTITY_MAX_LOG; } // különben annotációban meghatározott maxEntityLogSize (ha nincs annotáció, akkor unlimit) @@ -301,7 +303,7 @@ protected int getMaxResponseEntityLogSize(WriterInterceptorContext context) { // ha octet-stream vagy multipart és nincs LogSpecifier annotáció, akkor korlátozunk if (RestLoggerUtil.isLogSizeLimited(context, MediaType.APPLICATION_OCTET_STREAM_TYPE, MediaType.MULTIPART_FORM_DATA_TYPE) && !RestLoggerUtil.isLogSpecifierPresent(context)) { - return RequestResponseLoggerOptimized.ENTITY_MAX_LOG; + return RequestResponseLogger.ENTITY_MAX_LOG; } // különben annotációban meghatározott maxEntityLogSize (ha nincs annotáció, akkor unlimit) @@ -379,7 +381,7 @@ public String printResponseHeaders(Map> headerValues) { * @return entity in string */ protected String printResponseEntity(Object entity, MediaType mediaType) { - return printEntity(entity, RequestResponseLoggerOptimized.RESPONSE_PREFIX, false, mediaType); + return printEntity(entity, RequestResponseLogger.RESPONSE_PREFIX, false, mediaType); } /** @@ -455,7 +457,7 @@ public String printResponseEntity(String fullPath, WriterInterceptorContext writ } MediaType mediaType = writerInterceptorContext.getMediaType(); if (skipLoggingForPathOrMediaType(fullPath, mediaType)) { - sb.append(RequestResponseLoggerOptimized.RESPONSE_PREFIX) + sb.append(RequestResponseLogger.RESPONSE_PREFIX) .append("Response outputstream logging disabled, because MediaType: [" + mediaType + "]\n"); } else { String responseText = new String(entityCopy, StandardCharsets.UTF_8); diff --git a/docs/en/common/core/coffee-rest.adoc b/docs/en/common/core/coffee-rest.adoc index 9fe626804..dd2f2e8be 100644 --- a/docs/en/common/core/coffee-rest.adoc +++ b/docs/en/common/core/coffee-rest.adoc @@ -103,7 +103,7 @@ import javax.ws.rs.ext.Provider; import hu.icellmobilsoft.coffee.cdi.logger.AppLogger; import hu.icellmobilsoft.coffee.cdi.logger.ThisLogger; import hu.icellmobilsoft.coffee.dto.common.LogConstants; -import hu.icellmobilsoft.coffee.rest.log.optimized.BaseRestLoggerOptimized; +import hu.icellmobilsoft.coffee.rest.log.optimized.BaseRestLogger; @Provider // <1> public class RestLogger extends BaseRestLoggerOptimized { diff --git a/docs/hu/common/core/coffee-rest.adoc b/docs/hu/common/core/coffee-rest.adoc index aea9ee94b..32af6dbd5 100644 --- a/docs/hu/common/core/coffee-rest.adoc +++ b/docs/hu/common/core/coffee-rest.adoc @@ -104,7 +104,7 @@ import javax.ws.rs.ext.Provider; import hu.icellmobilsoft.coffee.cdi.logger.AppLogger; import hu.icellmobilsoft.coffee.cdi.logger.ThisLogger; import hu.icellmobilsoft.coffee.dto.common.LogConstants; -import hu.icellmobilsoft.coffee.rest.log.optimized.BaseRestLoggerOptimized; +import hu.icellmobilsoft.coffee.rest.log.optimized.BaseRestLogger; @Provider // <1> public class RestLogger extends BaseRestLoggerOptimized { From 70d8723663359309136c65d679dc84d25aacd9e0 Mon Sep 17 00:00:00 2001 From: "mate.biro" Date: Fri, 24 Nov 2023 16:05:44 +0100 Subject: [PATCH 33/33] OSP-55 - RequestResponseLogger memoria tuning --- docs/en/common/core/coffee-rest.adoc | 10 ++++++---- docs/en/migration/migration230to240.adoc | 6 +++--- docs/hu/common/core/coffee-rest.adoc | 9 +++++---- docs/hu/migration/migration230to240.adoc | 6 +++--- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/docs/en/common/core/coffee-rest.adoc b/docs/en/common/core/coffee-rest.adoc index dd2f2e8be..26fac4078 100644 --- a/docs/en/common/core/coffee-rest.adoc +++ b/docs/en/common/core/coffee-rest.adoc @@ -87,8 +87,8 @@ if needed in the project, the regex can be overwritten by specifying the configu < entity: [{"transactionId":"2G7XOSYJ6VUEJJ09","header":{"requestId":"RID314802331803","timestamp":"2019-02-01T15:31:32.432Z","requestVersion":"1.1","headerVersion":"1.0"},"result":{"funcCode":"OK"},"software":{"softwareId":"123456789123456789","softwareName":"string","softwareOperation":"LOCAL_SOFTWARE","softwareMainVersion":"string","softwareDevName":"string","softwareDevContact":"string","softwareCountryCode":"HU","softwareDescription":"string"}] ---- -[#common_core_coffee-rest_BaseRestLoggerOptimized] -== BaseRestLoggerOptimized +[#common_core_coffee-rest_optimized_BaseRestLogger] +== Optimized BaseRestLogger This class works similarly as the <>. The only difference is that it uses less memory, because it doesn't copy the streams of the request and response entities for logging, but collects the entities while reading and writing them. It is activated manually at the project level using the following pattern: @@ -106,7 +106,7 @@ import hu.icellmobilsoft.coffee.dto.common.LogConstants; import hu.icellmobilsoft.coffee.rest.log.optimized.BaseRestLogger; @Provider // <1> -public class RestLogger extends BaseRestLoggerOptimized { +public class RestLogger extends BaseRestLogger { @Inject @ThisLogger @@ -121,6 +121,8 @@ public class RestLogger extends BaseRestLoggerOptimized { <1> JAX-RS activator (this is the thing that activates it) <2> Session ID key name in HTTP header +The HTTP request-response log itself is compiled by the `hu.icellmobilsoft.coffee.rest.log.optimized.RequestResponseLogger` class, with the temprorary `@Named("optimized_RequestResponseLogger")` annotation. The request and response entity log limits are determined here according to whether the request or response entity is `application/octet-stream` or `multipart/form-data` and the REST interface is not annotated with the LogSpecifier then we limit the log size. + [#common_core_coffee-rest_LogSpecifier] == LogSpecifier REST logging can be customized per endpoint with the `hu.icellmobilsoft.coffee.rest.log.annotation.LogSpecifier` annotation, @@ -150,7 +152,7 @@ Currently the LogSpecifier is prepared for the following cases: IMPORTANT: if `maxEntityLogSize` is set to a value *other* than `LogSpecifier.NO_LOG`, then only the first 5000 characters of the request will be written for the `application/octet-stream` mediaType received by the REST endpoint. -IMPORTANT: When using the `BaseRestLoggerOptimized` class, if the `LogSpecifier` annotation is not specified, then in the case of `application/octet-stream` és `multipart/form-data` mediaTypes, only the first 5000 characters of the request and response entities are logged. +IMPORTANT: When using the optimized `BaseRestLogger` class, if the `LogSpecifier` annotation is not specified, then in the case of `application/octet-stream` és `multipart/form-data` mediaTypes, only the first 5000 characters of the request and response entities are logged. .LogSpecifier example [source,java] diff --git a/docs/en/migration/migration230to240.adoc b/docs/en/migration/migration230to240.adoc index bb11a9c6e..2271d4454 100644 --- a/docs/en/migration/migration230to240.adoc +++ b/docs/en/migration/migration230to240.adoc @@ -3,10 +3,10 @@ coff:ee v2.3.0 -> v2.4.0 migration description, news, changes === coffee-rest -* *RequestResponseLogger memory tuning*: Based on the `BaseRestLogger` class an optimized version was created: <>. With its help applications use less memory while logging request and response bodies. -In addition, the `RequestResponseLoggerOptimized` class was created as well, where the request and response entity log limits are determined according to whether the request or response entity is `application/octet-stream` vagy `multipart/form-data` and the REST interface is not annotated with the LogSpecifier then we limit the log size. +* *RequestResponseLogger memory tuning*: Based on the `hu.icellmobilsoft.coffee.rest.log.BaseRestLogger` class an optimized version was created: <>. With its help applications use less memory while logging request and response bodies. +In addition, the `hu.icellmobilsoft.coffee.rest.log.optimized.RequestResponseLogger` class was created as well (Temporarily with the `@Named("optimized_RequestResponseLogger")` annotation. This way we keep the old implementation which will be removed later), based on the `hu.icellmobilsoft.coffee.rest.log.RequestResponseLogger`, where the request and response entity log limits are determined according to whether the request or response entity is `application/octet-stream` or `multipart/form-data` and the REST interface is not annotated with the LogSpecifier then we limit the log size. Also, in this version, the `BYTECODE_MAX_LOG` constant has been renamed to `ENTITY_MAX_LOG`. ==== Migration -* When switching to `BaseRestLoggerOptimized`, it is advisable to switch to the `ENTITY_MAX_LOG` constant instead of `BYTECODE_MAX_LOG`, if it is used, as the former may be deprecated over time. +* When switching to the optimized `BaseRestLogger`, it is advisable to switch to the `ENTITY_MAX_LOG` constant instead of `BYTECODE_MAX_LOG`, if it is used, as the former may be deleted over time. diff --git a/docs/hu/common/core/coffee-rest.adoc b/docs/hu/common/core/coffee-rest.adoc index 32af6dbd5..ca439b814 100644 --- a/docs/hu/common/core/coffee-rest.adoc +++ b/docs/hu/common/core/coffee-rest.adoc @@ -87,8 +87,8 @@ amennyiben a projekten szükséges, úgy a regex felülírható ha valamelyik *a < entity: [{"transactionId":"2G7XOSYJ6VUEJJ09","header":{"requestId":"RID314802331803","timestamp":"2019-02-01T15:31:32.432Z","requestVersion":"1.1","headerVersion":"1.0"},"result":{"funcCode":"OK"},"software":{"softwareId":"123456789123456789","softwareName":"string","softwareOperation":"LOCAL_SOFTWARE","softwareMainVersion":"string","softwareDevName":"string","softwareDevContact":"string","softwareCountryCode":"HU","softwareDescription":"string"}] ---- -[#common_core_coffee-rest_BaseRestLoggerOptimized] -== BaseRestLoggerOptimized +[#common_core_coffee-rest_optimized_BaseRestLogger] +== Optimalizált BaseRestLogger Az osztály hasonlóan működik mint a <> annyi eltéréssel, hogy kevesebb memóriát használ fel azáltal, hogy a request és response entity-ket nem a stream-ek másolásával szerzi meg a logolás számára, hanem az entity stream olvasása és írása közben gyűjti azokat. @@ -107,7 +107,7 @@ import hu.icellmobilsoft.coffee.dto.common.LogConstants; import hu.icellmobilsoft.coffee.rest.log.optimized.BaseRestLogger; @Provider // <1> -public class RestLogger extends BaseRestLoggerOptimized { +public class RestLogger extends BaseRestLogger { @Inject @ThisLogger @@ -122,6 +122,7 @@ public class RestLogger extends BaseRestLoggerOptimized { <1> JAX-RS aktivátor (ez a lényeg ami aktiválja) <2> HTTP headerben szereplő session azonosító kulcs neve +Maga a HTTP request-response log összeállításáról az ideiglenes `@Named("optimized_RequestResponseLogger")` annotációval ellátott `hu.icellmobilsoft.coffee.rest.log.optimized.RequestResponseLogger` osztály gondoskodik. A request és response entity logolások hossza itt kerül meghatározásra miszerint, ha a request vagy response entity `application/octet-stream` vagy `multipart/form-data` és nem szerepel a REST interface-en LogSpecifier annotáció, akkor korlátozzuk a log méretet [#common_core_coffee-rest_LogSpecifier] == LogSpecifier @@ -152,7 +153,7 @@ Jelenleg a LogSpecifier a következő esetekre van felkészítve: IMPORTANT: ha a `maxEntityLogSize` `LogSpecifier.NO_LOG`-tól *eltérő* értékre van állítva, akkor a REST endpoint-hoz érkező `application/octet-stream` mediaType esetében csak a kérés első 5000 karaktere íródik ki. -IMPORTANT: `BaseRestLoggerOptimized` használata esetén, ha nincsen megadva a `LogSpecifier` annotáció, akkor `application/octet-stream` és `multipart/form-data` mediaType-ok esetében a kérésben és a válaszban lévő entity első 5000 karaktere íródik csak ki. +IMPORTANT: Az optimalizált `BaseRestLogger` használata esetén, ha nincsen megadva a `LogSpecifier` annotáció, akkor `application/octet-stream` és `multipart/form-data` mediaType-ok esetében a kérésben és a válaszban lévő entity első 5000 karaktere íródik csak ki. .LogSpecifier példa [source,java] diff --git a/docs/hu/migration/migration230to240.adoc b/docs/hu/migration/migration230to240.adoc index f005df0f4..9e25cd926 100644 --- a/docs/hu/migration/migration230to240.adoc +++ b/docs/hu/migration/migration230to240.adoc @@ -3,10 +3,10 @@ coff:ee v2.3.0 -> v2.4.0 migrációs leírás, újdonságok, változások leírása === coffee-rest -* *RequestResponseLogger memoria tuning*: A `BaseRestLogger` osztály alapján létrejött egy optimalizált változat: <>. Segítségével az alkalmazások kevesebb memóriát használnak fel a request és response body log-olás során. -Emellett létrehozásra került a `RequestResponseLoggerOptimized` osztály is, ahol a request és response entity logolások hossza meghatározásra kerül miszerint, ha a request vagy response entity `application/octet-stream` vagy `multipart/form-data` és nem szerepel a REST interface-en LogSpecifier annotáció, akkor korlátozzuk a log méretet. +* *RequestResponseLogger memoria tuning*: A `hu.icellmobilsoft.coffee.rest.log.BaseRestLogger` osztály alapján létrejött egy optimalizált változat: <>. Segítségével az alkalmazások kevesebb memóriát használnak fel a request és response body log-olás során. +Emellett létrehozásra került a `hu.icellmobilsoft.coffee.rest.log.RequestResponseLogger` osztály egy újabb változata is a `hu.icellmobilsoft.coffee.rest.log.optimized.RequestResponseLogger` (ideiglenesen `@Named("optimized_RequestResponseLogger")` annotációval ellátva, így megmarad a régi implementáció is, ami később kerül kivezetésre), ahol a request és response entity logolások hossza meghatározásra kerül miszerint, ha a request vagy response entity `application/octet-stream` vagy `multipart/form-data` és nem szerepel a REST interface-en LogSpecifier annotáció, akkor korlátozzuk a log méretet. Valamint ebben a változatban a `BYTECODE_MAX_LOG` konstans átvevezésre került `ENTITY_MAX_LOG`-ra. ==== Átállás -* `BaseRestLoggerOptimized`-ra átállással célszerű a `BYTECODE_MAX_LOG` helyett áttérni a `ENTITY_MAX_LOG` konstansra, ha használva van, mivel idővel az előbbi kivezetésre kerülhet. +* Optimalizált `BaseRestLogger`-ra átállással célszerű a `BYTECODE_MAX_LOG` helyett áttérni a `ENTITY_MAX_LOG` konstansra, ha használva van, mivel idővel az előbbi kivezetésre kerülhet.