@onekeyfe/react-native-native-logger 1.1.27 → 1.1.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -3,6 +3,7 @@ package com.margelo.nitro.nativelogger
|
|
|
3
3
|
import com.facebook.proguard.annotations.DoNotStrip
|
|
4
4
|
import com.margelo.nitro.core.Promise
|
|
5
5
|
import java.io.File
|
|
6
|
+
import java.io.RandomAccessFile
|
|
6
7
|
|
|
7
8
|
@DoNotStrip
|
|
8
9
|
class NativeLogger : HybridNativeLoggerSpec() {
|
|
@@ -24,24 +25,6 @@ class NativeLogger : HybridNativeLoggerSpec() {
|
|
|
24
25
|
Regex("(?:eyJ|AAAA)[A-Za-z0-9+/=]{40,}"),
|
|
25
26
|
)
|
|
26
27
|
|
|
27
|
-
/** Rate limiting: max messages per second */
|
|
28
|
-
private const val MAX_MESSAGES_PER_SECOND = 100
|
|
29
|
-
@Volatile private var messageCount = 0
|
|
30
|
-
@Volatile private var windowStartMs = System.currentTimeMillis()
|
|
31
|
-
private val rateLimitLock = Any()
|
|
32
|
-
|
|
33
|
-
private fun isRateLimited(): Boolean {
|
|
34
|
-
synchronized(rateLimitLock) {
|
|
35
|
-
val now = System.currentTimeMillis()
|
|
36
|
-
if (now - windowStartMs >= 1000L) {
|
|
37
|
-
windowStartMs = now
|
|
38
|
-
messageCount = 0
|
|
39
|
-
}
|
|
40
|
-
messageCount++
|
|
41
|
-
return messageCount > MAX_MESSAGES_PER_SECOND
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
28
|
fun sanitize(message: String): String {
|
|
46
29
|
var result = message
|
|
47
30
|
for (pattern in sensitivePatterns) {
|
|
@@ -54,7 +37,6 @@ class NativeLogger : HybridNativeLoggerSpec() {
|
|
|
54
37
|
}
|
|
55
38
|
|
|
56
39
|
override fun write(level: Double, msg: String) {
|
|
57
|
-
if (isRateLimited()) return
|
|
58
40
|
val sanitized = sanitize(msg)
|
|
59
41
|
when (level.toInt()) {
|
|
60
42
|
0 -> OneKeyLog.debug("JS", sanitized)
|
|
@@ -88,6 +70,7 @@ class NativeLogger : HybridNativeLoggerSpec() {
|
|
|
88
70
|
|
|
89
71
|
override fun deleteLogFiles(): Promise<Unit> {
|
|
90
72
|
return Promise.async {
|
|
73
|
+
OneKeyLog.flush()
|
|
91
74
|
val dir = OneKeyLog.logsDirectory
|
|
92
75
|
if (dir.isEmpty()) return@async
|
|
93
76
|
val files = File(dir).listFiles { _, name -> name.endsWith(".log") }
|
|
@@ -95,9 +78,16 @@ class NativeLogger : HybridNativeLoggerSpec() {
|
|
|
95
78
|
OneKeyLog.warn("NativeLogger", "Failed to list log directory for deletion")
|
|
96
79
|
return@async
|
|
97
80
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
81
|
+
files.forEach { file ->
|
|
82
|
+
try {
|
|
83
|
+
if (file.name == "app-latest.log") {
|
|
84
|
+
RandomAccessFile(file, "rw").use { raf ->
|
|
85
|
+
raf.setLength(0L)
|
|
86
|
+
}
|
|
87
|
+
} else if (!file.delete()) {
|
|
88
|
+
OneKeyLog.warn("NativeLogger", "Failed to delete log file")
|
|
89
|
+
}
|
|
90
|
+
} catch (_: Exception) {
|
|
101
91
|
OneKeyLog.warn("NativeLogger", "Failed to delete log file")
|
|
102
92
|
}
|
|
103
93
|
}
|
|
@@ -23,10 +23,48 @@ object OneKeyLog {
|
|
|
23
23
|
private const val MAX_FILE_SIZE = 20L * 1024 * 1024 // 20 MB
|
|
24
24
|
private const val MAX_HISTORY = 6
|
|
25
25
|
private const val TOTAL_SIZE_CAP = MAX_FILE_SIZE * MAX_HISTORY
|
|
26
|
+
private const val DEBUG_INFO_RATE_PER_SECOND = 400.0
|
|
27
|
+
private const val DEBUG_INFO_BURST = 2000.0
|
|
28
|
+
private const val WARN_RATE_PER_SECOND = 1000.0
|
|
29
|
+
private const val WARN_BURST = 2000.0
|
|
26
30
|
|
|
27
31
|
// Cached value; empty string means context was not yet available (will retry)
|
|
28
32
|
@Volatile
|
|
29
33
|
private var cachedLogsDir: String? = null
|
|
34
|
+
private data class TokenBucket(
|
|
35
|
+
val ratePerSecond: Double,
|
|
36
|
+
val burstCapacity: Double,
|
|
37
|
+
var tokens: Double,
|
|
38
|
+
var lastRefillAtMs: Long,
|
|
39
|
+
) {
|
|
40
|
+
fun allow(nowMs: Long): Boolean {
|
|
41
|
+
val elapsedMs = (nowMs - lastRefillAtMs).coerceAtLeast(0L)
|
|
42
|
+
if (elapsedMs > 0L) {
|
|
43
|
+
val refill = (elapsedMs.toDouble() / 1000.0) * ratePerSecond
|
|
44
|
+
tokens = minOf(burstCapacity, tokens + refill)
|
|
45
|
+
lastRefillAtMs = nowMs
|
|
46
|
+
}
|
|
47
|
+
if (tokens < 1.0) return false
|
|
48
|
+
tokens -= 1.0
|
|
49
|
+
return true
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private val rateLimitBuckets: MutableMap<String, TokenBucket> = mutableMapOf(
|
|
54
|
+
"DEBUG" to TokenBucket(
|
|
55
|
+
DEBUG_INFO_RATE_PER_SECOND, DEBUG_INFO_BURST, DEBUG_INFO_BURST, System.currentTimeMillis()
|
|
56
|
+
),
|
|
57
|
+
"INFO" to TokenBucket(
|
|
58
|
+
DEBUG_INFO_RATE_PER_SECOND, DEBUG_INFO_BURST, DEBUG_INFO_BURST, System.currentTimeMillis()
|
|
59
|
+
),
|
|
60
|
+
"WARN" to TokenBucket(
|
|
61
|
+
WARN_RATE_PER_SECOND, WARN_BURST, WARN_BURST, System.currentTimeMillis()
|
|
62
|
+
),
|
|
63
|
+
)
|
|
64
|
+
private val droppedCounts: MutableMap<String, Int> = mutableMapOf()
|
|
65
|
+
@Volatile
|
|
66
|
+
private var lastDropReportMs = System.currentTimeMillis()
|
|
67
|
+
private val rateLimitLock = Any()
|
|
30
68
|
|
|
31
69
|
/**
|
|
32
70
|
* Initialise OneKeyLog with an Android Context before NitroModules is ready.
|
|
@@ -154,7 +192,61 @@ object OneKeyLog {
|
|
|
154
192
|
return truncate("$time | $level : [$safeTag] $safeMessage")
|
|
155
193
|
}
|
|
156
194
|
|
|
195
|
+
private fun buildDropReportLocked(nowMs: Long): String? {
|
|
196
|
+
if (nowMs - lastDropReportMs < 1000L) return null
|
|
197
|
+
if (droppedCounts.isEmpty()) {
|
|
198
|
+
lastDropReportMs = nowMs
|
|
199
|
+
return null
|
|
200
|
+
}
|
|
201
|
+
val ordered = listOf("DEBUG", "INFO", "WARN")
|
|
202
|
+
val parts = ordered.mapNotNull { level ->
|
|
203
|
+
val count = droppedCounts[level] ?: 0
|
|
204
|
+
if (count > 0) "$level=$count" else null
|
|
205
|
+
}
|
|
206
|
+
droppedCounts.clear()
|
|
207
|
+
lastDropReportMs = nowMs
|
|
208
|
+
if (parts.isEmpty()) return null
|
|
209
|
+
return "[OneKeyLog] Rate-limited logs (last 1s): ${parts.joinToString(", ")}"
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
private data class RateLimitDecision(val drop: Boolean, val report: String?)
|
|
213
|
+
|
|
214
|
+
private fun evaluateRateLimit(level: String): RateLimitDecision {
|
|
215
|
+
synchronized(rateLimitLock) {
|
|
216
|
+
val nowMs = System.currentTimeMillis()
|
|
217
|
+
var report = buildDropReportLocked(nowMs)
|
|
218
|
+
|
|
219
|
+
// Never limit error logs.
|
|
220
|
+
if (level == "ERROR") {
|
|
221
|
+
return RateLimitDecision(drop = false, report = report)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
val bucket = rateLimitBuckets[level]
|
|
225
|
+
if (bucket == null) {
|
|
226
|
+
return RateLimitDecision(drop = false, report = report)
|
|
227
|
+
}
|
|
228
|
+
if (bucket.allow(nowMs)) {
|
|
229
|
+
return RateLimitDecision(drop = false, report = report)
|
|
230
|
+
}
|
|
231
|
+
droppedCounts[level] = (droppedCounts[level] ?: 0) + 1
|
|
232
|
+
report = buildDropReportLocked(nowMs) ?: report
|
|
233
|
+
return RateLimitDecision(drop = true, report = report)
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private fun emitRateLimitReport(report: String) {
|
|
238
|
+
val l = logger
|
|
239
|
+
if (l != null) {
|
|
240
|
+
l.warn(report)
|
|
241
|
+
} else {
|
|
242
|
+
android.util.Log.w("OneKeyLog", report)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
157
246
|
private fun log(tag: String, level: String, message: String, androidLogLevel: Int) {
|
|
247
|
+
val decision = evaluateRateLimit(level)
|
|
248
|
+
decision.report?.let { emitRateLimitReport(it) }
|
|
249
|
+
if (decision.drop) return
|
|
158
250
|
val formatted = formatMessage(tag, level, message)
|
|
159
251
|
val l = logger
|
|
160
252
|
if (l != null) {
|
package/ios/NativeLogger.swift
CHANGED
|
@@ -22,24 +22,6 @@ class NativeLogger: HybridNativeLoggerSpec {
|
|
|
22
22
|
return patterns.compactMap { try? NSRegularExpression(pattern: $0) }
|
|
23
23
|
}()
|
|
24
24
|
|
|
25
|
-
/// Rate limiting: max messages per second
|
|
26
|
-
private static let maxMessagesPerSecond = 100
|
|
27
|
-
private static var messageCount = 0
|
|
28
|
-
private static var windowStart = Date()
|
|
29
|
-
private static let rateLimitLock = NSLock()
|
|
30
|
-
|
|
31
|
-
private static func isRateLimited() -> Bool {
|
|
32
|
-
rateLimitLock.lock()
|
|
33
|
-
defer { rateLimitLock.unlock() }
|
|
34
|
-
let now = Date()
|
|
35
|
-
if now.timeIntervalSince(windowStart) >= 1.0 {
|
|
36
|
-
windowStart = now
|
|
37
|
-
messageCount = 0
|
|
38
|
-
}
|
|
39
|
-
messageCount += 1
|
|
40
|
-
return messageCount > maxMessagesPerSecond
|
|
41
|
-
}
|
|
42
|
-
|
|
43
25
|
private static func sanitize(_ message: String) -> String {
|
|
44
26
|
var result = message
|
|
45
27
|
for regex in sensitivePatterns {
|
|
@@ -55,8 +37,24 @@ class NativeLogger: HybridNativeLoggerSpec {
|
|
|
55
37
|
return result
|
|
56
38
|
}
|
|
57
39
|
|
|
40
|
+
private static func truncateFile(atPath path: String) throws {
|
|
41
|
+
guard FileManager.default.fileExists(atPath: path) else { return }
|
|
42
|
+
let handle = try FileHandle(forWritingTo: URL(fileURLWithPath: path))
|
|
43
|
+
defer {
|
|
44
|
+
if #available(iOS 13.0, *) {
|
|
45
|
+
try? handle.close()
|
|
46
|
+
} else {
|
|
47
|
+
handle.closeFile()
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if #available(iOS 13.0, *) {
|
|
51
|
+
try handle.truncate(atOffset: 0)
|
|
52
|
+
} else {
|
|
53
|
+
handle.truncateFile(atOffset: 0)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
58
57
|
func write(level: Double, msg: String) {
|
|
59
|
-
if NativeLogger.isRateLimited() { return }
|
|
60
58
|
let sanitized = NativeLogger.sanitize(msg)
|
|
61
59
|
switch Int(level) {
|
|
62
60
|
case 0: OneKeyLog.debug("JS", sanitized)
|
|
@@ -93,6 +91,7 @@ class NativeLogger: HybridNativeLoggerSpec {
|
|
|
93
91
|
|
|
94
92
|
func deleteLogFiles() throws -> Promise<Void> {
|
|
95
93
|
return Promise.async {
|
|
94
|
+
DDLog.flushLog()
|
|
96
95
|
let dir = OneKeyLog.logsDirectory
|
|
97
96
|
let fm = FileManager.default
|
|
98
97
|
let files: [String]
|
|
@@ -102,10 +101,14 @@ class NativeLogger: HybridNativeLoggerSpec {
|
|
|
102
101
|
OneKeyLog.warn("NativeLogger", "Failed to list log directory for deletion")
|
|
103
102
|
return
|
|
104
103
|
}
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
for file in files where file.hasSuffix(".log") {
|
|
105
|
+
let path = "\(dir)/\(file)"
|
|
107
106
|
do {
|
|
108
|
-
|
|
107
|
+
if file == "app-latest.log" {
|
|
108
|
+
try NativeLogger.truncateFile(atPath: path)
|
|
109
|
+
} else {
|
|
110
|
+
try fm.removeItem(atPath: path)
|
|
111
|
+
}
|
|
109
112
|
} catch {
|
|
110
113
|
OneKeyLog.warn("NativeLogger", "Failed to delete log file")
|
|
111
114
|
}
|
package/ios/OneKeyLog.swift
CHANGED
|
@@ -6,6 +6,7 @@ private class OneKeyLogFileManager: DDLogFileManagerDefault {
|
|
|
6
6
|
private static let logPrefix = "app"
|
|
7
7
|
private static let latestFileName = "\(logPrefix)-latest.log"
|
|
8
8
|
private static let dateFormatterLock = NSLock()
|
|
9
|
+
private static let archiveLock = NSLock()
|
|
9
10
|
private static let _dateFormatter: DateFormatter = {
|
|
10
11
|
let fmt = DateFormatter()
|
|
11
12
|
fmt.dateFormat = "yyyy-MM-dd"
|
|
@@ -30,8 +31,11 @@ private class OneKeyLogFileManager: DDLogFileManagerDefault {
|
|
|
30
31
|
|
|
31
32
|
/// When rolled, rename app-latest.log → app-{yyyy-MM-dd}.{i}.log (matches Android pattern)
|
|
32
33
|
override func didArchiveLogFile(atPath logFilePath: String, wasRolled: Bool) {
|
|
34
|
+
Self.archiveLock.lock()
|
|
35
|
+
defer { Self.archiveLock.unlock() }
|
|
36
|
+
|
|
33
37
|
guard wasRolled else {
|
|
34
|
-
|
|
38
|
+
runCleanup()
|
|
35
39
|
return
|
|
36
40
|
}
|
|
37
41
|
|
|
@@ -53,16 +57,37 @@ private class OneKeyLogFileManager: DDLogFileManagerDefault {
|
|
|
53
57
|
try fm.moveItem(atPath: logFilePath, toPath: archivedPath)
|
|
54
58
|
moved = true
|
|
55
59
|
} catch {
|
|
56
|
-
// Another
|
|
57
|
-
|
|
60
|
+
// Another callback may have already moved the source file.
|
|
61
|
+
if !fm.fileExists(atPath: logFilePath) {
|
|
62
|
+
break
|
|
63
|
+
}
|
|
64
|
+
let nsError = error as NSError
|
|
65
|
+
// Retry only for recoverable "target exists" collisions.
|
|
66
|
+
if nsError.domain == NSCocoaErrorDomain &&
|
|
67
|
+
nsError.code == NSFileWriteFileExistsError {
|
|
68
|
+
index += 1
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
71
|
+
NSLog(
|
|
72
|
+
"[OneKeyLog] Failed to archive log file move (%@:%ld): %@",
|
|
73
|
+
nsError.domain,
|
|
74
|
+
nsError.code,
|
|
75
|
+
nsError.localizedDescription
|
|
76
|
+
)
|
|
77
|
+
break
|
|
58
78
|
}
|
|
59
79
|
}
|
|
60
80
|
if !moved {
|
|
61
81
|
NSLog("[OneKeyLog] Failed to archive log file after 1000 attempts: %@", logFilePath)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
82
|
+
}
|
|
83
|
+
runCleanup()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private func runCleanup() {
|
|
87
|
+
do {
|
|
88
|
+
try cleanupLogFiles()
|
|
89
|
+
} catch {
|
|
90
|
+
NSLog("[OneKeyLog] Failed to cleanup log files: %@", (error as NSError).localizedDescription)
|
|
66
91
|
}
|
|
67
92
|
}
|
|
68
93
|
}
|
|
@@ -71,6 +96,56 @@ private class OneKeyLogFileManager: DDLogFileManagerDefault {
|
|
|
71
96
|
|
|
72
97
|
private static let maxMessageLength = 4096
|
|
73
98
|
|
|
99
|
+
private struct TokenBucket {
|
|
100
|
+
let ratePerSecond: Double
|
|
101
|
+
let burstCapacity: Double
|
|
102
|
+
var tokens: Double
|
|
103
|
+
var lastRefillAt: TimeInterval
|
|
104
|
+
|
|
105
|
+
mutating func allow(at now: TimeInterval) -> Bool {
|
|
106
|
+
let elapsed = max(0, now - lastRefillAt)
|
|
107
|
+
if elapsed > 0 {
|
|
108
|
+
tokens = min(burstCapacity, tokens + elapsed * ratePerSecond)
|
|
109
|
+
lastRefillAt = now
|
|
110
|
+
}
|
|
111
|
+
guard tokens >= 1 else { return false }
|
|
112
|
+
tokens -= 1
|
|
113
|
+
return true
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private static let debugInfoRatePerSecond = 400.0
|
|
118
|
+
private static let debugInfoBurst = 2000.0
|
|
119
|
+
private static let warnRatePerSecond = 1000.0
|
|
120
|
+
private static let warnBurst = 2000.0
|
|
121
|
+
|
|
122
|
+
private static var rateLimitBuckets: [String: TokenBucket] = {
|
|
123
|
+
let now = Date().timeIntervalSinceReferenceDate
|
|
124
|
+
return [
|
|
125
|
+
"DEBUG": TokenBucket(
|
|
126
|
+
ratePerSecond: debugInfoRatePerSecond,
|
|
127
|
+
burstCapacity: debugInfoBurst,
|
|
128
|
+
tokens: debugInfoBurst,
|
|
129
|
+
lastRefillAt: now
|
|
130
|
+
),
|
|
131
|
+
"INFO": TokenBucket(
|
|
132
|
+
ratePerSecond: debugInfoRatePerSecond,
|
|
133
|
+
burstCapacity: debugInfoBurst,
|
|
134
|
+
tokens: debugInfoBurst,
|
|
135
|
+
lastRefillAt: now
|
|
136
|
+
),
|
|
137
|
+
"WARN": TokenBucket(
|
|
138
|
+
ratePerSecond: warnRatePerSecond,
|
|
139
|
+
burstCapacity: warnBurst,
|
|
140
|
+
tokens: warnBurst,
|
|
141
|
+
lastRefillAt: now
|
|
142
|
+
),
|
|
143
|
+
]
|
|
144
|
+
}()
|
|
145
|
+
private static var droppedCounts: [String: Int] = [:]
|
|
146
|
+
private static var lastDropReportAt = Date().timeIntervalSinceReferenceDate
|
|
147
|
+
private static let rateLimitLock = NSLock()
|
|
148
|
+
|
|
74
149
|
private static let configured: Bool = {
|
|
75
150
|
let logsDir = logsDirectory
|
|
76
151
|
|
|
@@ -115,6 +190,63 @@ private class OneKeyLogFileManager: DDLogFileManagerDefault {
|
|
|
115
190
|
return _timeFormatter.string(from: date)
|
|
116
191
|
}
|
|
117
192
|
|
|
193
|
+
private static func rateLimitReportLocked(now: TimeInterval) -> String? {
|
|
194
|
+
guard now - lastDropReportAt >= 1.0 else { return nil }
|
|
195
|
+
guard !droppedCounts.isEmpty else {
|
|
196
|
+
lastDropReportAt = now
|
|
197
|
+
return nil
|
|
198
|
+
}
|
|
199
|
+
let ordered = ["DEBUG", "INFO", "WARN"]
|
|
200
|
+
let parts = ordered.compactMap { level -> String? in
|
|
201
|
+
guard let count = droppedCounts[level], count > 0 else { return nil }
|
|
202
|
+
return "\(level)=\(count)"
|
|
203
|
+
}
|
|
204
|
+
droppedCounts.removeAll()
|
|
205
|
+
lastDropReportAt = now
|
|
206
|
+
guard !parts.isEmpty else { return nil }
|
|
207
|
+
return "[OneKeyLog] Rate-limited logs (last 1s): \(parts.joined(separator: ", "))"
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private static func evaluateRateLimit(for level: String) -> (drop: Bool, report: String?) {
|
|
211
|
+
rateLimitLock.lock()
|
|
212
|
+
defer { rateLimitLock.unlock() }
|
|
213
|
+
|
|
214
|
+
let now = Date().timeIntervalSinceReferenceDate
|
|
215
|
+
var report = rateLimitReportLocked(now: now)
|
|
216
|
+
|
|
217
|
+
// Never limit error logs.
|
|
218
|
+
if level == "ERROR" {
|
|
219
|
+
return (false, report)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
guard var bucket = rateLimitBuckets[level] else {
|
|
223
|
+
return (false, report)
|
|
224
|
+
}
|
|
225
|
+
let allowed = bucket.allow(at: now)
|
|
226
|
+
rateLimitBuckets[level] = bucket
|
|
227
|
+
if allowed {
|
|
228
|
+
return (false, report)
|
|
229
|
+
}
|
|
230
|
+
droppedCounts[level, default: 0] += 1
|
|
231
|
+
report = rateLimitReportLocked(now: now) ?? report
|
|
232
|
+
return (true, report)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private static func log(
|
|
236
|
+
_ level: String,
|
|
237
|
+
_ tag: String,
|
|
238
|
+
_ message: String,
|
|
239
|
+
writer: (String) -> Void
|
|
240
|
+
) {
|
|
241
|
+
_ = configured
|
|
242
|
+
let decision = evaluateRateLimit(for: level)
|
|
243
|
+
if let report = decision.report {
|
|
244
|
+
DDLogWarn(report)
|
|
245
|
+
}
|
|
246
|
+
if decision.drop { return }
|
|
247
|
+
writer(formatMessage(tag, level, message))
|
|
248
|
+
}
|
|
249
|
+
|
|
118
250
|
private static func truncate(_ message: String) -> String {
|
|
119
251
|
if message.count > maxMessageLength {
|
|
120
252
|
return String(message.prefix(maxMessageLength)) + "...(truncated)"
|
|
@@ -163,23 +295,19 @@ private class OneKeyLogFileManager: DDLogFileManagerDefault {
|
|
|
163
295
|
}
|
|
164
296
|
|
|
165
297
|
@objc public static func debug(_ tag: String, _ message: String) {
|
|
166
|
-
|
|
167
|
-
DDLogDebug(formatMessage(tag, "DEBUG", message))
|
|
298
|
+
log("DEBUG", tag, message) { DDLogDebug($0) }
|
|
168
299
|
}
|
|
169
300
|
|
|
170
301
|
@objc public static func info(_ tag: String, _ message: String) {
|
|
171
|
-
|
|
172
|
-
DDLogInfo(formatMessage(tag, "INFO", message))
|
|
302
|
+
log("INFO", tag, message) { DDLogInfo($0) }
|
|
173
303
|
}
|
|
174
304
|
|
|
175
305
|
@objc public static func warn(_ tag: String, _ message: String) {
|
|
176
|
-
|
|
177
|
-
DDLogWarn(formatMessage(tag, "WARN", message))
|
|
306
|
+
log("WARN", tag, message) { DDLogWarn($0) }
|
|
178
307
|
}
|
|
179
308
|
|
|
180
309
|
@objc public static func error(_ tag: String, _ message: String) {
|
|
181
|
-
|
|
182
|
-
DDLogError(formatMessage(tag, "ERROR", message))
|
|
310
|
+
log("ERROR", tag, message) { DDLogError($0) }
|
|
183
311
|
}
|
|
184
312
|
|
|
185
313
|
/// Returns the logs directory path (for getLogFilePaths / deleteLogFiles)
|