Search code examples
javaandroidkotlinokhttpmockwebserver

java.lang.IllegalArgumentException: Log tag "okhttp3.mockwebserver.MockWebServer" exceeds limit of 23 characters


Some points to clarify that this is not a duplicate question as someone suggested:


Original question:

I am working on Android web service tests using Expresso and MockWebServer, however I encounter below exception that tells me the log tag issue:

"okhttp3.mockwebserver.MockWebServer" exceeds limit of 23 characters.

Detailed stack trace is as following:

2020-08-13 11:31:13.277 16901-17085/com.xxx.app I/okhttp.OkHttpClient: <-- HTTP FAILED: java.net.SocketTimeoutException: timeout
2020-08-13 11:31:13.280 16901-17346/com.xxx.app E/AndroidRuntime: FATAL EXCEPTION: MockWebServer TaskRunner
    Process: com.xxx.app, PID: 16901
    java.lang.IllegalArgumentException: Log tag "okhttp3.mockwebserver.MockWebServer" exceeds limit of 23 characters
    
        at android.util.Log.isLoggable(Native Method)
        at okhttp3.internal.platform.android.AndroidLog.androidLog$okhttp(AndroidLog.kt:66)
        at okhttp3.internal.platform.android.AndroidLogHandler.publish(AndroidLog.kt:39)
        at java.util.logging.Logger.log(Logger.java:615)
        at java.util.logging.Logger.doLog(Logger.java:636)
        at java.util.logging.Logger.log(Logger.java:725)
        at okhttp3.mockwebserver.MockWebServer$serveConnection$$inlined$execute$1.runOnce(TaskQueue.kt:224)
        at okhttp3.internal.concurrent.TaskRunner.runTask(TaskRunner.kt:116)
        at okhttp3.internal.concurrent.TaskRunner.access$runTask(TaskRunner.kt:42)
        at okhttp3.internal.concurrent.TaskRunner$runnable$1.run(TaskRunner.kt:65)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
        at java.lang.Thread.run(Thread.java:762)
2020-08-13 11:31:13.293 16901-17346/com.xxx.app I/Process: Sending signal. PID: 16901 SIG: 9

Solution

  • I have figured out the workaround for this issue after digging into the source code of MockWebServer.kt. Inside this file, there is a property like below:

    private val logger = Logger.getLogger(MockWebServer::class.java.name)
    

    The MockWebServer::class.java.name will return a full class name okhttp3.mockwebserver.MockWebServer, obviously, this name as an Android log tag is already longer than 23 chars. The fix is using Kotlin reflection to replace the logger property. Reflection code is as below:

    fun <T : Any> T.setPrivateProperty(variableName: String, data: Any): Any? {
        return javaClass.getDeclaredField(variableName).let { field ->
            field.isAccessible = true
            field.set(this, data)
            return@let field.get(this)
        }
    }
    
    

    Inside the @before method, set the logger tag with simpleName

    val mockWebServer = MockWebServer() // this is declared inside test class.
    
    @Before
    fun setup() {
    
        mockWebServer.setAndReturnPrivateProperty("logger", 
            Logger.getLogger(MockWebServer::class.java.simpleName))
    
        mockWebServer.start(8080)
    }    
    

    MockWebServer::class.java.simpleName will return a shorter class name and fix the issue.