diff --git a/ballerina/http_log_manager.bal b/ballerina/http_log_manager.bal index 67928b082b..28b9a88c97 100644 --- a/ballerina/http_log_manager.bal +++ b/ballerina/http_log_manager.bal @@ -35,9 +35,13 @@ public type TraceLogAdvancedConfiguration record {| # Represents HTTP access log configuration. # # + console - Boolean value to enable or disable console access logs +# + format - The format of access logs to be printed (either `flat` or `json`) +# + attributes - The list of attributes of access logs to be printed # + path - Optional file path to store access logs public type AccessLogConfiguration record {| boolean console = false; + string format = "flat"; + string[] attributes?; string path?; |}; diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java b/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java index b31d83f132..48b1915153 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/HttpConstants.java @@ -323,9 +323,12 @@ public final class HttpConstants { public static final String HTTP_TRACE_LOG_ENABLED = "http.tracelog.enabled"; public static final String HTTP_ACCESS_LOG = "http.accesslog"; public static final String HTTP_ACCESS_LOG_ENABLED = "http.accesslog.enabled"; + public static final String HTTP_LOG_FORMAT_JSON = "json"; // TraceLog and AccessLog configs public static final BString HTTP_LOG_CONSOLE = StringUtils.fromString("console"); + public static final BString HTTP_LOG_FORMAT = StringUtils.fromString("format"); + public static final BString HTTP_LOG_ATTRIBUTES = StringUtils.fromString("attributes"); public static final BString HTTP_LOG_FILE_PATH = StringUtils.fromString("path"); public static final BString HTTP_TRACE_LOG_HOST = StringUtils.fromString("host"); public static final BString HTTP_TRACE_LOG_PORT = StringUtils.fromString("port"); diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/logging/HttpLogManager.java b/native/src/main/java/io/ballerina/stdlib/http/api/logging/HttpLogManager.java index 1cd7666f49..296e12ce7f 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/logging/HttpLogManager.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/logging/HttpLogManager.java @@ -23,6 +23,12 @@ import io.ballerina.stdlib.http.api.logging.formatters.HttpAccessLogFormatter; import io.ballerina.stdlib.http.api.logging.formatters.HttpTraceLogFormatter; import io.ballerina.stdlib.http.api.logging.formatters.JsonLogFormatter; +import io.ballerina.stdlib.http.api.logging.logger.HttpAccessLogger; +import io.ballerina.stdlib.http.api.logging.logger.HttpLoggerFactory; +import io.ballerina.stdlib.http.transport.contractimpl.common.accesslog.HttpAccessLogFormat; +import io.ballerina.stdlib.http.transport.contractimpl.common.accesslog.HttpAccessLogMessage; +import io.netty.util.internal.logging.InternalLogger; +import io.netty.util.internal.logging.InternalLoggerFactory; import java.io.IOException; import java.io.InputStream; @@ -38,10 +44,13 @@ import static io.ballerina.stdlib.http.api.HttpConstants.HTTP_ACCESS_LOG_ENABLED; import static io.ballerina.stdlib.http.api.HttpConstants.HTTP_LOG_CONSOLE; import static io.ballerina.stdlib.http.api.HttpConstants.HTTP_LOG_FILE_PATH; +import static io.ballerina.stdlib.http.api.HttpConstants.HTTP_LOG_FORMAT; +import static io.ballerina.stdlib.http.api.HttpConstants.HTTP_LOG_FORMAT_JSON; import static io.ballerina.stdlib.http.api.HttpConstants.HTTP_TRACE_LOG; import static io.ballerina.stdlib.http.api.HttpConstants.HTTP_TRACE_LOG_ENABLED; import static io.ballerina.stdlib.http.api.HttpConstants.HTTP_TRACE_LOG_HOST; import static io.ballerina.stdlib.http.api.HttpConstants.HTTP_TRACE_LOG_PORT; +import static io.ballerina.stdlib.http.transport.contract.Constants.ACCESS_LOG; /** * Java util logging manager for ballerina which overrides the readConfiguration method to replace placeholders @@ -63,6 +72,7 @@ public class HttpLogManager extends LogManager { protected Logger httpTraceLogger; protected Logger httpAccessLogger; + protected InternalLogger httpInternalLogger; private String protocol; public HttpLogManager(boolean traceLogConsole, BMap traceLogAdvancedConfig, BMap accessLogConfig, @@ -70,6 +80,7 @@ public HttpLogManager(boolean traceLogConsole, BMap traceLogAdvancedConfig, BMap this.protocol = protocol.getValue(); this.setHttpTraceLogHandler(traceLogConsole, traceLogAdvancedConfig); this.setHttpAccessLogHandler(accessLogConfig); + HttpAccessLogMessage.initializeHttpAccessLogConfig(accessLogConfig); } /** @@ -134,13 +145,17 @@ public void setHttpAccessLogHandler(BMap accessLogConfig) { // keep a reference to prevent this logger from being garbage collected httpAccessLogger = Logger.getLogger(HTTP_ACCESS_LOG); } + if (httpInternalLogger == null) { + httpInternalLogger = InternalLoggerFactory.getInstance(ACCESS_LOG); + } PrintStream stdErr = System.err; boolean accessLogsEnabled = false; + HttpAccessLogFormat accessLogFormat = getAccessLogFormat(accessLogConfig); Boolean consoleLogEnabled = accessLogConfig.getBooleanValue(HTTP_LOG_CONSOLE); if (consoleLogEnabled) { ConsoleHandler consoleHandler = new ConsoleHandler(); - consoleHandler.setFormatter(new HttpAccessLogFormatter()); + consoleHandler.setFormatter(new HttpAccessLogFormatter(accessLogFormat)); consoleHandler.setLevel(Level.INFO); httpAccessLogger.addHandler(consoleHandler); httpAccessLogger.setLevel(Level.INFO); @@ -151,7 +166,7 @@ public void setHttpAccessLogHandler(BMap accessLogConfig) { if (filePath != null && !filePath.getValue().trim().isEmpty()) { try { FileHandler fileHandler = new FileHandler(filePath.getValue(), true); - fileHandler.setFormatter(new HttpAccessLogFormatter()); + fileHandler.setFormatter(new HttpAccessLogFormatter(accessLogFormat)); fileHandler.setLevel(Level.INFO); httpAccessLogger.addHandler(fileHandler); httpAccessLogger.setLevel(Level.INFO); @@ -167,4 +182,11 @@ public void setHttpAccessLogHandler(BMap accessLogConfig) { } } + private HttpAccessLogFormat getAccessLogFormat(BMap accessLogConfig) { + BString logFormat = accessLogConfig.getStringValue(HTTP_LOG_FORMAT); + if (logFormat.getValue().equals(HTTP_LOG_FORMAT_JSON)) { + return HttpAccessLogFormat.JSON; + } + return HttpAccessLogFormat.FLAT; + } } diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/logging/formatters/HttpAccessLogFormatter.java b/native/src/main/java/io/ballerina/stdlib/http/api/logging/formatters/HttpAccessLogFormatter.java index ad676230c6..302a5adb68 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/api/logging/formatters/HttpAccessLogFormatter.java +++ b/native/src/main/java/io/ballerina/stdlib/http/api/logging/formatters/HttpAccessLogFormatter.java @@ -19,6 +19,7 @@ package io.ballerina.stdlib.http.api.logging.formatters; import io.ballerina.stdlib.http.api.logging.HttpLogManager; +import io.ballerina.stdlib.http.transport.contractimpl.common.accesslog.HttpAccessLogFormat; import java.util.logging.Formatter; import java.util.logging.LogRecord; @@ -29,6 +30,11 @@ * @since 0.965 */ public class HttpAccessLogFormatter extends Formatter { + private HttpAccessLogFormat accessLogFormat; + + public HttpAccessLogFormatter(HttpAccessLogFormat accessLogFormat) { + this.accessLogFormat = accessLogFormat; + } private static final String format = HttpLogManager.getLogManager().getProperty( HttpAccessLogFormatter.class.getCanonicalName() + ".format"); diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/logging/logger/HttpAccessLogger.java b/native/src/main/java/io/ballerina/stdlib/http/api/logging/logger/HttpAccessLogger.java new file mode 100644 index 0000000000..dc6a725246 --- /dev/null +++ b/native/src/main/java/io/ballerina/stdlib/http/api/logging/logger/HttpAccessLogger.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you 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. + */ + +package io.ballerina.stdlib.http.api.logging.logger; + +import io.ballerina.stdlib.http.transport.contractimpl.common.accesslog.HttpAccessLogFormat; + +public class HttpAccessLogger extends HttpLogger { + HttpAccessLogFormat format = HttpAccessLogFormat.FLAT; + public HttpAccessLogger(String name) { + super(name); + } + + public HttpAccessLogFormat getFormat() { + return format; + } + + public void setFormat(HttpAccessLogFormat format) { + this.format = format; + } +} diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/logging/logger/HttpLogger.java b/native/src/main/java/io/ballerina/stdlib/http/api/logging/logger/HttpLogger.java new file mode 100644 index 0000000000..205c7108f7 --- /dev/null +++ b/native/src/main/java/io/ballerina/stdlib/http/api/logging/logger/HttpLogger.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you 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. + */ + +package io.ballerina.stdlib.http.api.logging.logger; + +import io.netty.util.internal.logging.AbstractInternalLogger; +import io.netty.util.internal.logging.InternalLogLevel; + +public class HttpLogger extends AbstractInternalLogger { + + protected HttpLogger(String name) { + super(name); + } + + @Override + public boolean isTraceEnabled() { + return false; + } + + @Override + public void trace(String s) { + + } + + @Override + public void trace(String s, Object o) { + + } + + @Override + public void trace(String s, Object o, Object o1) { + + } + + @Override + public void trace(String s, Object... objects) { + + } + + @Override + public void trace(String s, Throwable throwable) { + + } + + @Override + public boolean isDebugEnabled() { + + return false; + } + + @Override + public void debug(String s) { + + } + + @Override + public void debug(String s, Object o) { + + } + + @Override + public void debug(String s, Object o, Object o1) { + + } + + @Override + public void debug(String s, Object... objects) { + + } + + @Override + public void debug(String s, Throwable throwable) { + + } + + @Override + public boolean isInfoEnabled() { + + return false; + } + + @Override + public void info(String s) { + + } + + @Override + public void info(String s, Object o) { + + } + + @Override + public void info(String s, Object o, Object o1) { + + } + + @Override + public void info(String s, Object... objects) { + + } + + @Override + public void info(String s, Throwable throwable) { + + } + + @Override + public boolean isWarnEnabled() { + + return false; + } + + @Override + public void warn(String s) { + + } + + @Override + public void warn(String s, Object o) { + + } + + @Override + public void warn(String s, Object... objects) { + + } + + @Override + public void warn(String s, Object o, Object o1) { + + } + + @Override + public void warn(String s, Throwable throwable) { + + } + + @Override + public boolean isErrorEnabled() { + + return false; + } + + @Override + public void error(String s) { + + } + + @Override + public void error(String s, Object o) { + + } + + @Override + public void error(String s, Object o, Object o1) { + + } + + @Override + public void error(String s, Object... objects) { + + } + + @Override + public void error(String s, Throwable throwable) { + + } + + @Override + public void log(InternalLogLevel level, String msg) { + super.log(level, msg); + } +} \ No newline at end of file diff --git a/native/src/main/java/io/ballerina/stdlib/http/api/logging/logger/HttpLoggerFactory.java b/native/src/main/java/io/ballerina/stdlib/http/api/logging/logger/HttpLoggerFactory.java new file mode 100644 index 0000000000..6c2ae7ccf2 --- /dev/null +++ b/native/src/main/java/io/ballerina/stdlib/http/api/logging/logger/HttpLoggerFactory.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 LLC. licenses this file to you 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. + */ + +package io.ballerina.stdlib.http.api.logging.logger; + +import io.netty.util.internal.logging.InternalLogger; +import io.netty.util.internal.logging.InternalLoggerFactory; + +public class HttpLoggerFactory extends InternalLoggerFactory { + @Override + protected InternalLogger newInstance(String name) { + if (name.contains("accesslog")) { + return new HttpAccessLogger(name); + } + return this.newInstance(name); + } +} diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java index a2ff002207..b21025ba78 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contract/Constants.java @@ -158,7 +158,7 @@ public final class Constants { public static final String HTTP_REASON_PHRASE = "HTTP_REASON_PHRASE"; public static final String CHNL_HNDLR_CTX = "CHNL_HNDLR_CTX"; - public static final String ACCESS_LOG_MESSAGE_ID = "ACCESS_LOG_MESSAGE_ID"; + public static final String OUTBOUND_ACCESS_LOG_MESSAGE = "OUTBOUND_ACCESS_LOG_MESSAGE"; public static final String SRC_HANDLER = "SRC_HANDLER"; public static final String POOLED_BYTE_BUFFER_FACTORY = "POOLED_BYTE_BUFFER_FACTORY"; diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/DefaultHttpClientConnector.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/DefaultHttpClientConnector.java index 1687bb2abf..ca42c76ac0 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/DefaultHttpClientConnector.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/DefaultHttpClientConnector.java @@ -64,10 +64,9 @@ import java.net.SocketAddress; import java.util.Calendar; import java.util.NoSuchElementException; -import java.util.UUID; -import static io.ballerina.stdlib.http.transport.contract.Constants.ACCESS_LOG_MESSAGE_ID; import static io.ballerina.stdlib.http.transport.contract.Constants.HTTP_X_FORWARDED_FOR; +import static io.ballerina.stdlib.http.transport.contract.Constants.OUTBOUND_ACCESS_LOG_MESSAGE; import static io.ballerina.stdlib.http.transport.contract.Constants.REMOTE_SERVER_CLOSED_BEFORE_INITIATING_OUTBOUND_REQUEST; import static io.ballerina.stdlib.http.transport.contract.Constants.TO; @@ -158,10 +157,10 @@ public HttpResponseFuture send(HttpCarbonMessage httpOutboundRequest) { } public HttpResponseFuture send(OutboundMsgHolder outboundMsgHolder, HttpCarbonMessage httpOutboundRequest) { - HttpAccessLogMessage httpAccessLogMessage = new HttpAccessLogMessage(); - String httpAccessLogMessageId = UUID.randomUUID().toString(); - httpAccessLogMessage.setDateTime(Calendar.getInstance()); - httpOutboundRequest.setProperty(ACCESS_LOG_MESSAGE_ID, httpAccessLogMessageId); + HttpAccessLogMessage outboundAccessLogMessage = new HttpAccessLogMessage(); + outboundAccessLogMessage.setDateTime(Calendar.getInstance()); + httpOutboundRequest.setProperty(OUTBOUND_ACCESS_LOG_MESSAGE, outboundAccessLogMessage); + final HttpResponseFuture httpResponseFuture; Object sourceHandlerObject = httpOutboundRequest.getProperty(Constants.SRC_HANDLER); @@ -173,7 +172,6 @@ public HttpResponseFuture send(OutboundMsgHolder outboundMsgHolder, HttpCarbonMe srcHandler = (SourceHandler) sourceHandlerObject; } else if (sourceHandlerObject instanceof Http2SourceHandler) { http2SourceHandler = (Http2SourceHandler) sourceHandlerObject; - http2SourceHandler.putHttpAccessLogMessage(httpAccessLogMessageId, httpAccessLogMessage); } } @@ -206,7 +204,6 @@ public HttpResponseFuture send(OutboundMsgHolder outboundMsgHolder, HttpCarbonMe new RequestWriteStarter(outboundMsgHolder, activeHttp2ClientChannel).startWritingContent(); httpResponseFuture = outboundMsgHolder.getResponseFuture(); httpResponseFuture.notifyResponseHandle(new ResponseHandle(outboundMsgHolder)); - updateAccessLogInfo(activeHttp2ClientChannel, httpOutboundRequest, httpAccessLogMessage); return httpResponseFuture; } @@ -260,7 +257,6 @@ private void startExecutingOutboundRequest(String protocol, ChannelFuture channe } targetChannel.writeContent(httpOutboundRequest); } - updateAccessLogInfo(freshHttp2ClientChannel, httpOutboundRequest, httpAccessLogMessage); } private void prepareTargetChannelForHttp2() { @@ -401,42 +397,4 @@ private void initTargetChannelProperties(SenderConfiguration senderConfiguration this.sslConfig = senderConfiguration.getClientSSLConfig(); this.forwardedExtensionConfig = senderConfiguration.getForwardedExtensionConfig(); } - - private void updateAccessLogInfo(Http2ClientChannel http2ClientChannel, HttpCarbonMessage httpOutboundRequest, - HttpAccessLogMessage httpAccessLogMessage) { - SocketAddress address = http2ClientChannel.getChannel().remoteAddress(); - if (address instanceof InetSocketAddress) { - httpAccessLogMessage.setIp(((InetSocketAddress) address).getAddress().toString()); - } - if (httpAccessLogMessage.getIp().startsWith("/")) { - httpAccessLogMessage.setIp(httpAccessLogMessage.getIp().substring(1)); - } - - HttpHeaders headers = httpOutboundRequest.getHeaders(); - if (headers.contains(HTTP_X_FORWARDED_FOR)) { - String forwardedHops = headers.get(HTTP_X_FORWARDED_FOR); - httpAccessLogMessage.setHttpXForwardedFor(forwardedHops); - // If multiple IPs available, the first ip is the client - int firstCommaIndex = forwardedHops.indexOf(','); - httpAccessLogMessage.setIp(firstCommaIndex != -1 ? - forwardedHops.substring(0, firstCommaIndex) : forwardedHops); - } - - // Populate request parameters - if (headers.contains(HttpHeaderNames.USER_AGENT)) { - httpAccessLogMessage.setHttpUserAgent(headers.get(HttpHeaderNames.USER_AGENT)); - } - if (headers.contains(HttpHeaderNames.REFERER)) { - httpAccessLogMessage.setHttpReferrer(headers.get(HttpHeaderNames.REFERER)); - } - httpAccessLogMessage.setRequestMethod(httpOutboundRequest.getHttpMethod()); - httpAccessLogMessage.setRequestUri((String) httpOutboundRequest.getProperty(TO)); - HttpMessage request = httpOutboundRequest.getNettyHttpRequest(); - if (request != null) { - httpAccessLogMessage.setScheme(request.protocolVersion().toString()); - } else { - httpAccessLogMessage.setScheme(httpOutboundRequest.getHttpVersion()); - } - httpAccessLogMessage.setRequestBodySize((long) httpOutboundRequest.getContentSize()); - } } diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/accesslog/HttpAccessLogMessage.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/accesslog/HttpAccessLogMessage.java index 500e83980b..2201b3fd6d 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/accesslog/HttpAccessLogMessage.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/common/accesslog/HttpAccessLogMessage.java @@ -21,34 +21,45 @@ import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import io.netty.util.internal.logging.InternalLogger; -import io.netty.util.internal.logging.InternalLoggerFactory; +import io.ballerina.runtime.api.values.BArray; +import io.ballerina.runtime.api.values.BMap; +import io.ballerina.runtime.api.values.BString; +import java.util.Arrays; import java.util.Calendar; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; -import static io.ballerina.stdlib.http.transport.contract.Constants.ACCESS_LOG; +import static io.ballerina.stdlib.http.api.HttpConstants.HTTP_LOG_ATTRIBUTES; +import static io.ballerina.stdlib.http.api.HttpConstants.HTTP_LOG_FORMAT; public class HttpAccessLogMessage { - private static final InternalLogger ACCESS_LOGGER = InternalLoggerFactory.getInstance(ACCESS_LOG); + private static final Set EXCLUDED_ATTRIBUTES = new HashSet<>(List.of( + "http_referrer", "http_user_agent", "http_x_forwarded_for" + )); + private static BMap accessLogConfig = null; private String ip; private Calendar dateTime; private String requestMethod; private String requestUri; private String scheme; private int status; - private Long requestBodySize; - private Long responseBodySize; - private Long requestTime; + private long requestBodySize; + private long responseBodySize; + private long requestTime; private String httpReferrer; private String httpUserAgent; private String httpXForwardedFor; + private String host; + private int port; private Map customHeader; public HttpAccessLogMessage() { @@ -56,7 +67,7 @@ public HttpAccessLogMessage() { } public HttpAccessLogMessage(String ip, Calendar dateTime, String requestMethod, String requestUri, String scheme, - int status, Long responseBodySize, String httpReferrer, String httpUserAgent) { + int status, long responseBodySize, String httpReferrer, String httpUserAgent) { this.ip = ip; this.dateTime = dateTime; this.requestMethod = requestMethod; @@ -117,7 +128,7 @@ public void setStatus(int status) { this.status = status; } - public Long getRequestBodySize() { + public long getRequestBodySize() { return requestBodySize; } @@ -125,7 +136,7 @@ public void setRequestBodySize(Long requestBodySize) { this.requestBodySize = requestBodySize; } - public Long getResponseBodySize() { + public long getResponseBodySize() { return responseBodySize; } @@ -133,7 +144,7 @@ public void setResponseBodySize(Long responseBodySize) { this.responseBodySize = responseBodySize; } - public Long getRequestTime() { + public long getRequestTime() { return requestTime; } @@ -165,6 +176,22 @@ public void setHttpXForwardedFor(String httpXForwardedFor) { this.httpXForwardedFor = httpXForwardedFor; } + public String getHost() { + return this.host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return this.port; + } + + public void setPort(int port) { + this.port = port; + } + public Map getCustomHeader() { return customHeader; } @@ -177,6 +204,39 @@ public void putCustomHeader(String headerKey, String headerValue) { this.customHeader.put(headerKey, headerValue); } + public static void initializeHttpAccessLogConfig(BMap accessLogConfigFromBallerina) { + accessLogConfig = accessLogConfigFromBallerina; + } + + public static List getCustomHeaders() { + List attributes = getAccessLogAttributes(); + if (attributes == null) { + return Collections.emptyList(); + } + + return attributes.stream() + .filter(attr -> attr.startsWith("http_") && !EXCLUDED_ATTRIBUTES.contains(attr)) + .map(attr -> attr.substring(5)) + .collect(Collectors.toList()); + } + + public static HttpAccessLogFormat getAccessLogFormat() { + BString logFormat = accessLogConfig.getStringValue(HTTP_LOG_FORMAT); + if (logFormat.getValue().equals("json")) { + return HttpAccessLogFormat.JSON; + } + return HttpAccessLogFormat.FLAT; + } + + public static List getAccessLogAttributes() { + BArray logAttributes = accessLogConfig.getArrayValue(HTTP_LOG_ATTRIBUTES); + if (logAttributes != null) { + return Arrays.stream(logAttributes.getStringArray()) + .collect(Collectors.toList()); + } + return null; + } + public static String formatAccessLogMessage(HttpAccessLogMessage inboundMessage, List outboundMessages, HttpAccessLogFormat format, List attributes) { @@ -221,10 +281,10 @@ public static String formatAccessLogMessage(HttpAccessLogMessage inboundMessage, private static Map mapAccessLogMessage(HttpAccessLogMessage httpAccessLogMessage, HttpAccessLogFormat format, List attributes) { List allAttributes = List.of("ip", "date_time", "request", "request_method", "request_uri", - "scheme", "status", "request_body_size", "response_body_size", "request_time", "http_referer", + "scheme", "status", "request_body_size", "response_body_size", "request_time", "http_referrer", "http_user_agent", "http_x_forwarded_for"); List defaultAttributes = List.of("ip", "date_time", "request", "status", "response_body_size", - "http_referer", "http_user_agent"); + "http_referrer", "http_user_agent"); Map attributeValues = new LinkedHashMap<>(); allAttributes.forEach(attr -> attributeValues.put(attr, null)); @@ -244,7 +304,7 @@ private static String formatAccessLogAttribute(HttpAccessLogMessage httpAccessLo HttpAccessLogFormat format, String attribute) { return switch (attribute) { case "ip" -> httpAccessLogMessage.getIp(); - case "date_time" -> String.format("[%1$td/%1$tb/%1$tY:%1$tT %1$tz]", httpAccessLogMessage.getDateTime()); + case "date_time" -> String.format("[%1$td/%1$tb/%1$tY:%1$tT.%1$tL %1$tz]", httpAccessLogMessage.getDateTime()); case "request_method" -> httpAccessLogMessage.getRequestMethod(); case "request_uri" -> httpAccessLogMessage.getRequestUri(); case "scheme" -> httpAccessLogMessage.getScheme(); @@ -255,7 +315,7 @@ private static String formatAccessLogAttribute(HttpAccessLogMessage httpAccessLo case "request_body_size" -> String.valueOf(httpAccessLogMessage.getRequestBodySize()); case "response_body_size" -> String.valueOf(httpAccessLogMessage.getResponseBodySize()); case "request_time" -> String.valueOf(httpAccessLogMessage.getRequestTime()); - case "http_referer" -> String.format(format == HttpAccessLogFormat.FLAT ? + case "http_referrer" -> String.format(format == HttpAccessLogFormat.FLAT ? "\"%1$s\"" : "%1$s", getHyphenForNull(httpAccessLogMessage.getHttpReferrer())); case "http_user_agent" -> String.format(format == HttpAccessLogFormat.FLAT ? "\"%1$s\"" : "%1$s", getHyphenForNull(httpAccessLogMessage.getHttpUserAgent())); diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/http2/Http2SourceHandler.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/http2/Http2SourceHandler.java index 88691307c7..3284bdb6b3 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/http2/Http2SourceHandler.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/http2/Http2SourceHandler.java @@ -51,7 +51,9 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -83,7 +85,7 @@ public final class Http2SourceHandler extends ChannelInboundHandlerAdapter { private SocketAddress remoteAddress; private ChannelGroup allChannels; private ChannelGroup listenerChannels; - private Map httpAccessLogMessages; + private List httpAccessLogMessages; Http2SourceHandler(HttpServerChannelInitializer serverChannelInitializer, Http2ConnectionEncoder encoder, String interfaceId, Http2Connection conn, ServerConnectorFuture serverConnectorFuture, @@ -97,7 +99,7 @@ public final class Http2SourceHandler extends ChannelInboundHandlerAdapter { this.targetChannelPool = new ConcurrentHashMap<>(); this.allChannels = allChannels; this.listenerChannels = listenerChannels; - this.httpAccessLogMessages = new HashMap<>(); + this.httpAccessLogMessages = new ArrayList<>(); setRemoteFlowController(); setDataEventListeners(); } @@ -296,15 +298,11 @@ public SocketAddress getRemoteAddress() { return remoteAddress; } - public void putHttpAccessLogMessage(String accessLogMessageId, HttpAccessLogMessage httpAccessLogMessage) { - this.httpAccessLogMessages.put(accessLogMessageId, httpAccessLogMessage); + public void addHttpAccessLogMessage(HttpAccessLogMessage httpAccessLogMessage) { + this.httpAccessLogMessages.add(httpAccessLogMessage); } - public HttpAccessLogMessage getHttpAccessLogMessage(String accessLogMessageId) { - return this.httpAccessLogMessages.get(accessLogMessageId); - } - - public Map getHttpAccessLogMessages() { + public List getHttpAccessLogMessages() { return this.httpAccessLogMessages; } } diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/states/http2/SendingEntityBody.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/states/http2/SendingEntityBody.java index 1091f6ec07..1d14df7952 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/states/http2/SendingEntityBody.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/listener/states/http2/SendingEntityBody.java @@ -23,7 +23,6 @@ import io.ballerina.stdlib.http.transport.contract.exceptions.ServerConnectorException; import io.ballerina.stdlib.http.transport.contractimpl.Http2OutboundRespListener; import io.ballerina.stdlib.http.transport.contractimpl.common.Util; -import io.ballerina.stdlib.http.transport.contractimpl.common.accesslog.HttpAccessLogFormat; import io.ballerina.stdlib.http.transport.contractimpl.common.accesslog.HttpAccessLogMessage; import io.ballerina.stdlib.http.transport.contractimpl.common.states.Http2MessageStateContext; import io.ballerina.stdlib.http.transport.contractimpl.common.states.Http2StateUtil; @@ -256,16 +255,20 @@ private void logAccessInfo(HttpCarbonMessage inboundRequestMsg, HttpCarbonMessag // Populate response parameters int statusCode = Util.getHttpResponseStatus(outboundResponseMsg).code(); + long requestTime = Calendar.getInstance().getTimeInMillis() - inboundRequestArrivalTime.getTimeInMillis(); HttpAccessLogMessage inboundMessage = new HttpAccessLogMessage(remoteAddress, inboundRequestArrivalTime, method, uri, protocol, statusCode, contentLength, referrer, userAgent); + inboundMessage.setRequestBodySize((long) inboundRequestMsg.getContentSize()); + inboundMessage.setRequestTime(requestTime); + List outboundMessages = new ArrayList<>(); Object sourceHandlerObject = inboundRequestMsg.getProperty(SRC_HANDLER); if (sourceHandlerObject instanceof Http2SourceHandler http2SourceHandler) { - http2SourceHandler.getHttpAccessLogMessages().forEach((key, value) -> outboundMessages.add(value)); + outboundMessages.addAll(http2SourceHandler.getHttpAccessLogMessages()); } String formattedAccessLogMessage = HttpAccessLogMessage.formatAccessLogMessage(inboundMessage, outboundMessages, - HttpAccessLogFormat.JSON, null); + HttpAccessLogMessage.getAccessLogFormat(), HttpAccessLogMessage.getAccessLogAttributes()); ACCESS_LOGGER.log(InternalLogLevel.INFO, formattedAccessLogMessage); } } diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/states/ReceivingEntityBody.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/states/ReceivingEntityBody.java index 35f77b78a7..1c48d00a34 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/states/ReceivingEntityBody.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/states/ReceivingEntityBody.java @@ -28,17 +28,25 @@ import io.ballerina.stdlib.http.transport.message.HttpCarbonMessage; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMessage; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.LastHttpContent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.util.Calendar; -import static io.ballerina.stdlib.http.transport.contract.Constants.ACCESS_LOG_MESSAGE_ID; +import static io.ballerina.stdlib.http.transport.contract.Constants.HTTP_X_FORWARDED_FOR; import static io.ballerina.stdlib.http.transport.contract.Constants.IDLE_STATE_HANDLER; import static io.ballerina.stdlib.http.transport.contract.Constants.IDLE_TIMEOUT_TRIGGERED_WHILE_READING_INBOUND_RESPONSE_BODY; +import static io.ballerina.stdlib.http.transport.contract.Constants.OUTBOUND_ACCESS_LOG_MESSAGE; import static io.ballerina.stdlib.http.transport.contract.Constants.REMOTE_SERVER_CLOSED_WHILE_READING_INBOUND_RESPONSE_BODY; +import static io.ballerina.stdlib.http.transport.contract.Constants.TO; import static io.ballerina.stdlib.http.transport.contractimpl.common.Util.isKeepAlive; import static io.ballerina.stdlib.http.transport.contractimpl.common.Util.safelyRemoveHandlers; import static io.ballerina.stdlib.http.transport.contractimpl.common.states.StateUtil.ILLEGAL_STATE_ERROR; @@ -87,7 +95,7 @@ public void readInboundResponseEntityBody(ChannelHandlerContext ctx, HttpContent inboundResponseMsg.setLastHttpContentArrived(); targetHandler.resetInboundMsg(); safelyRemoveHandlers(targetHandler.getTargetChannel().getChannel().pipeline(), IDLE_STATE_HANDLER); - updateAccessLogInfo(targetHandler.getOutboundRequestMsg(), inboundResponseMsg); + updateAccessLogInfo(targetHandler, inboundResponseMsg); senderReqRespStateManager.state = new EntityBodyReceived(senderReqRespStateManager); if (!isKeepAlive(targetHandler.getKeepAliveConfig(), @@ -116,19 +124,64 @@ public void handleIdleTimeoutConnectionClosure(TargetHandler targetHandler, IDLE_TIMEOUT_TRIGGERED_WHILE_READING_INBOUND_RESPONSE_BODY); } - private void updateAccessLogInfo(HttpCarbonMessage outboundRequestMsg, HttpCarbonMessage inboundResponseMsg) { - String httpAccessLogMessageId = getTypedProperty(outboundRequestMsg, ACCESS_LOG_MESSAGE_ID, String.class); - if (httpAccessLogMessageId == null) { + private void updateAccessLogInfo(TargetHandler targetHandler, + HttpCarbonMessage inboundResponseMsg) { + HttpCarbonMessage httpOutboundRequest = targetHandler.getOutboundRequestMsg(); + HttpAccessLogMessage outboundAccessLogMessage = + getTypedProperty(httpOutboundRequest, OUTBOUND_ACCESS_LOG_MESSAGE, HttpAccessLogMessage.class); + Http2SourceHandler http2SourceHandler = + getTypedProperty(httpOutboundRequest, Constants.SRC_HANDLER, Http2SourceHandler.class); + if (outboundAccessLogMessage == null || http2SourceHandler == null) { return; } - Http2SourceHandler http2SourceHandler = - getTypedProperty(outboundRequestMsg, Constants.SRC_HANDLER, Http2SourceHandler.class); - if (http2SourceHandler == null) { - return; + SocketAddress remoteAddress = targetHandler.getTargetChannel().getChannel().remoteAddress(); + if (remoteAddress instanceof InetSocketAddress inetSocketAddress) { + InetAddress inetAddress = inetSocketAddress.getAddress(); + outboundAccessLogMessage.setIp(inetAddress.getHostAddress()); + outboundAccessLogMessage.setHost(inetAddress.getHostName()); + outboundAccessLogMessage.setPort(inetSocketAddress.getPort()); + } + if (outboundAccessLogMessage.getIp().startsWith("/")) { + outboundAccessLogMessage.setIp(outboundAccessLogMessage.getIp().substring(1)); } - updateHttpAccessLogMessage(inboundResponseMsg, httpAccessLogMessageId, http2SourceHandler); + // Populate with header parameters + HttpHeaders headers = httpOutboundRequest.getHeaders(); + if (headers.contains(HTTP_X_FORWARDED_FOR)) { + String forwardedHops = headers.get(HTTP_X_FORWARDED_FOR); + outboundAccessLogMessage.setHttpXForwardedFor(forwardedHops); + // If multiple IPs available, the first ip is the client + int firstCommaIndex = forwardedHops.indexOf(','); + outboundAccessLogMessage.setIp(firstCommaIndex != -1 ? + forwardedHops.substring(0, firstCommaIndex) : forwardedHops); + } + if (headers.contains(HttpHeaderNames.USER_AGENT)) { + outboundAccessLogMessage.setHttpUserAgent(headers.get(HttpHeaderNames.USER_AGENT)); + } + if (headers.contains(HttpHeaderNames.REFERER)) { + outboundAccessLogMessage.setHttpReferrer(headers.get(HttpHeaderNames.REFERER)); + } + HttpAccessLogMessage.getCustomHeaders().forEach(customHeader -> + outboundAccessLogMessage.putCustomHeader(customHeader, headers.contains(customHeader) ? + headers.get(customHeader) : "-")); + + outboundAccessLogMessage.setRequestMethod(httpOutboundRequest.getHttpMethod()); + outboundAccessLogMessage.setRequestUri((String) httpOutboundRequest.getProperty(TO)); + HttpMessage outboundRequest = httpOutboundRequest.getNettyHttpRequest(); + if (outboundRequest != null) { + outboundAccessLogMessage.setScheme(outboundRequest.protocolVersion().toString()); + } else { + outboundAccessLogMessage.setScheme(httpOutboundRequest.getHttpVersion()); + } + outboundAccessLogMessage.setRequestBodySize((long) httpOutboundRequest.getContentSize()); + outboundAccessLogMessage.setStatus(inboundResponseMsg.getHttpStatusCode()); + outboundAccessLogMessage.setResponseBodySize(contentLength); + long requestTime = Calendar.getInstance().getTimeInMillis() - + outboundAccessLogMessage.getDateTime().getTimeInMillis(); + outboundAccessLogMessage.setRequestTime(requestTime); + + http2SourceHandler.addHttpAccessLogMessage(outboundAccessLogMessage); } private T getTypedProperty(HttpCarbonMessage request, String propertyName, Class type) { @@ -138,16 +191,4 @@ private T getTypedProperty(HttpCarbonMessage request, String propertyName, C } return null; } - - private void updateHttpAccessLogMessage(HttpCarbonMessage inboundResponseMsg, String httpAccessLogMessageId, - Http2SourceHandler sourceHandler) { - HttpAccessLogMessage httpAccessLogMessage = sourceHandler.getHttpAccessLogMessage(httpAccessLogMessageId); - if (httpAccessLogMessage != null) { - httpAccessLogMessage.setStatus(inboundResponseMsg.getHttpStatusCode()); - httpAccessLogMessage.setResponseBodySize(contentLength); - long requestTime = Calendar.getInstance().getTimeInMillis() - - httpAccessLogMessage.getDateTime().getTimeInMillis(); - httpAccessLogMessage.setRequestTime(requestTime); - } - } } diff --git a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/states/http2/ReceivingEntityBody.java b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/states/http2/ReceivingEntityBody.java index 66bd738fd7..f0535fb270 100644 --- a/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/states/http2/ReceivingEntityBody.java +++ b/native/src/main/java/io/ballerina/stdlib/http/transport/contractimpl/sender/states/http2/ReceivingEntityBody.java @@ -34,16 +34,24 @@ import io.netty.handler.codec.http.DefaultHttpContent; import io.netty.handler.codec.http.DefaultLastHttpContent; import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpHeaderNames; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMessage; import io.netty.handler.codec.http2.Http2Exception; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.util.Calendar; -import static io.ballerina.stdlib.http.transport.contract.Constants.ACCESS_LOG_MESSAGE_ID; +import static io.ballerina.stdlib.http.transport.contract.Constants.HTTP_X_FORWARDED_FOR; +import static io.ballerina.stdlib.http.transport.contract.Constants.OUTBOUND_ACCESS_LOG_MESSAGE; import static io.ballerina.stdlib.http.transport.contract.Constants.REMOTE_SERVER_CLOSED_WHILE_READING_INBOUND_RESPONSE_BODY; import static io.ballerina.stdlib.http.transport.contract.Constants.REMOTE_SERVER_SENT_GOAWAY_WHILE_READING_INBOUND_RESPONSE_BODY; import static io.ballerina.stdlib.http.transport.contract.Constants.REMOTE_SERVER_SENT_RST_STREAM_WHILE_READING_INBOUND_RESPONSE_BODY; +import static io.ballerina.stdlib.http.transport.contract.Constants.TO; import static io.ballerina.stdlib.http.transport.contractimpl.common.states.Http2StateUtil.releaseContent; import static io.ballerina.stdlib.http.transport.contractimpl.common.states.StateUtil.handleIncompleteInboundMessage; @@ -181,19 +189,62 @@ private void onResponseDataRead(OutboundMsgHolder outboundMsgHolder, int streamI } private void updateAccessLogInfo(OutboundMsgHolder outboundMsgHolder) { - String httpAccessLogMessageId = - getTypedProperty(outboundMsgHolder.getRequest(), ACCESS_LOG_MESSAGE_ID, String.class); - if (httpAccessLogMessageId == null) { + HttpCarbonMessage httpOutboundRequest = outboundMsgHolder.getRequest(); + HttpAccessLogMessage outboundAccessLogMessage = + getTypedProperty(httpOutboundRequest, OUTBOUND_ACCESS_LOG_MESSAGE, HttpAccessLogMessage.class); + Http2SourceHandler http2SourceHandler = + getTypedProperty(httpOutboundRequest, Constants.SRC_HANDLER, Http2SourceHandler.class); + if (outboundAccessLogMessage == null || http2SourceHandler == null) { return; } - Http2SourceHandler http2SourceHandler = - getTypedProperty(outboundMsgHolder.getRequest(), Constants.SRC_HANDLER, Http2SourceHandler.class); - if (http2SourceHandler == null) { - return; + SocketAddress remoteAddress = http2TargetHandler.getHttp2ClientChannel().getChannel().remoteAddress(); + if (remoteAddress instanceof InetSocketAddress inetSocketAddress) { + InetAddress inetAddress = inetSocketAddress.getAddress(); + outboundAccessLogMessage.setIp(inetAddress.getHostAddress()); + outboundAccessLogMessage.setHost(inetAddress.getHostName()); + outboundAccessLogMessage.setPort(inetSocketAddress.getPort()); + } + if (outboundAccessLogMessage.getIp().startsWith("/")) { + outboundAccessLogMessage.setIp(outboundAccessLogMessage.getIp().substring(1)); + } + + // Populate with header parameters + HttpHeaders headers = httpOutboundRequest.getHeaders(); + if (headers.contains(HTTP_X_FORWARDED_FOR)) { + String forwardedHops = headers.get(HTTP_X_FORWARDED_FOR); + outboundAccessLogMessage.setHttpXForwardedFor(forwardedHops); + // If multiple IPs available, the first ip is the client + int firstCommaIndex = forwardedHops.indexOf(','); + outboundAccessLogMessage.setIp(firstCommaIndex != -1 ? + forwardedHops.substring(0, firstCommaIndex) : forwardedHops); + } + if (headers.contains(HttpHeaderNames.USER_AGENT)) { + outboundAccessLogMessage.setHttpUserAgent(headers.get(HttpHeaderNames.USER_AGENT)); } + if (headers.contains(HttpHeaderNames.REFERER)) { + outboundAccessLogMessage.setHttpReferrer(headers.get(HttpHeaderNames.REFERER)); + } + HttpAccessLogMessage.getCustomHeaders().forEach(customHeader -> + outboundAccessLogMessage.putCustomHeader(customHeader, headers.contains(customHeader) ? + headers.get(customHeader) : "-")); + + outboundAccessLogMessage.setRequestMethod(httpOutboundRequest.getHttpMethod()); + outboundAccessLogMessage.setRequestUri((String) httpOutboundRequest.getProperty(TO)); + HttpMessage outboundRequest = httpOutboundRequest.getNettyHttpRequest(); + if (outboundRequest != null) { + outboundAccessLogMessage.setScheme(outboundRequest.protocolVersion().toString()); + } else { + outboundAccessLogMessage.setScheme(httpOutboundRequest.getHttpVersion()); + } + outboundAccessLogMessage.setRequestBodySize((long) httpOutboundRequest.getContentSize()); + outboundAccessLogMessage.setStatus(outboundMsgHolder.getResponse().getHttpStatusCode()); + outboundAccessLogMessage.setResponseBodySize(contentLength); + long requestTime = Calendar.getInstance().getTimeInMillis() - + outboundAccessLogMessage.getDateTime().getTimeInMillis(); + outboundAccessLogMessage.setRequestTime(requestTime); - updateHttpAccessLogMessage(outboundMsgHolder, httpAccessLogMessageId, http2SourceHandler); + http2SourceHandler.addHttpAccessLogMessage(outboundAccessLogMessage); } private T getTypedProperty(HttpCarbonMessage request, String propertyName, Class type) { @@ -203,16 +254,4 @@ private T getTypedProperty(HttpCarbonMessage request, String propertyName, C } return null; } - - private void updateHttpAccessLogMessage(OutboundMsgHolder outboundMsgHolder, String httpAccessLogMessageId, - Http2SourceHandler sourceHandler) { - HttpAccessLogMessage httpAccessLogMessage = sourceHandler.getHttpAccessLogMessage(httpAccessLogMessageId); - if (httpAccessLogMessage != null) { - httpAccessLogMessage.setStatus(outboundMsgHolder.getResponse().getHttpStatusCode()); - httpAccessLogMessage.setResponseBodySize(contentLength); - long requestTime = Calendar.getInstance().getTimeInMillis() - - httpAccessLogMessage.getDateTime().getTimeInMillis(); - httpAccessLogMessage.setRequestTime(requestTime); - } - } }