Skip to content

Commit 56a0a59

Browse files
committed
feat: Firetail Interceptor. Add tests to support correct disabling
1 parent 8e1abf8 commit 56a0a59

File tree

17 files changed

+294
-130
lines changed

17 files changed

+294
-130
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,5 @@ project.xcworkspace
100100
version.yml
101101

102102
#Andorid
103-
local.properties
103+
local.properties
104+
/examples/src/main/resources/application-local.yml

examples/src/main/resources/application.properties

Lines changed: 0 additions & 2 deletions
This file was deleted.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
firetail:
2+
apikey: "set-your-ft-api-key-here"
3+
url: "https://your.sandbox.firetail.app"
4+
5+
logging:
6+
firetail:
7+
enabled: true
8+
springdoc:
9+
api-docs:
10+
path: /api-docs

src/main/kotlin/io/firetail/logging/base/Constants.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ class Constants {
88
const val RESPONSE_TIME = "X-Response-Time"
99
const val RESPONSE_STATUS = "X-Response-Status"
1010
const val AUDIT = "audit"
11+
12+
// const val FIRETAIL_APPENDER_NAME = "FIRETAIL"
1113
val empty = ByteArray(0)
1214
}
1315
}
Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,53 @@
11
package io.firetail.logging.base
22

33
import io.firetail.logging.servlet.FiretailFilter
4-
import io.firetail.logging.util.LogContext
4+
import io.firetail.logging.servlet.FiretailHeaderInterceptor
5+
import io.firetail.logging.util.FiretailLogContext
56
import io.firetail.logging.util.StringUtils
67
import org.springframework.beans.factory.annotation.Autowired
78
import org.springframework.beans.factory.annotation.Value
8-
import org.springframework.context.ApplicationContext
9+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
10+
import org.springframework.context.annotation.Bean
911
import org.springframework.context.annotation.Configuration
1012
import org.springframework.context.annotation.Import
13+
import org.springframework.web.client.RestTemplate
1114

1215
@Configuration
1316
@Import(
14-
FiretailLogger::class,
1517
StringUtils::class,
16-
LogContext::class,
1718
FiretailFilter::class,
1819
)
20+
@ConditionalOnProperty("logging.firetail.enabled")
1921
class FiretailConfig @Autowired constructor(
2022
@Value("\${firetail.ignorePatterns:#null}")
2123
val ignorePatterns: String?,
2224
@Value("\${firetail.logHeaders:false}")
2325
val logHeaders: Boolean = false,
26+
@Value("\${firetail.url:http://localhost:8500}")
27+
val url: String,
28+
@Value("\${firetail.apiKey:not-defined}")
29+
val apiKey: String,
2430
) {
25-
@Autowired
26-
lateinit var context: ApplicationContext
31+
32+
val key = "X-FT-API-KEY"
33+
34+
@Bean
35+
fun firetailLogContext(): FiretailLogContext = FiretailLogContext()
36+
37+
@Bean
38+
fun firetailTemplate(): FiretailTemplate {
39+
return FiretailTemplate(this)
40+
}
41+
42+
@Bean
43+
fun firetailHeaderInterceptor(): FiretailHeaderInterceptor = FiretailHeaderInterceptor()
44+
45+
@Bean
46+
fun wireInterceptor(
47+
restTemplate: RestTemplate,
48+
firetailHeaderInterceptor: FiretailHeaderInterceptor,
49+
): RestTemplate {
50+
restTemplate.interceptors.add(firetailHeaderInterceptor)
51+
return restTemplate
52+
}
2753
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package io.firetail.logging.base
2+
3+
import java.time.LocalDateTime
4+
import java.time.ZoneOffset
5+
6+
data class FireTailLog(
7+
val version: String = "1.0.0-alpha",
8+
val dateCreated: Long = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC),
9+
val executionTime: Int,
10+
val request: Request,
11+
val response: Response,
12+
)
13+
14+
data class Request(
15+
val headers: Headers,
16+
val httpProtocol: String,
17+
val method: String,
18+
val body: String = "",
19+
val ip: String,
20+
val resource: String,
21+
val uri: String,
22+
)
23+
24+
data class Headers(
25+
val key: Map<String, String>,
26+
)
27+
28+
data class Response(
29+
val statusCode: Int,
30+
val body: String,
31+
val headers: Headers,
32+
)

src/main/kotlin/io/firetail/logging/base/FiretailLogger.kt renamed to src/main/kotlin/io/firetail/logging/base/FiretailTemplate.kt

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,46 @@
11
package io.firetail.logging.base
22

