From 823d882c78eeb07635e0ad5e5aeadc0bb97c49ae Mon Sep 17 00:00:00 2001 From: Konstantin Ulitin Date: Mon, 16 Oct 2017 19:00:51 +0300 Subject: [PATCH] JS debug logger: add last messages, don't use busy wait --- .../backend/src/debugger/util.kt | 136 +++++++++--------- 1 file changed, 70 insertions(+), 66 deletions(-) diff --git a/platform/script-debugger/backend/src/debugger/util.kt b/platform/script-debugger/backend/src/debugger/util.kt index 7d08a9dca8a2..c36151fdb2fd 100644 --- a/platform/script-debugger/backend/src/debugger/util.kt +++ b/platform/script-debugger/backend/src/debugger/util.kt @@ -19,6 +19,7 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtilRt import com.intellij.openapi.util.registry.Registry +import com.intellij.util.concurrency.AppExecutorUtil import com.intellij.util.io.CharSequenceBackedByChars import com.intellij.util.io.addChannelListener import io.netty.buffer.ByteBuf @@ -28,14 +29,74 @@ import java.io.File import java.io.FileOutputStream import java.nio.CharBuffer import java.text.SimpleDateFormat -import java.util.concurrent.ConcurrentLinkedQueue +import java.util.concurrent.Future +import java.util.concurrent.LinkedBlockingQueue +import java.util.concurrent.TimeUnit internal class LogEntry(val message: Any, val marker: String) { internal val time = System.currentTimeMillis() } -class MessagingLogger internal constructor(private val queue: ConcurrentLinkedQueue) { - internal @Volatile var closed = false +class MessagingLogger internal constructor(debugFile: String) { + private val processFuture: Future<*> + private val queue = LinkedBlockingQueue() + + init { + processFuture = ApplicationManager.getApplication().executeOnPooledThread { + val file = File(FileUtil.expandUserHome(debugFile)) + FileUtilRt.createParentDirs(file) + val out = FileOutputStream(file) + val writer = out.writer() + writer.write("[\n") + writer.flush() + val fileChannel = out.channel + + val dateFormatter = SimpleDateFormat("HH.mm.ss,SSS") + + try { + while (true) { + val entry = queue.take() + + writer.write("""{"timestamp": "${dateFormatter.format(entry.time)}", """) + val message = entry.message + when (message) { + is CharSequence -> { + writer.write("\"${entry.marker}\": ") + writer.flush() + + if (message is CharSequenceBackedByChars) { + fileChannel.write(message.byteBuffer) + } + else { + fileChannel.write(Charsets.UTF_8.encode(CharBuffer.wrap(message))) + } + + writer.write("},\n") + writer.flush() + } + is ByteBuf -> { + writer.write("\"${entry.marker}\": ") + writer.flush() + + message.getBytes(message.readerIndex(), out, message.readableBytes()) + message.release() + + writer.write("},\n") + writer.flush() + } + else -> throw RuntimeException("Unknown message type") + } + } + } + catch (e: InterruptedException) { + } + finally { + writer.write("]") + writer.flush() + out.close() + } + } + } fun add(inMessage: CharSequence, marker: String = "IN") { queue.add(LogEntry(inMessage, marker)) @@ -46,7 +107,9 @@ class MessagingLogger internal constructor(private val queue: ConcurrentLinkedQu } fun close() { - closed = true + AppExecutorUtil.getAppScheduledExecutorService().schedule(fun() { + processFuture.cancel(true) + }, 1, TimeUnit.SECONDS) } fun closeOnChannelClose(channel: Channel) { @@ -63,71 +126,12 @@ class MessagingLogger internal constructor(private val queue: ConcurrentLinkedQu fun createDebugLogger(@PropertyKey(resourceBundle = Registry.REGISTRY_BUNDLE) key: String, suffix: String = ""): MessagingLogger? { var debugFile = Registry.stringValue(key) - if (debugFile.isNullOrEmpty()) { + if (debugFile.isEmpty()) { return null } - if (!suffix.isNullOrEmpty()) { + if (!suffix.isEmpty()) { debugFile = debugFile.replace(".json", suffix + ".json") } - return createDebugLoggerWithFile(debugFile) -} - -fun createDebugLoggerWithFile(debugFile: String): MessagingLogger? { - val queue = ConcurrentLinkedQueue() - val logger = MessagingLogger(queue) - ApplicationManager.getApplication().executeOnPooledThread { - val file = File(FileUtil.expandUserHome(debugFile)) - FileUtilRt.createParentDirs(file) - val out = FileOutputStream(file) - val writer = out.writer() - writer.write("[\n") - writer.flush() - val fileChannel = out.channel - - val dateFormatter = SimpleDateFormat("HH.mm.ss,SSS") - - while (true) { - val entry = queue.poll() ?: if (logger.closed) { - break - } - else { - continue - } - - writer.write("""{"timestamp": "${dateFormatter.format(entry.time)}", """) - val message = entry.message - when (message) { - is CharSequence -> { - writer.write("\"${entry.marker}\": ") - writer.flush() - - if (message is CharSequenceBackedByChars) { - fileChannel.write(message.byteBuffer) - } - else { - fileChannel.write(Charsets.UTF_8.encode(CharBuffer.wrap(message))) - } - - writer.write("},\n") - writer.flush() - } - is ByteBuf -> { - writer.write("\"${entry.marker}\": ") - writer.flush() - - message.getBytes(message.readerIndex(), out, message.readableBytes()) - message.release() - - writer.write("},\n") - writer.flush() - } - else -> throw RuntimeException("Unknown message type") - } - } - writer.write("]") - writer.flush() - out.close() - } - return logger + return MessagingLogger(debugFile) }