Scarlet icon indicating copy to clipboard operation
Scarlet copied to clipboard

Log raw requests/responses

Open amitav13 opened this issue 5 years ago • 3 comments

Hi, I wanted to log all raw requests/responses going out from and into my websocket connection, like how HttpLoggingInterceptor does for regular Http requests/responses. OkHttp interceptors don't seem to have access to websocket messages.

Is there a way to do this from within Scarlet itself, since the OkHttp Websockets being created aren't exposed publicly?

amitav13 avatar Jul 27 '19 11:07 amitav13

Did you find a way to do this @amitav13?

francos avatar Jan 21 '20 04:01 francos

@amitav13 I found a way to do this, it is not the best solution but seems like there is no good solution provided from Scarlet itself.

You can create your own MessageAdapter and copy the code from whatever adapter you are currently using (in my case that is GsonMessageAdapter). Then, you have to change the fromMessage() and toMessage() methods to add the logging.

For example:

class WebSocketMessageAdapter<T> private constructor(

    private val gson: Gson,
    private val typeAdapter: TypeAdapter<T>

) : MessageAdapter<T> {

    override fun fromMessage(message: Message): T {
        val stringValue = when (message) {
            is Message.Text -> message.value
            is Message.Bytes -> String(message.value)
        }
        val jsonReader = gson.newJsonReader(StringReader(stringValue))

        val wsMessageJson = typeAdapter.read(jsonReader)!!

        // TODO: Log wsMessageJson

        return wsMessageJson
    }

    override fun toMessage(data: T): Message {
        // TODO: Log data

        val buffer = Buffer()
        val writer = OutputStreamWriter(buffer.outputStream(), StandardCharsets.UTF_8)
        val jsonWriter = gson.newJsonWriter(writer)
        typeAdapter.write(jsonWriter, data)
        jsonWriter.close()
        val stringValue = buffer.readByteString().utf8()
        return Message.Text(stringValue)
    }

    /*
     * Inner types
     */

    class Factory(

        private val gson: Gson = DEFAULT_GSON

    ) : MessageAdapter.Factory {

        override fun create(type: Type, annotations: Array<Annotation>): MessageAdapter<*> {
            val typeAdapter = gson.getAdapter(TypeToken.get(type))
            return WebSocketMessageAdapter(gson, typeAdapter)
        }

        /*
         * Inner types
         */

        companion object {
            private val DEFAULT_GSON = Gson()
        }

    }

}

francos avatar Jan 21 '20 04:01 francos

@FrancoSabadini I didn't end up finding a good way for this. Yours seems like the kind of approach we'd want to take. Ideally we'd just be passing in a flag to enable this logging into the Scarlet builder.

amitav13 avatar Jan 21 '20 06:01 amitav13