3+
import com.fasterxml.jackson.databind.ObjectMapper
34
import io.firetail.logging.servlet.SpringRequestWrapper
45
import io.firetail.logging.servlet.SpringResponseWrapper
56
import io.firetail.logging.util.StringUtils
67
import net.logstash.logback.argument.StructuredArguments
78
import org.slf4j.LoggerFactory
8-
import org.springframework.stereotype.Service
9+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
10+
import java.io.DataOutputStream
11+
import java.net.HttpURLConnection
12+
import java.net.URL
13+
14+
@ConditionalOnProperty("logging.firetail.enabled")
15+
class FiretailTemplate(private val firetailConfig: FiretailConfig) {
16+
17+
private val uploadUrl = firetailConfig.url + "/logs/bulk"
18+
private val connection = URL(uploadUrl).openConnection() as HttpURLConnection
19+
private val objectMapper = ObjectMapper()
20+
private val stringUtils: StringUtils = StringUtils()
21+
22+
companion object {
23+
private val LOGGER = LoggerFactory.getLogger(this::class.java)
24+
}
25+
26+
fun send(fireTailLog: FireTailLog) {
27+
post(objectMapper.writeValueAsString(fireTailLog))
28+
}
29+
30+
private fun post(jsonBody: String) {
31+
// Set up the connection for a POST request
32+
connection.requestMethod = "POST"
33+
connection.doOutput = false
34+
connection.setRequestProperty(firetailConfig.key, firetailConfig.apiKey)
35+
connection.setRequestProperty("CONTENT-TYPE", "application/nd-json")
36+
37+
// Write the JSON body to the request
38+
val outputStream = DataOutputStream(connection.outputStream)
39+
outputStream.writeBytes(jsonBody)
40+
outputStream.flush()
41+
outputStream.close()
42+
}
943

10-
@Service
11-
class FiretailLogger(
12-
private val stringUtils: StringUtils = StringUtils(),
13-
private val firetailConfig: FiretailConfig,
14-
) {
1544
fun logRequest(wrappedRequest: SpringRequestWrapper) =
1645
if (firetailConfig.logHeaders) {
1746
logWithHeaders(wrappedRequest)
@@ -82,8 +111,4 @@ class FiretailLogger(
82111
StructuredArguments.value(Constants.AUDIT, true),
83112
)
84113
}
85-
86-
companion object {
87-
private val LOGGER = LoggerFactory.getLogger(this::class.java)
88-
}
89114
}

src/main/kotlin/io/firetail/logging/base/SpringLoggerAutoConfiguration.kt

Lines changed: 0 additions & 81 deletions
This file was deleted.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package io.firetail.logging.base
2+
3+
import org.springframework.beans.factory.annotation.Value
4+
import org.springframework.boot.context.properties.ConfigurationProperties
5+
import org.springframework.context.annotation.Configuration
6+
import org.springframework.context.annotation.Import
7+
8+
@Configuration
9+
@ConfigurationProperties(prefix = "logging.logstash")
10+
@Import(FiretailConfig::class)
11+
class TcpLogger(val firetailConfig: FiretailConfig) {
12+
var trustStoreLocation: String? = null
13+
var trustStorePassword: String? = null
14+
15+
@Value("\${spring.application.name:-}")
16+
lateinit var name: String
17+
18+
// @Bean
19+
// @ConditionalOnProperty("logging.firetail.enabled")
20+
// fun firetailAppender(): LogstashTcpSocketAppender {
21+
// val loggerContext = LoggerFactory.getILoggerFactory() as LoggerContext
22+
// val logstashTcpSocketAppender = LogstashTcpSocketAppender()
23+
// logstashTcpSocketAppender.name = FIRETAIL_APPENDER_NAME
24+
// logstashTcpSocketAppender.context = loggerContext
25+
// logstashTcpSocketAppender.addDestination(firetailConfig.url)
26+
// if (trustStoreLocation != null) {
27+
// val sslConfiguration = SSLConfiguration()
28+
// val factory = KeyStoreFactoryBean()
29+
// factory.location = trustStoreLocation
30+
// if (trustStorePassword != null) factory.password = trustStorePassword
31+
// sslConfiguration.trustStore = factory
32+
// logstashTcpSocketAppender.ssl = sslConfiguration
33+
// }
34+
// val encoder = LogstashEncoder()
35+
// encoder.context = loggerContext
36+
// encoder.isIncludeContext = true
37+
// encoder.customFields = "{\"appname\":\"$name\"}"
38+
// encoder.start()
39+
// logstashTcpSocketAppender.encoder = encoder
40+
// logstashTcpSocketAppender.start()
41+
// loggerContext.getLogger(Logger.ROOT_LOGGER_NAME).addAppender(logstashTcpSocketAppender)
42+
// return logstashTcpSocketAppender
43+
// }
44+
}

0 commit comments

Comments
 (0)