mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IJPL-215943 [log] read attachments only once during saving on disk
GitOrigin-RevId: d0a9d31cf7752e5d0eae2ffb08a52ffa7a78f76b
This commit is contained in:
committed by
intellij-monorepo-bot
parent
182d3fa53e
commit
84dc0d1ebc
@@ -16,64 +16,85 @@ import kotlin.io.path.name
|
||||
/**
|
||||
* Handler for logging attachments of [ExceptionWithAttachments] to log folder.
|
||||
*/
|
||||
internal class AttachmentHandler(private val logPath: Path) : Handler() {
|
||||
internal class AttachmentHandler(private val logPath: Path ) : Handler() {
|
||||
override fun publish(record: LogRecord) {
|
||||
if (!isLoggable(record)) return
|
||||
|
||||
val t = record.thrown ?: return
|
||||
val ewas = ExceptionUtil.findCauseAndSuppressed(t, ExceptionWithAttachments::class.java).ifEmpty { return }
|
||||
|
||||
val hasAnyAttachments = ewas.any { it.attachments.isNotEmpty() }
|
||||
if (!hasAnyAttachments) return
|
||||
|
||||
val attachmentsDir = prepareDir(logPath, record) ?: return
|
||||
|
||||
log.info("Saving attachments of [${record.loggerName}] ${t.javaClass.name} to $attachmentsDir")
|
||||
|
||||
writeStacktrace(attachmentsDir, t)
|
||||
|
||||
if (ewas.singleOrNull() == t) {
|
||||
// Single EWA: write files directly into the main folder (no nested folder)
|
||||
writeAttachments(attachmentsDir, ewas.single().attachments)
|
||||
val dirWithLoggedAttachments = if (ewas.singleOrNull() == t) {
|
||||
writeSingleEwa(ewas.single(), t)
|
||||
}
|
||||
else {
|
||||
// Multiple EWAs: create a separate subfolder for each
|
||||
for ((index, ewa) in ewas.withIndex()) {
|
||||
if (ewa.attachments.isEmpty()) continue
|
||||
val subDir = prepareEwaDir(ewa, attachmentsDir, index) ?: continue
|
||||
writeEwaStacktrace(subDir, ewa)
|
||||
writeAttachments(subDir, ewa.attachments)
|
||||
}
|
||||
writeEwas(ewas, t)
|
||||
}
|
||||
|
||||
if (dirWithLoggedAttachments != null) {
|
||||
log.info("Saving attachments of [${record.loggerName}] ${t.javaClass.name} to $dirWithLoggedAttachments")
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareEwaDir(ewa: ExceptionWithAttachments, attachmentsDir: Path, index: Int): Path? {
|
||||
val subDir = attachmentsDir.resolve("ewa-" + (index + 1) + "-" + inferErrorAbbreviation(ewa))
|
||||
try {
|
||||
Files.createDirectories(subDir)
|
||||
return subDir
|
||||
private fun writeEwas(ewas: MutableList<ExceptionWithAttachments>, t: Throwable): Path? {
|
||||
val attachmentsDir = prepareDir(logPath, t) ?: return null
|
||||
|
||||
// store all EWAs directly in the main folder, prefixing files with the EWA index
|
||||
var index = 1
|
||||
for (ewa in ewas) {
|
||||
val attachments = ewa.attachments.ifEmpty { continue }
|
||||
writeEwa(attachmentsDir, ewa, "$index-", attachments)
|
||||
index++
|
||||
}
|
||||
catch (_: IOException) {
|
||||
|
||||
if (index == 1) {
|
||||
// no attachments saved => delete the empty directory
|
||||
try {
|
||||
Files.deleteIfExists(attachmentsDir)
|
||||
}
|
||||
catch (_: IOException) {}
|
||||
return null
|
||||
}
|
||||
|
||||
// Keep the overall throwable stacktrace for context
|
||||
writeStacktrace(attachmentsDir.resolve("stacktrace.txt"), t)
|
||||
|
||||
return attachmentsDir
|
||||
}
|
||||
|
||||
private fun writeEwaStacktrace(subDir: Path, ewa: ExceptionWithAttachments) {
|
||||
private fun writeSingleEwa(ewa: ExceptionWithAttachments, t: Throwable): Path? {
|
||||
val attachments = ewa.attachments.ifEmpty { return null }
|
||||
val attachmentsDir = prepareDir(logPath, t) ?: return null
|
||||
writeEwa(attachmentsDir, ewa, "", attachments)
|
||||
return attachmentsDir
|
||||
}
|
||||
|
||||
private fun writeEwa(
|
||||
attachmentsDir: Path,
|
||||
ewa: ExceptionWithAttachments,
|
||||
prefix: String,
|
||||
attachments: Array<Attachment>,
|
||||
) {
|
||||
writeIndexedEwaStacktrace(attachmentsDir, ewa, prefix)
|
||||
writeAttachments(attachmentsDir, attachments, prefix)
|
||||
}
|
||||
|
||||
private fun writeIndexedEwaStacktrace(dir: Path, ewa: ExceptionWithAttachments, prefix: String) {
|
||||
if (ewa is Throwable) {
|
||||
writeStacktrace(subDir, ewa)
|
||||
val stacktraceFile = dir.resolve("${prefix}stacktrace.txt")
|
||||
writeStacktrace(stacktraceFile, ewa)
|
||||
}
|
||||
else {
|
||||
try {
|
||||
Files.write(subDir.resolve("ewa.txt"), ewa.toString().toByteArray())
|
||||
Files.write(dir.resolve("${prefix}ewa.txt"), ewa.toString().toByteArray())
|
||||
}
|
||||
catch (_: IOException) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareDir(logPath: Path, record: LogRecord): Path? {
|
||||
private fun prepareDir(logPath: Path, t: Throwable): Path? {
|
||||
val baseDir = logPath.parent.resolve("attachments")
|
||||
val dirName = prepareDirName(record)
|
||||
val dirName = prepareDirName(t)
|
||||
val attachmentsDir = baseDir.resolve(dirName)
|
||||
|
||||
try {
|
||||
@@ -93,15 +114,14 @@ internal class AttachmentHandler(private val logPath: Path) : Handler() {
|
||||
return attachmentsDir
|
||||
}
|
||||
|
||||
private fun prepareDirName(record: LogRecord): String {
|
||||
private fun prepareDirName(t: Throwable): String {
|
||||
val now = ZonedDateTime.now()
|
||||
val errorAbbr = inferErrorAbbreviation(record.thrown)
|
||||
val errorAbbr = inferErrorAbbreviation(t)
|
||||
return "attachments-" + dateFormat.format(now) + "-" + errorAbbr
|
||||
}
|
||||
|
||||
private fun writeStacktrace(dir: Path, t: Throwable) {
|
||||
private fun writeStacktrace(stacktraceFile: Path, t: Throwable) {
|
||||
try {
|
||||
val stacktraceFile = dir.resolve("stacktrace.txt")
|
||||
PrintWriter(Files.newBufferedWriter(stacktraceFile)).use {
|
||||
t.printStackTrace(it)
|
||||
}
|
||||
@@ -130,11 +150,11 @@ internal class AttachmentHandler(private val logPath: Path) : Handler() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeAttachments(dir: Path, attachments: Array<Attachment>) {
|
||||
private fun writeAttachments(dir: Path, attachments: Array<Attachment>, prefix: String) {
|
||||
val usedNames = HashSet<String>()
|
||||
for (attachment in attachments) {
|
||||
val base = sanitizeFileName(attachment.name.ifEmpty { "attachment" })
|
||||
val fileName = uniqueName(base, usedNames)
|
||||
val fileName = uniqueName(prefix + base, usedNames)
|
||||
val file = dir.resolve(fileName)
|
||||
try {
|
||||
Files.write(file, attachment.bytes)
|
||||
@@ -149,6 +169,7 @@ internal class AttachmentHandler(private val logPath: Path) : Handler() {
|
||||
* Keep at most [maxGroups] attachment groups under [baseDir]. If the number of existing groups
|
||||
* is >= [maxGroups], delete the oldest ones to make room for a new group.
|
||||
*/
|
||||
@Suppress("SameParameterValue")
|
||||
private fun pruneOldAttachmentGroups(baseDir: Path, maxGroups: Int) {
|
||||
val entries = try {
|
||||
val directoryStream = Files.newDirectoryStream(baseDir) { path ->
|
||||
|
||||
Reference in New Issue
Block a user