日志打印示例
库开发场景记录日志
下面是开发仓颉库时,打印日志的示例。
代码如下:
import log.*
import logger.*
import std.console.Console
public class PGConnection {
let objId: Int64 = 1
let logger = getGlobalLogger(("name", "PGConnection"))
public func close(): Unit {
logger.trace("driver conn closed", ("id", objId))
}
}
main ():Unit {
let tl = SimpleLogger(Console.stdOut)
tl.level = LogLevel.TRACE
setGlobalLogger(tl)
var conn = PGConnection()
conn.close()
}
运行结果如下:
2024-11-21T20:16:43.33200773+08:00 TRACE driver conn closed name="PGConnection" id=1
应用程序开发场景日志打印
下面是 自定义 PasswordFilter 和 TextLogger 日志打印示例。
代码如下:
import std.time.*
import std.io.{OutputStream, ByteBuffer, BufferedOutputStream}
import std.console.Console
import std.fs.*
import std.collection.{ArrayList, Map, HashMap}
import std.collection.concurrent.NonBlockingQueue
import std.sync.AtomicBool
import std.time.DateTime
import log.{LogValue, LogWriter, Logger, Attr, LogRecord, LogLevel}
import log
public class PasswordFilter <: Logger {
var _level = LogLevel.INFO
let processor: Logger
public init(logger: Logger) {
processor = logger
}
public mut prop level: LogLevel {
get() {
_level
}
set(v) {
_level = v
}
}
public func withAttrs(attrs: Array<Attr>): Logger {
this
}
// log
public func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit {
let record: LogRecord = LogRecord(DateTime.now(), level, message, attrs)
log(record)
}
// lazy
public func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit {
let record: LogRecord = LogRecord(DateTime.now(), level, message(), attrs)
log(record)
}
// 根据键值对的名字过滤,将密码值换成 "***"
public func log(record: LogRecord): Unit {
var attrs = record.attrs.clone()
for (i in 0..attrs.size) {
var attr = attrs[i]
if (attr[0] == "password") {
attrs[i] = (attr[0], "***")
}
}
let r = LogRecord(record.time, record.level, record.message, attrs)
processor.log(r)
}
public func isClosed(): Bool {
false
}
public func close(): Unit {
}
}
main() {
let o = ByteBuffer()
let tl = TextLogger(Console.stdOut)
tl.level = LogLevel.TRACE
let l = PasswordFilter(tl)
log.setGlobalLogger(l)
let logger = log.getGlobalLogger([("name", "main")])
let user = User()
// 普通记录信息日志
logger.info("Hello, World!", ("k1", [[1, 4], [2, 5], [3]]), ("password", "v22222"))
// 记录诊断日志,如果 DEBUG 级别未开启,直接返回,几乎无cost
logger.debug("Logging in user ${user.name} with birthday ${user.birthdayCalendar}")
// lazy 方式记录耗时日志数据
logger.log(LogLevel.ERROR, "long-running operation msg", ("k1", 100), ("k2", user.birthdayCalendar),
("oper", ToStringWrapper({=> "Some long-running operation returned"})))
logger.log(LogLevel.ERROR, "long-running operation msg", ("sourcePackage", @sourcePackage()),
("sourceFile", @sourceFile()), ("sourceLine", @sourceLine()), ("birthdayCalendar", user.birthdayCalendar),
("oper", ToStringWrapper({=> "Some long-running operation returned"})))
let m = HashMap<String, String>()
m.add("k1", "1")
m.add("k2", "2")
m.add("k3", "3")
logger.trace({=> "Some long-running operation returned"}, ("k1", m))
let m2 = HashMap<String, LogValue>()
m2.add("g1", m)
// 如果TRACE 级别没有开启,那么lambda表达式不会被执行
logger.trace({=> "Some long-running operation returned"}, ("k2", m2))
// Console.stdOut.write(o.bytes())
// Console.stdOut.flush()
}
public class User {
public prop name: String {
get() {
"foo"
}
}
public prop birthdayCalendar: DateTime {
get() {
DateTime.now()
}
}
}
public class ToStringWrapper <: ToString & LogValue {
let _fn: () -> String
public init(fn: () -> String) {
_fn = fn
}
public func toString(): String {
return _fn()
}
public func writeTo(w: LogWriter): Unit {
w.writeValue(_fn())
}
}
func expensiveOperation(): String {
for (_ in 0..1000000) {
unsafe {
let b = LibC.malloc<Byte>(count: 1000)
LibC.free(b)
}
}
"Some long-running operation returned"
}
public class TextLogger <: Logger {
let w: TextLogWriter
let opts = HashMap<String, String>()
let _closed = AtomicBool(false)
let queue = NonBlockingQueue<LogRecord>()
let bo: BufferedOutputStream<OutputStream>
let _attrs = ArrayList<Attr>()
var _level = LogLevel.INFO
public init(output: OutputStream) {
bo = BufferedOutputStream<OutputStream>(output)
w = TextLogWriter(bo)
}
public mut prop level: LogLevel {
get() {
_level
}
set(v) {
_level = v
}
}
public func withAttrs(attrs: Array<Attr>): Logger {
if (attrs.size > 0) {
let nl = TextLogger(w.out)
nl._attrs.add(all: attrs)
return nl
}
return this
}
// log
public func log(level: LogLevel, message: String, attrs: Array<Attr>): Unit {
if (this.enabled(level)) {
let record: LogRecord = LogRecord(DateTime.now(), level, message, attrs)
log(record)
}
}
// lazy
public func log(level: LogLevel, message: () -> String, attrs: Array<Attr>): Unit {
if (this.enabled(level)) {
let record: LogRecord = LogRecord(DateTime.now(), level, message(), attrs)
log(record)
}
}
public func log(record: LogRecord): Unit {
// write time
w.writeKey("time")
w.writeValue(record.time)
w.writeString(" ")
// write level
w.writeKey("level")
w.writeString(record.level.toString())
w.writeString(" ")
// write message
w.writeKey("msg")
w.writeValue(record.message)
w.writeString(" ")
// write source
// write attrs
for (i in 0..record.attrs.size) {
let attr = record.attrs[i]
w.writeKey(attr[0])
w.writeValue(attr[1])
if (i < record.attrs.size - 1) {
w.writeString(" ")
}
}
w.writeString("\n")
bo.flush()
}
public func isClosed(): Bool {
_closed.load()
}
public func close(): Unit {
if (isClosed()) {
return
}
_closed.store(true)
}
}
class TextLogWriter <: LogWriter {
var out: OutputStream
init(out: OutputStream) {
this.out = out
}
public func writeNone(): Unit {
out.write("None".toArray())
}
public func writeInt(v: Int64): Unit {
out.write(v.toString().toArray())
}
public func writeUInt(v: UInt64): Unit {
out.write(v.toString().toArray())
}
public func writeBool(v: Bool): Unit {
out.write(v.toString().toArray())
}
public func writeFloat(v: Float64): Unit {
out.write(v.toString().toArray())
}
public func writeString(v: String): Unit {
out.write(v.toArray())
}
public func writeDateTime(v: DateTime): Unit {
out.write(v.toString().toArray())
}
public func writeDuration(v: Duration): Unit {
out.write(v.toString().toArray())
}
public func writeException(v: Exception): Unit {
out.write(v.toString().toArray())
}
public func writeKey(v: String): Unit {
out.write(v.toString().toArray())
out.write("=".toArray())
}
public func writeValue(v: LogValue): Unit {
match (v) {
case vv: String =>
out.write("\"".toArray())
out.write(vv.toArray())
out.write("\"".toArray())
case vv: ToString =>
out.write("\"".toArray())
out.write(vv.toString().toArray())
out.write("\"".toArray())
case _ =>
out.write("\"".toArray())
v.writeTo(this)
out.write("\"".toArray())
}
}
public func startArray(): Unit {
out.write("[".toArray())
}
public func endArray(): Unit {
out.write("]".toArray())
}
public func startObject(): Unit {
out.write("{".toArray())
}
public func endObject(): Unit {
out.write("}".toArray())
}
}
运行结果如下:
time="2024-06-17T14:10:07.1861349Z" level=INFO msg="Hello, World!" k1="[[1, 4], [2, 5], [3]]" password="***"
time="2024-06-17T14:10:07.1864929Z" level=DEBUG msg="Logging in user foo with birthday 2024-06-17T14:10:07.1864802Z"
time="2024-06-17T14:10:07.1869579Z" level=ERROR msg="long-running operation msg" k1="100" k2="2024-06-17T14:10:07.186957Z" oper="Some long-running operation returned"
time="2024-06-17T14:10:07.18742Z" level=ERROR msg="long-running operation msg" sourcePackage="log" sourceFile="main.cj" sourceLine="77" birthdayCalendar="2024-06-17T14:10:07.1874188Z" oper="Some long-running operation returned"
time="2024-06-17T14:10:07.1879195Z" level=TRACE msg="Some long-running operation returned" k1="[(k1, 1), (k2, 2), (k3, 3)]"
time="2024-06-17T14:10:07.1881599Z" level=TRACE msg="Some long-running operation returned" k2="{g1="[(k1, 1), (k2, 2), (k3, 3)]"}"