diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 0bed0d7..445c62e 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -19,7 +19,7 @@ jobs:
# Indexes for parallel jobs (starting from zero).
# E.g. use [0, 1] for 2 parallel jobs, [0, 1, 2] for 3 parallel jobs, etc.
#ci_node_index: [0, 1, 2, 3, 4, 5, 6, 7]
- java-version: ['11', '17', '21']
+ java-version: ['17', '21']
env:
TZ: "Europe/Ireland"
diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts
index 69464db..6c8aa0a 100644
--- a/examples/build.gradle.kts
+++ b/examples/build.gradle.kts
@@ -1,7 +1,7 @@
plugins {
id("org.springframework.boot") version "3.1.3"
id("io.spring.dependency-management") version "1.1.2"
- kotlin("jvm") version "1.6.10"
+ kotlin("jvm") version "1.8.20"
}
group = "com.github.firetail-io"
diff --git a/examples/src/main/java/com/example/demo/DemoApplication.java b/examples/src/main/java/com/example/demo/DemoApplication.java
index 6d28f62..25e27e7 100644
--- a/examples/src/main/java/com/example/demo/DemoApplication.java
+++ b/examples/src/main/java/com/example/demo/DemoApplication.java
@@ -4,6 +4,7 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.Clock;
@@ -23,4 +24,9 @@ public static void main(String[] args) {
public String hello() {
return String.format("Hello %s, utc: %s!", LocalDateTime.now(), ZonedDateTime.now(Clock.systemUTC()));
}
+
+ @PostMapping("/hello")
+ public String helloPost() {
+ return String.format("Hello %s, utc: %s!", LocalDateTime.now(), ZonedDateTime.now(Clock.systemUTC()));
+ }
}
diff --git a/pom.xml b/pom.xml
deleted file mode 100644
index 252c401..0000000
--- a/pom.xml
+++ /dev/null
@@ -1,178 +0,0 @@
-
-
- 4.0.0
-
- com.github.firetail-io
- firetail-java-lib
- 0.0.1.SNAPSPOT
- firetail-java-lib
- Java Library for Firetail
- https://github.com/muhammadn/firetail-java-lib
-
-
-
- Muhammad Nuzaihan
- zaihan@unrealasia.net
- https://github.com/muhammadn
-
-
-
-
-
- LGPL License
- https://opensource.org/license/lgpl-3-0/
- repo
-
-
-
-
- 1.8
- 2.6
- 4.0.1
- 5.3
- 5.2.21.RELEASE
- 2.1.4.RELEASE
- 1.7.26
-
-
-
- scm:git:git://github.com/muhammadn/firetail-java-lib.git
- scm:git:git@github.com:muhammadn/firetail-java-lib.git
- https://github.com/muhammadn/firetail-java-lib
-
-
-
-
- ossrh
- https://oss.sonatype.org/content/repositories/snapshots
-
-
- ossrh
- https://oss.sonatype.org/service/local/staging/deploy/maven2/
-
-
-
-
-
- org.springframework
- spring-context
- ${spring.version}
- provided
-
-
- org.springframework
- spring-web
- ${spring.version}
- provided
-
-
- org.springframework
- spring-webmvc
- ${spring.version}
- provided
-
-
- org.springframework.boot
- spring-boot-autoconfigure
- ${spring.boot.version}
- provided
-
-
- net.logstash.logback
- logstash-logback-encoder
- ${logstash-logback.version}
-
-
- javax.servlet
- javax.servlet-api
- ${javax-servlet.version}
- provided
-
-
- commons-io
- commons-io
- ${commons-io.version}
-
-
- org.slf4j
- slf4j-api
- ${slf4j.version}
-
-
- ch.qos.logback
- logback-classic
- 1.2.3
-
-
- javax.annotation
- javax.annotation-api
- 1.3.2
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.8.0
-
- ${java.version}
- ${java.version}
- UTF-8
-
-
-
-
-
-
-
- release
-
-
-
- org.apache.maven.plugins
- maven-gpg-plugin
- 1.5
-
-
- sign-artifacts
- verify
-
- sign
-
-
-
-
-
- org.apache.maven.plugins
- maven-source-plugin
- 3.0.1
-
-
- attach-sources
-
- jar-no-fork
-
-
-
-
-
- org.apache.maven.plugins
- maven-javadoc-plugin
- 3.0.0
-
-
- attach-javadocs
-
- jar
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/kotlin/io/firetail/logging/core/FiretailLogger.kt b/src/main/kotlin/io/firetail/logging/core/FiretailLogger.kt
index bbad951..edacf65 100644
--- a/src/main/kotlin/io/firetail/logging/core/FiretailLogger.kt
+++ b/src/main/kotlin/io/firetail/logging/core/FiretailLogger.kt
@@ -40,4 +40,4 @@ class FiretailLogger (val firetailConfig: FiretailConfig) {
companion object {
val LOGGER = LoggerFactory.getLogger(FiretailLogger::class.java)
}
-}
\ No newline at end of file
+}
diff --git a/src/main/kotlin/io/firetail/logging/servlet/FiretailFilter.kt b/src/main/kotlin/io/firetail/logging/servlet/FiretailFilter.kt
index 5d9823f..e129cbd 100644
--- a/src/main/kotlin/io/firetail/logging/servlet/FiretailFilter.kt
+++ b/src/main/kotlin/io/firetail/logging/servlet/FiretailFilter.kt
@@ -22,6 +22,7 @@ import org.springframework.web.method.HandlerMethod
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
import java.util.*
import java.util.concurrent.CompletableFuture
+import java.nio.charset.Charset
@Service
@ConditionalOnClass(FiretailConfig::class)
@@ -31,6 +32,7 @@ class FiretailFilter(
private val firetailConfig: FiretailConfig,
private val firetailMapper: FiretailMapper,
) {
+
@Autowired
private lateinit var firetailBuffer: FiretailBuffer
@@ -58,19 +60,27 @@ class FiretailFilter(
val startTime = System.currentTimeMillis()
val wrappedRequest = SpringRequestWrapper(request)
firetailLogger.logRequest(wrappedRequest)
- val wrappedResponse = SpringResponseWrapper(response)
+ val wrappedResponse = SpringResponseWrapper(response)
try {
with(wrappedResponse) {
setHeader(REQUEST_ID, firetailLogContext.get(REQUEST_ID))
setHeader(CORRELATION_ID, firetailLogContext.get(CORRELATION_ID))
}
+
chain.doFilter(wrappedRequest, wrappedResponse)
+
+ val charset: Charset = Charsets.UTF_8
+ val responseArray: ByteArray = wrappedResponse.contentAsByteArray
+ val responseBody: String = responseArray.toString(charset)
+ wrappedResponse.copyBodyToResponse()
+
val duration = System.currentTimeMillis() - startTime
firetailLogger.logResponse(wrappedResponse, duration = duration)
val firetailLog =
firetailMapper.from(
wrappedRequest,
wrappedResponse,
+ responseBody,
duration,
)
CompletableFuture.runAsync {
diff --git a/src/main/kotlin/io/firetail/logging/servlet/FiretailMapper.kt b/src/main/kotlin/io/firetail/logging/servlet/FiretailMapper.kt
index e19d353..be9b71f 100644
--- a/src/main/kotlin/io/firetail/logging/servlet/FiretailMapper.kt
+++ b/src/main/kotlin/io/firetail/logging/servlet/FiretailMapper.kt
@@ -7,11 +7,13 @@ import io.firetail.logging.core.FtResponse
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import java.util.HashMap
+import java.io.StringWriter
+import java.io.InputStreamReader
class FiretailMapper {
private val objectMapper = ObjectMapper()
- fun from(request: HttpServletRequest, response: HttpServletResponse, executionTime: Long): FiretailData {
- return FiretailData(request = from(request), response = from(response), executionTime = executionTime.toInt())
+ fun from(request: HttpServletRequest, response: HttpServletResponse, responseBody: String, executionTime: Long): FiretailData {
+ return FiretailData(request = from(request), response = from(response, responseBody), executionTime = executionTime.toInt())
}
fun from(request: HttpServletRequest): FtRequest {
@@ -20,23 +22,26 @@ class FiretailMapper {
.mapIndexed { _, value -> value to listOf(request.getHeader(value)) }
.toMap()
+ val body = request.inputStream.bufferedReader().use { it.readText() }
return FtRequest(
httpProtocol = request.protocol,
method = request.method,
headers = headers,
+ body = body,
ip = request.remoteAddr,
resource = request.requestURI,
uri = request.requestURL.toString(), // FT calls the defines the URI as URL.
)
}
- fun from(response: HttpServletResponse): FtResponse {
+ fun from(response: HttpServletResponse, body: String): FtResponse {
val headers = response.headerNames
.mapIndexed { _, value -> value to listOf(response.getHeader(value)) }
.toMap()
+
return FtResponse(
statusCode = response.status,
- body = "",
+ body = body,
headers = headers,
)
}
diff --git a/src/main/kotlin/io/firetail/logging/servlet/SpringResponseWrapper.kt b/src/main/kotlin/io/firetail/logging/servlet/SpringResponseWrapper.kt
index b7a2bb2..b6aa5ff 100644
--- a/src/main/kotlin/io/firetail/logging/servlet/SpringResponseWrapper.kt
+++ b/src/main/kotlin/io/firetail/logging/servlet/SpringResponseWrapper.kt
@@ -7,41 +7,10 @@ import jakarta.servlet.http.HttpServletResponseWrapper
import java.io.OutputStreamWriter
import java.io.PrintWriter
import java.util.function.Consumer
+import org.springframework.web.util.ContentCachingResponseWrapper
-class SpringResponseWrapper(response: HttpServletResponse?) : HttpServletResponseWrapper(response) {
- private var outputStream: ServletOutputStream? = null
- private var writer: PrintWriter? = null
- private var copier: ServletOutputStreamWrapper? = null
+class SpringResponseWrapper(response: HttpServletResponse) : ContentCachingResponseWrapper(response) {
- override fun getOutputStream(): ServletOutputStream {
- check(writer == null) { "getWriter() has already been called on this response." }
- copier = ServletOutputStreamWrapper(response.outputStream)
- return copier!!
- }
-
- override fun getWriter(): PrintWriter {
- check(outputStream == null) { "getOutputStream() has already been called on this response." }
- if (writer == null) {
- copier = ServletOutputStreamWrapper(response.outputStream)
- writer = PrintWriter(OutputStreamWriter(copier!!, response.characterEncoding), true)
- }
- return writer!!
- }
-
- override fun flushBuffer() {
- if (writer != null) {
- writer!!.flush()
- } else if (outputStream != null) {
- copier!!.flush()
- }
- }
-
- val contentAsByteArray: ByteArray
- get() = if (copier != null) {
- copier!!.getCopy()
- } else {
- empty
- }
val allHeaders: Map
get() {
val headers: MutableMap = HashMap()
diff --git a/src/test/kotlin/io/firetail/logging/FiretailMapperTest.kt b/src/test/kotlin/io/firetail/logging/FiretailMapperTest.kt
index 178dc96..ba31cf3 100644
--- a/src/test/kotlin/io/firetail/logging/FiretailMapperTest.kt
+++ b/src/test/kotlin/io/firetail/logging/FiretailMapperTest.kt
@@ -14,40 +14,6 @@ import java.util.*
class FiretailMapperTest {
- private val firetailMapper = FiretailMapper()
-
- @Test
- fun fromResponse() {
- val mockResponse: HttpServletResponse = Mockito.mock(HttpServletResponse::class.java)
- Mockito.`when`(mockResponse.headerNames).thenReturn(listOf(TEST))
- Mockito.`when`(mockResponse.getHeader(TEST)).thenReturn(TEST_RESULTS)
- val result = firetailMapper.from(mockResponse)
- Assertions.assertThat(result.headers)
- .isNotNull
- .hasFieldOrPropertyWithValue(TEST, listOf(TEST_RESULTS))
- }
-
- @Test
- fun fromRequest() {
- val mockRequest: HttpServletRequest = Mockito.mock(HttpServletRequest::class.java)
-
- Mockito.`when`(mockRequest.protocol).thenReturn("HTTP")
- Mockito.`when`(mockRequest.method).thenReturn("GET")
- Mockito.`when`(mockRequest.requestURI).thenReturn("/")
- Mockito.`when`(mockRequest.requestURL).thenReturn(StringBuffer().append("http://blah.com"))
- Mockito.`when`(mockRequest.remoteAddr).thenReturn("127.0.0.1")
- Mockito.`when`(mockRequest.queryString).thenReturn("123")
- Mockito.`when`(mockRequest.getHeader(TEST)).thenReturn(TEST_RESULTS)
- Mockito.`when`(mockRequest.headerNames)
- .thenReturn(Collections.enumeration(Collections.singletonList(TEST)))
-
- val result = firetailMapper.from(mockRequest)
-
- Assertions.assertThat(result.headers)
- .isNotNull
- .hasFieldOrPropertyWithValue(TEST, listOf(TEST_RESULTS))
- }
-
@Test
fun jsonNd() {
val firetailMapper = FiretailMapper()