Skip to content

Commit

Permalink
Merge branch 'network'
Browse files Browse the repository at this point in the history
  • Loading branch information
devindi committed Jun 3, 2020
2 parents 069ed6d + 00c96f0 commit ae8fcaa
Show file tree
Hide file tree
Showing 12 changed files with 248 additions and 4 deletions.
51 changes: 49 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The idea of `Kalev` is pretty similar to `Timber`. Library provides `Kalevipoeg`

`kalev-lib` provides pure JVM implementation. Doesn't cotains any implementation of `Kalevipoeg`
`kalev-android` contains bridge between Kalev and Android's log system. `PrintPoeg` format log entry as JSON string and print it to LogCat
`kalev-okhttp` provide interceptor for `okhttp` to log network requests in Kalev-way


## Usage
Expand Down Expand Up @@ -61,15 +62,61 @@ Besides the fields added with `with` some fields are automatically added to all
`timestamp` The timestamp when the entry was created.
`message` The logging message passed to {v, d, i, w, e} after the `with` call. E.g. `Failed to send event.`

### Network Logging

Add `LoggingInterceptor` to your `OkHttpClient` to log network requests in Kalev-way.
Examples of network logs:

[http://httpbin.org/get?id=42](http://httpbin.org/get?id=42)
```json
{
"message": "network",
"method": "GET",
"path": "\/get",
"id": "42",
"response.code": 200,
"response.body": {
"args": {
"id": "42"
},
"headers": {
"Accept-Encoding": "gzip",
"Content-Type": "application\/json",
"Host": "httpbin.org",
"User-Agent": "okhttp\/3.12.12",
"X-Amzn-Trace-Id": "Root=1-5ed772b8-71eaec363ea2adcca9201200"
},
"url": "https:\/\/httpbin.org\/get?id=42"
}
}
```

[http://httpbin.org/unknown](http://httpbin.org/unknown)
```json
{
"message": "network",
"method": "GET",
"path": "\/gett",
"id": "42",
"response.code": 404,
"response.body": "<!DOCTYPE HTML PUBLIC \"-\/\/W3C\/\/DTD HTML 3.2 Final\/\/EN\">\n<title>404 Not Found<\/title>\n<h1>Not Found<\/h1>\n<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.<\/p>\n"
}
```

## Gradle
Add this to your dependencies block.
```
implementation 'eu.bolt:kalev:1.0.0'
implementation 'eu.bolt:kalev:1.0.1'
```

To use an android extension use this dependency instead:
```
implementation 'eu.bolt:kalev-android:1.0.0'
implementation 'eu.bolt:kalev-android:1.0.1'
```

Kalev-okhttp package:
```
implementation 'eu.bolt:kalev-okhttp:1.0.1'
```

## Naming
Expand Down
4 changes: 3 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ POM_LICENCE_URL=https://github.com/bolteu/kalev#license
POM_LICENCE_DIST=repo

POM_DEVELOPER_ID=bolteu
POM_DEVELOPER_NAME=Bolt Technologies OÜ
POM_DEVELOPER_NAME=Bolt Technologies OÜ

VERSION_NAME=1.0.1
1 change: 1 addition & 0 deletions kalev-okhttp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
10 changes: 10 additions & 0 deletions kalev-okhttp/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apply plugin: 'kotlin'
apply plugin: 'com.vanniktech.maven.publish'

dependencies {
api project (':kalev-lib')

implementation "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}"
implementation "com.squareup.okhttp3:okhttp:3.12.12"
compileOnly "org.json:json:20141113"
}
4 changes: 4 additions & 0 deletions kalev-okhttp/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
POM_ARTIFACT_ID=kalev-okhttp
POM_NAME=kalev-okhttp
POM_PACKAGING=jar
POM_DESCRIPTION=OkHttp logging interceptor with Kalev
108 changes: 108 additions & 0 deletions kalev-okhttp/src/main/java/eu/bolt/kalev/okhttp/LoggingInterceptor.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package eu.bolt.kalev.okhttp

import eu.bolt.kalev.Kalev
import okhttp3.Interceptor
import okhttp3.Interceptor.Chain
import okhttp3.Request
import okhttp3.Response
import okhttp3.ResponseBody
import okio.Buffer
import org.json.JSONException
import org.json.JSONObject
import java.nio.charset.Charset

class LoggingInterceptor : Interceptor {

override fun intercept(chain: Chain): Response {
val request = chain.request()
val response: Response
try {
response = chain.proceed(request)
} catch (e: Exception) {
logError(request ,e)
throw e
}
logResponse(response)
return response
}

private fun logResponse(response: Response) {
val url = response.request().url()
val query = url.queryParameterNames().map { name -> name to url.queryParameter(name) }.toMap()

val entry = Kalev.with("method", response.request().method())
.with("path", url.encodedPath())

query.entries.forEach { queryEntry ->
entry.with(queryEntry.key, queryEntry.value ?: "")
}

formatRequestBody(response.request())?.let {
try {
entry.with("request.body", JSONObject(it))
} catch (exc: JSONException) {
entry.with("request.body", it)
}
}

entry.with("response.code", response.code())
formatResponseBody(response.body())?.let {
try {
entry.with("response.body", JSONObject(it))
} catch (exc: JSONException) {
entry.with("response.body", it)
}
}
entry.v(NETWORK_MESSAGE)
}

private fun formatRequestBody(request: Request): String? {
if (request.method() == "GET") {
return null
}
return request.body()?.let {
val buffer = Buffer()
it.writeTo(buffer)
buffer.readString(Charset.forName("UTF-8"))
}
}

private fun formatResponseBody(body: ResponseBody?): String? {
return body?.let {
val source = it.source()
source.request(Long.MAX_VALUE)
val buffer = source.buffer()
buffer.clone().readString(Charset.forName("UTF-8"))
}
}

private fun logError(request: Request, error: Throwable) {
val url = request.url()
val query = url.queryParameterNames().map { name -> name to url.queryParameter(name) }.toMap()

val entry = Kalev.with("method", request.method())
.with("path", url.encodedPath())

query.entries.forEach { queryEntry ->
entry.with(queryEntry.key, queryEntry.value ?: "")
}

formatRequestBody(request)?.let {
try {
entry.with("request.body", JSONObject(it))
} catch (exc: JSONException) {
entry.with("request.body", it)
}
}

entry.with("response.error", error.javaClass.name)
error.message?.let {
entry.with("response.error.message", it)
}
entry.e(NETWORK_MESSAGE)
}

companion object {
const val NETWORK_MESSAGE = "network"
}
}
2 changes: 2 additions & 0 deletions sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ android {

dependencies {
implementation project (':kalev-android')
implementation project (':kalev-okhttp')
implementation "com.squareup.okhttp3:okhttp:3.12.12"
implementation "org.jetbrains.kotlin:kotlin-stdlib:${versions.kotlin}"
}
2 changes: 2 additions & 0 deletions sample/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="eu.bolt.kalev.sample">

<uses-permission android:name="android.permission.INTERNET"/>

<application
android:label="Kalev Sample"
android:name=".SampleApp">
Expand Down
46 changes: 46 additions & 0 deletions sample/src/main/java/eu/bolt/kalev/sample/NetworkDemo.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package eu.bolt.kalev.sample

import eu.bolt.kalev.Kalev
import eu.bolt.kalev.okhttp.LoggingInterceptor
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.io.IOException

class NetworkDemo {

private val okHttpClient = OkHttpClient.Builder()
.addNetworkInterceptor(LoggingInterceptor())
.build()

fun doGet() {
val request: Request = Request.Builder()
.url("https://httpbin.org/get?id=42")
.header("Content-Type", "application/json")
.build()

okHttpClient.newCall(request).enqueue(networkCallback)
}

fun doNotFound() {
val request: Request = Request.Builder()
.url("https://httpbin.org/unknown")
.header("Content-Type", "application/json")
.build()

okHttpClient.newCall(request).enqueue(networkCallback)
}

private val networkCallback = object : Callback {

override fun onResponse(call: Call, response: Response) {
Kalev.d("Got response")
}

override fun onFailure(call: Call, e: IOException) {
Kalev.e(e, "Got error")
}
}
}
9 changes: 9 additions & 0 deletions sample/src/main/java/eu/bolt/kalev/sample/SampleActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import eu.bolt.kalev.Kalev
class SampleActivity : Activity() {

private var clickCounter = 0
private val networkDemo = NetworkDemo()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand All @@ -18,6 +19,14 @@ class SampleActivity : Activity() {
Kalev.with("counter", clickCounter).d("Click")
}

findViewById<View>(R.id.networkGet).setOnClickListener {
networkDemo.doGet()
}

findViewById<View>(R.id.networkErr).setOnClickListener {
networkDemo.doNotFound()
}

Kalev.d("On start")
}
}
13 changes: 13 additions & 0 deletions sample/src/main/res/layout/sample_activity.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,17 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Click" />

<Button
android:id="@+id/networkGet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="GET request" />

<Button
android:id="@+id/networkErr"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="404 request" />

</LinearLayout>
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
include ':kalev-lib', ':kalev-android', ':sample'
include ':kalev-lib', ':kalev-android', ':sample', ':kalev-okhttp'
rootProject.name = 'kalev'

0 comments on commit ae8fcaa

Please sign in to comment.