-
-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Logging interceptor remastered: introduced curl and http patterns
- Loading branch information
1 parent
c6dfcba
commit c88850f
Showing
7 changed files
with
159 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 11 additions & 10 deletions
21
src/main/kotlin/io/github/rybalkinsd/kohttp/interceptors/LoggingInterceptor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,36 @@ | ||
package io.github.rybalkinsd.kohttp.interceptors | ||
|
||
import io.github.rybalkinsd.kohttp.ext.asSequence | ||
import io.github.rybalkinsd.kohttp.interceptors.logging.HttpLoggingStrategy | ||
import io.github.rybalkinsd.kohttp.interceptors.logging.LoggingStrategy | ||
import okhttp3.Interceptor | ||
import okhttp3.Response | ||
import okio.Buffer | ||
|
||
/** | ||
* Request Logging Interceptor | ||
* | ||
* Logs HTTP requests. | ||
* | ||
* @param strategy logging option (format type...etc). | ||
* HttpLoggingStrategy: http request format strategy | ||
* CurlLoggingStrategy: curl command format strategy | ||
* @param log function to consume log message | ||
* | ||
* Sample Output: [2019-01-28T04:17:42.885Z] GET 200 - 1743ms https://postman-echo.com/get | ||
* | ||
* @since 0.8.0 | ||
* @author gokul | ||
*/ | ||
class LoggingInterceptor(private val log: (String) -> Unit = ::println) : Interceptor { | ||
class LoggingInterceptor( | ||
private val strategy: LoggingStrategy = HttpLoggingStrategy(), | ||
private val log: (String) -> Unit = ::println | ||
) : Interceptor { | ||
|
||
override fun intercept(chain: Interceptor.Chain): Response { | ||
val request = chain.request() | ||
val startTime = System.currentTimeMillis() | ||
return chain.proceed(request).also { response -> | ||
log("${request.method()} ${response.code()} - ${System.currentTimeMillis() - startTime}ms ${request.url()}") | ||
|
||
request.headers().asSequence().forEach { log("${it.name}: ${it.value}") } | ||
|
||
Buffer().use { | ||
request.body()?.writeTo(it) | ||
log(it.readByteString().utf8()) | ||
} | ||
strategy.log(request, log) | ||
} | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
src/main/kotlin/io/github/rybalkinsd/kohttp/interceptors/logging/CurlLoggingStrategy.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package io.github.rybalkinsd.kohttp.interceptors.logging | ||
|
||
import io.github.rybalkinsd.kohttp.ext.asSequence | ||
import okhttp3.Headers | ||
import okhttp3.Request | ||
import okhttp3.RequestBody | ||
import okio.Buffer | ||
|
||
/** | ||
* Logging strategy as curl command format | ||
* | ||
* @author doyaaaaaken | ||
*/ | ||
class CurlLoggingStrategy : LoggingStrategy { | ||
|
||
override fun log(request: Request, logging: (String) -> Unit) { | ||
val command = buildCurlCommand(request) | ||
logging("╭--- cURL command ---") | ||
logging(command) | ||
logging("╰--- (copy and paste the above line to a terminal)") | ||
} | ||
|
||
fun buildCurlCommand(request: Request): String { | ||
return buildString { | ||
append("curl -X ${request.method()}") | ||
append(buildCurlHeaderOption(request.headers())) | ||
append(buildCurlBodyOption(request.body())) | ||
append(" \"${request.url()}\"") | ||
} | ||
} | ||
|
||
private fun buildCurlHeaderOption(headers: Headers): String { | ||
return headers.asSequence().map { (name, value) -> | ||
val trimmedValue = value.trimDoubleQuote() | ||
" -H \"$name: $trimmedValue\"" | ||
}.joinToString("") | ||
} | ||
|
||
private fun buildCurlBodyOption(body: RequestBody?): String { | ||
if (body == null) return "" | ||
val buffer = Buffer().apply { body.writeTo(this) } | ||
return " --data $'${buffer.readUtf8().replace("\n", "\\n")}'" | ||
} | ||
|
||
private fun String.trimDoubleQuote(): String { | ||
return if (startsWith('"') && endsWith('"')) { | ||
substring(1, length - 1) | ||
} else { | ||
this | ||
} | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
src/main/kotlin/io/github/rybalkinsd/kohttp/interceptors/logging/HttpLoggingStrategy.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package io.github.rybalkinsd.kohttp.interceptors.logging | ||
|
||
import io.github.rybalkinsd.kohttp.ext.asSequence | ||
import okhttp3.Request | ||
import okio.Buffer | ||
|
||
/** | ||
* Logging strategy as http request format | ||
* | ||
* @author doyaaaaaken | ||
*/ | ||
class HttpLoggingStrategy : LoggingStrategy { | ||
|
||
override fun log(request: Request, logging: (String) -> Unit) { | ||
//TODO: output http request format logging. | ||
// see https://github.com/rybalkinsd/kohttp/pull/141#issuecomment-516428314 | ||
logging("╭--- http request output ---") | ||
request.headers().asSequence().forEach { logging("${it.name}: ${it.value}") } | ||
Buffer().use { | ||
request.body()?.writeTo(it) | ||
logging(it.readByteString().utf8()) | ||
} | ||
logging("╰---------------------------") | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
src/main/kotlin/io/github/rybalkinsd/kohttp/interceptors/logging/LoggingStrategy.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package io.github.rybalkinsd.kohttp.interceptors.logging | ||
|
||
import okhttp3.Request | ||
|
||
/** | ||
* Logging strategy | ||
* | ||
* @author doyaaaaaken | ||
*/ | ||
interface LoggingStrategy { | ||
|
||
fun log(request: Request, logging: (String) -> Unit) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
src/test/kotlin/io/github/rybalkinsd/kohttp/interceptors/logging/CurlLoggingStrategyTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package io.github.rybalkinsd.kohttp.interceptors.logging | ||
|
||
import okhttp3.FormBody | ||
import okhttp3.Request | ||
import org.junit.Test | ||
import kotlin.test.assertEquals | ||
|
||
/** | ||
* @author doyaaaaaken | ||
*/ | ||
class CurlLoggingStrategyTest { | ||
|
||
@Test | ||
fun `build curl command of simple get request`() { | ||
val request = Request.Builder().url("https://postman-echo.com/get").build() | ||
val actual = CurlLoggingStrategy().buildCurlCommand(request) | ||
|
||
assertEquals("curl -X GET \"https://postman-echo.com/get\"", actual) | ||
} | ||
|
||
@Test | ||
fun `build curl command of request with header`() { | ||
val request = Request.Builder() | ||
.url("https://postman-echo.com/get") | ||
.header("Cookie", "foo=6; bar=28") | ||
.header("Content-Type", "\"application/json\"") | ||
.build() | ||
val actual = CurlLoggingStrategy().buildCurlCommand(request) | ||
|
||
assertEquals("curl -X GET -H \"Cookie: foo=6; bar=28\" -H \"Content-Type: application/json\" \"https://postman-echo.com/get\"", actual) | ||
} | ||
|
||
@Test | ||
fun `build curl command of request with body`() { | ||
val request = Request.Builder() | ||
.url("https://postman-echo.com/post") | ||
.post(FormBody.Builder().add("foo", "123").add("bar", "abc").build()) | ||
.build() | ||
val actual = CurlLoggingStrategy().buildCurlCommand(request) | ||
|
||
assertEquals("curl -X POST --data \$'foo=123&bar=abc' \"https://postman-echo.com/post\"", actual) | ||
} | ||
} |