/**
* Copyright 2024 Beijing Baolande Software Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Runtime Library Exception to the Apache 2.0 License:
*
* As an exception, if you use this Software to compile your source code and
* portions of this Software are embedded into the binary product as a result,
* you may redistribute such product without providing attribution as would
* otherwise be required by Sections 4(a), 4(b) and 4(d) of the License.
*/
package hyperion.logadapter
/**
* 格式化日志
*
* @author yangfuping
*/
public interface SimpleLogFormatter {
func format(record: SimpleLogRecord): String
}
/**
* 默认的SimpleLogFormatter实现
*
* @author yangfuping
*/
public open class DefaultSimpleLogFormatter <: SimpleLogFormatter {
private static let RECORD_BEGIN_MARKER = "####|"
private static let RECORD_END_MARKER = "|####"
private static let FIELD_SEPARATOR = '|'
protected static let LINE_SEPARATOR = '\n'
private static let INDENT_STEP = " "
private static let MAX_CAUSE_DEPTH = 3
public open func format(record: SimpleLogRecord): String {
let builder = StringBuilder()
builder.append(RECORD_BEGIN_MARKER)
builder.append(formatDateTime(record.logTime))
builder.append(FIELD_SEPARATOR)
builder.append(record.level.getName())
builder.append(FIELD_SEPARATOR)
builder.append(record.threadName)
builder.append(FIELD_SEPARATOR)
builder.append(record.message)
if (let Some(ex) <- record.exception) {
builder.append(LINE_SEPARATOR)
formatException(builder, ex)
}
builder.append(RECORD_END_MARKER)
builder.append(LINE_SEPARATOR)
return builder.toString()
}
public static func formatDateTime(dateTime: DateTime): String {
let year = dateTime.year
let month = dateTime.month.toInteger()
let day = dateTime.dayOfMonth
let hour = dateTime.hour
let minute = dateTime.minute
let second = dateTime.second
let millSecond = dateTime.nanosecond / (1000 * 1000)
return year.format("04") + "-" + month.format("02") + "-" + day.format("02") + "-" + hour.format("02") + ":" +
minute.format("02") + ":" + second.format("02") + "." + millSecond.format("03")
}
public static func formatException(exception: Exception): String {
let builder = StringBuilder()
formatException(builder, exception)
return builder.toString()
}
public static func formatException(builder: StringBuilder, exception: Exception) {
builder.append(exception.toString())
builder.append(LINE_SEPARATOR)
builder.append("Detail stack traces:")
builder.append(LINE_SEPARATOR)
let traces = exception.getStackTrace()
for (trace in traces) {
builder.append(
"${INDENT_STEP}at " + trace.declaringClass + "." + trace.methodName + "(" + trace.fileName + ":" +
"${trace.lineNumber}" + ")"
)
builder.append(LINE_SEPARATOR)
}
if (let Some(causeEmbbed) <- (exception as CauseEmbedded)) {
if (let Some(innerCause) <- causeEmbbed.getCause()) {
if (refEq(innerCause, exception)) {
return
}
let depth = AtomicInt64(0)
appendCause(builder, INDENT_STEP, depth, causeEmbbed)
}
}
}
public static func appendCause(
builder: StringBuilder,
indent: String,
depth: AtomicInt64,
causeEmbbed: CauseEmbedded
): Unit {
if (let Some(cause) <- causeEmbbed.getCause()) {
depth.fetchAdd(1)
if (depth.load() > MAX_CAUSE_DEPTH) {
// 避免无限循环
return
}
builder.append(LINE_SEPARATOR)
builder.append(indent + "Cause: " + cause.toString())
builder.append(LINE_SEPARATOR)
builder.append("${indent}Detail stack traces:")
builder.append(LINE_SEPARATOR)
let traces = cause.getStackTrace()
for (trace in traces) {
builder.append(indent + INDENT_STEP)
builder.append(
"at " + trace.declaringClass + "." + trace.methodName + "(" + trace.fileName + ":" +
"${trace.lineNumber}" + ")"
)
builder.append(LINE_SEPARATOR)
}
if (let Some(causeEmbbed) <- (cause as CauseEmbedded)) {
if (let Some(innerCause) <- causeEmbbed.getCause()) {
if (refEq(innerCause, cause)) {
return
}
appendCause(builder, indent + INDENT_STEP, depth, causeEmbbed)
}
}
}
}
}