mirror of
https://github.com/TermoraDev/termora.git
synced 2026-01-15 18:02:58 +08:00
feat: 当停止记录终端日志的时候立即关闭文件流
This commit is contained in:
@@ -23,6 +23,8 @@ class TerminalLoggerAction : AnAction(I18n.getString("termora.terminal-logger"),
|
|||||||
var isRecording = properties.getString("terminal.logger.isRecording")?.toBoolean() ?: false
|
var isRecording = properties.getString("terminal.logger.isRecording")?.toBoolean() ?: false
|
||||||
private set(value) {
|
private set(value) {
|
||||||
field = value
|
field = value
|
||||||
|
// firePropertyChange
|
||||||
|
putValue("Recording", value)
|
||||||
properties.putString("terminal.logger.isRecording", value.toString())
|
properties.putString("terminal.logger.isRecording", value.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,13 @@ import org.apache.commons.io.IOUtils
|
|||||||
import org.apache.commons.lang3.time.DateFormatUtils
|
import org.apache.commons.lang3.time.DateFormatUtils
|
||||||
import org.jdesktop.swingx.action.ActionManager
|
import org.jdesktop.swingx.action.ActionManager
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import java.beans.PropertyChangeListener
|
||||||
import java.io.BufferedWriter
|
import java.io.BufferedWriter
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileWriter
|
import java.io.FileWriter
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
class TerminalLoggerDataListener(private val terminal: Terminal) : DataListener {
|
class TerminalLoggerDataListener(private val terminal: Terminal) : DataListener {
|
||||||
companion object {
|
companion object {
|
||||||
@@ -26,11 +28,21 @@ class TerminalLoggerDataListener(private val terminal: Terminal) : DataListener
|
|||||||
private val log = LoggerFactory.getLogger(TerminalLoggerDataListener::class.java)
|
private val log = LoggerFactory.getLogger(TerminalLoggerDataListener::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val coroutineScope by lazy { CoroutineScope(Dispatchers.IO) }
|
private var coroutineScope: CoroutineScope? = null
|
||||||
private val channel by lazy { Channel<String>(Channel.UNLIMITED) }
|
private var channel: Channel<String>? = null
|
||||||
|
private var file: File? = null
|
||||||
|
private var writer: BufferedWriter? = null
|
||||||
|
|
||||||
private lateinit var file: File
|
private val isRecording = AtomicBoolean(false)
|
||||||
private lateinit var writer: BufferedWriter
|
|
||||||
|
// 监听 Recording 变化,如果已经停止录制,那么立即关闭文件
|
||||||
|
private val terminalLoggerActionPropertyChangeListener = PropertyChangeListener { evt ->
|
||||||
|
if (evt.propertyName == "Recording") {
|
||||||
|
if (evt.newValue == false) {
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val host: Host?
|
private val host: Host?
|
||||||
get() {
|
get() {
|
||||||
@@ -65,21 +77,31 @@ class TerminalLoggerDataListener(private val terminal: Terminal) : DataListener
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 尝试记录
|
try {// 尝试记录
|
||||||
tryRecord(data as String, host, action)
|
tryRecord(data as String, host, action)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (log.isErrorEnabled) {
|
||||||
|
log.error(e.message, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tryRecord(text: String, host: Host, action: TerminalLoggerAction) {
|
private fun tryRecord(text: String, host: Host, action: TerminalLoggerAction) {
|
||||||
if (!::writer.isInitialized) {
|
if (isRecording.compareAndSet(false, true)) {
|
||||||
|
|
||||||
file = createFile(host, action.getLogDir())
|
val file = createFile(host, action.getLogDir()).apply { file = this }
|
||||||
|
val writer = BufferedWriter(FileWriter(file, false)).apply { writer = this }
|
||||||
writer = BufferedWriter(FileWriter(file, false))
|
|
||||||
|
|
||||||
if (log.isInfoEnabled) {
|
if (log.isInfoEnabled) {
|
||||||
log.info("Terminal logger file: ${file.absolutePath}")
|
log.info("Terminal logger file: ${file.absolutePath}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
action.removePropertyChangeListener(terminalLoggerActionPropertyChangeListener)
|
||||||
|
action.addPropertyChangeListener(terminalLoggerActionPropertyChangeListener)
|
||||||
|
|
||||||
|
val coroutineScope = this.coroutineScope ?: CoroutineScope(Dispatchers.IO).apply { coroutineScope = this }
|
||||||
|
val channel = this.channel ?: Channel<String>(Channel.UNLIMITED).apply { channel = this }
|
||||||
|
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
while (coroutineScope.isActive) {
|
while (coroutineScope.isActive) {
|
||||||
channel.receiveCatching().onSuccess {
|
channel.receiveCatching().onSuccess {
|
||||||
@@ -97,7 +119,9 @@ class TerminalLoggerDataListener(private val terminal: Terminal) : DataListener
|
|||||||
channel.trySend("${ControlCharacters.LF}${ControlCharacters.CR}").isSuccess
|
channel.trySend("${ControlCharacters.LF}${ControlCharacters.CR}").isSuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.trySend(text).isSuccess
|
if (isRecording.get()) {
|
||||||
|
channel?.trySend(text)?.isSuccess
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createFile(host: Host, dir: File): File {
|
private fun createFile(host: Host, dir: File): File {
|
||||||
@@ -119,29 +143,41 @@ class TerminalLoggerDataListener(private val terminal: Terminal) : DataListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun close() {
|
private fun close() {
|
||||||
if (!::writer.isInitialized) {
|
if (!isRecording.compareAndSet(true, false)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.close()
|
// 移除监听
|
||||||
coroutineScope.cancel()
|
ActionManager.getInstance().getAction(Actions.TERMINAL_LOGGER)
|
||||||
|
?.removePropertyChangeListener(terminalLoggerActionPropertyChangeListener)
|
||||||
|
|
||||||
|
this.channel?.close()
|
||||||
|
this.coroutineScope?.cancel()
|
||||||
|
|
||||||
|
this.channel = null
|
||||||
|
this.coroutineScope = null
|
||||||
|
|
||||||
// write end
|
// write end
|
||||||
runCatching {
|
runCatching {
|
||||||
val date = DateFormatUtils.format(Date(), I18n.getString("termora.date-format"))
|
val date = DateFormatUtils.format(Date(), I18n.getString("termora.date-format"))
|
||||||
writer.write("${ControlCharacters.LF}${ControlCharacters.CR}")
|
this.writer?.write("${ControlCharacters.LF}${ControlCharacters.CR}")
|
||||||
writer.write("[END] ---- $date ----")
|
this.writer?.write("[END] ---- $date ----")
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
if (log.isErrorEnabled) {
|
if (log.isErrorEnabled) {
|
||||||
log.info(it.message, it)
|
log.error(it.message, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IOUtils.closeQuietly(this.writer)
|
||||||
|
|
||||||
IOUtils.closeQuietly(writer)
|
val file = this.file
|
||||||
|
if (log.isInfoEnabled && file != null) {
|
||||||
if (log.isInfoEnabled) {
|
|
||||||
log.info("Terminal logger file: {} saved", file.absolutePath)
|
log.info("Terminal logger file: {} saved", file.absolutePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.writer = null
|
||||||
|
this.file = null
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user