JS debug logger: add last messages, don't use busy wait

This commit is contained in:
Konstantin Ulitin
2017-10-16 19:01:37 +03:00
parent 0d8bf87b38
commit 823d882c78
@@ -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<LogEntry>) {
internal @Volatile var closed = false
class MessagingLogger internal constructor(debugFile: String) {
private val processFuture: Future<*>
private val queue = LinkedBlockingQueue<LogEntry>()
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<LogEntry>()
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)
}