@onekeyfe/react-native-native-logger 1.1.46 → 1.1.47

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.
@@ -36,6 +36,10 @@ class NativeLogger : HybridNativeLoggerSpec() {
36
36
  }
37
37
  }
38
38
 
39
+ override fun flushPendingRepeat() {
40
+ OneKeyLog.flushPendingRepeat()
41
+ }
42
+
39
43
  override fun write(level: Double, msg: String) {
40
44
  val sanitized = sanitize(msg)
41
45
  when (level.toInt()) {
@@ -243,7 +243,32 @@ object OneKeyLog {
243
243
  }
244
244
  }
245
245
 
246
+ // -----------------------------------------------------------------------
247
+ // Dedup: collapse identical consecutive messages into [N repeat]
248
+ // -----------------------------------------------------------------------
249
+ private val dedupLock = Any()
250
+ @Volatile private var prevLogMessage: String? = null
251
+ private var repeatCount: Int = 0
252
+
246
253
  private fun log(tag: String, level: String, message: String, androidLogLevel: Int) {
254
+ // Dedup identical consecutive messages
255
+ synchronized(dedupLock) {
256
+ if (message == prevLogMessage) {
257
+ repeatCount += 1
258
+ return
259
+ }
260
+ val pendingRepeat = repeatCount
261
+ prevLogMessage = message
262
+ repeatCount = 0
263
+
264
+ if (pendingRepeat > 0) {
265
+ val repeatMsg = "[$pendingRepeat repeat]"
266
+ val l = logger
267
+ if (l != null) l.info(repeatMsg)
268
+ else android.util.Log.i("OneKeyLog", repeatMsg)
269
+ }
270
+ }
271
+
247
272
  val decision = evaluateRateLimit(level)
248
273
  decision.report?.let { emitRateLimitReport(it) }
249
274
  if (decision.drop) return
@@ -283,6 +308,26 @@ object OneKeyLog {
283
308
  }
284
309
  }
285
310
 
311
+ /**
312
+ * Flush any pending dedup repeat summary to the log file.
313
+ * Call before log export to ensure trailing repeated messages are included.
314
+ */
315
+ @JvmStatic
316
+ fun flushPendingRepeat() {
317
+ synchronized(dedupLock) {
318
+ val pending = repeatCount
319
+ repeatCount = 0
320
+ prevLogMessage = null
321
+
322
+ if (pending > 0) {
323
+ val repeatMsg = "[$pending repeat]"
324
+ val l = logger
325
+ if (l != null) l.info(repeatMsg)
326
+ else android.util.Log.i("OneKeyLog", repeatMsg)
327
+ }
328
+ }
329
+ }
330
+
286
331
  @JvmStatic
287
332
  fun debug(tag: String, message: String) { log(tag, "DEBUG", message, android.util.Log.DEBUG) }
288
333
 
@@ -54,6 +54,10 @@ class NativeLogger: HybridNativeLoggerSpec {
54
54
  }
55
55
  }
56
56
 
57
+ func flushPendingRepeat() {
58
+ OneKeyLog.flushPendingRepeat()
59
+ }
60
+
57
61
  func write(level: Double, msg: String) {
58
62
  let sanitized = NativeLogger.sanitize(msg)
59
63
  switch Int(level) {
@@ -232,6 +232,13 @@ private class OneKeyLogFileManager: DDLogFileManagerDefault {
232
232
  return (true, report)
233
233
  }
234
234
 
235
+ // -----------------------------------------------------------------------
236
+ // Dedup: collapse identical consecutive messages into [N repeat]
237
+ // -----------------------------------------------------------------------
238
+ private static let dedupLock = NSLock()
239
+ private static var prevLogMessage: String?
240
+ private static var repeatCount: Int = 0
241
+
235
242
  private static func log(
236
243
  _ level: String,
237
244
  _ tag: String,
@@ -239,6 +246,24 @@ private class OneKeyLogFileManager: DDLogFileManagerDefault {
239
246
  writer: (String) -> Void
240
247
  ) {
241
248
  _ = configured
249
+
250
+ // Dedup identical consecutive messages
251
+ dedupLock.lock()
252
+ let isDuplicate = (message == prevLogMessage)
253
+ if isDuplicate {
254
+ repeatCount += 1
255
+ dedupLock.unlock()
256
+ return
257
+ }
258
+ let pendingRepeat = repeatCount
259
+ prevLogMessage = message
260
+ repeatCount = 0
261
+ dedupLock.unlock()
262
+
263
+ if pendingRepeat > 0 {
264
+ DDLogInfo("[\(pendingRepeat) repeat]")
265
+ }
266
+
242
267
  let decision = evaluateRateLimit(for: level)
243
268
  if let report = decision.report {
244
269
  DDLogWarn(report)
@@ -294,6 +319,20 @@ private class OneKeyLogFileManager: DDLogFileManagerDefault {
294
319
  return truncate("\(time) | \(level) : [\(safeTag)] \(safeMessage)")
295
320
  }
296
321
 
322
+ /// Flush any pending dedup repeat summary to the log file.
323
+ /// Call before log export to ensure trailing repeated messages are included.
324
+ @objc public static func flushPendingRepeat() {
325
+ dedupLock.lock()
326
+ let pending = repeatCount
327
+ repeatCount = 0
328
+ prevLogMessage = nil
329
+ dedupLock.unlock()
330
+
331
+ if pending > 0 {
332
+ DDLogInfo("[\(pending) repeat]")
333
+ }
334
+ }
335
+
297
336
  @objc public static func debug(_ tag: String, _ message: String) {
298
337
  log("DEBUG", tag, message) { DDLogDebug($0) }
299
338
  }
@@ -4,6 +4,8 @@ export interface NativeLogger extends HybridObject<{
4
4
  android: 'kotlin';
5
5
  }> {
6
6
  write(level: number, msg: string): void;
7
+ /** Flush any pending dedup repeat summary to the log file. Call before log export. */
8
+ flushPendingRepeat(): void;
7
9
  getLogDirectory(): string;
8
10
  getLogFilePaths(): Promise<string[]>;
9
11
  deleteLogFiles(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"NativeLogger.nitro.d.ts","sourceRoot":"","sources":["../../../src/NativeLogger.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,MAAM,WAAW,YACf,SAAQ,YAAY,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;IACzD,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,eAAe,IAAI,MAAM,CAAC;IAC1B,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACrC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC"}
1
+ {"version":3,"file":"NativeLogger.nitro.d.ts","sourceRoot":"","sources":["../../../src/NativeLogger.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,MAAM,WAAW,YACf,SAAQ,YAAY,CAAC;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;IACzD,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,sFAAsF;IACtF,kBAAkB,IAAI,IAAI,CAAC;IAC3B,eAAe,IAAI,MAAM,CAAC;IAC1B,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACrC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC"}
@@ -50,6 +50,10 @@ namespace margelo::nitro::nativelogger {
50
50
  static const auto method = javaClassStatic()->getMethod<void(double /* level */, jni::alias_ref<jni::JString> /* msg */)>("write");
51
51
  method(_javaPart, level, jni::make_jstring(msg));
52
52
  }
53
+ void JHybridNativeLoggerSpec::flushPendingRepeat() {
54
+ static const auto method = javaClassStatic()->getMethod<void()>("flushPendingRepeat");
55
+ method(_javaPart);
56
+ }
53
57
  std::string JHybridNativeLoggerSpec::getLogDirectory() {
54
58
  static const auto method = javaClassStatic()->getMethod<jni::local_ref<jni::JString>()>("getLogDirectory");
55
59
  auto __result = method(_javaPart);
@@ -55,6 +55,7 @@ namespace margelo::nitro::nativelogger {
55
55
  public:
56
56
  // Methods
57
57
  void write(double level, const std::string& msg) override;
58
+ void flushPendingRepeat() override;
58
59
  std::string getLogDirectory() override;
59
60
  std::shared_ptr<Promise<std::vector<std::string>>> getLogFilePaths() override;
60
61
  std::shared_ptr<Promise<void>> deleteLogFiles() override;
@@ -50,6 +50,10 @@ abstract class HybridNativeLoggerSpec: HybridObject() {
50
50
  @Keep
51
51
  abstract fun write(level: Double, msg: String): Unit
52
52
 
53
+ @DoNotStrip
54
+ @Keep
55
+ abstract fun flushPendingRepeat(): Unit
56
+
53
57
  @DoNotStrip
54
58
  @Keep
55
59
  abstract fun getLogDirectory(): String
@@ -68,6 +68,12 @@ namespace margelo::nitro::nativelogger {
68
68
  std::rethrow_exception(__result.error());
69
69
  }
70
70
  }
71
+ inline void flushPendingRepeat() override {
72
+ auto __result = _swiftPart.flushPendingRepeat();
73
+ if (__result.hasError()) [[unlikely]] {
74
+ std::rethrow_exception(__result.error());
75
+ }
76
+ }
71
77
  inline std::string getLogDirectory() override {
72
78
  auto __result = _swiftPart.getLogDirectory();
73
79
  if (__result.hasError()) [[unlikely]] {
@@ -15,6 +15,7 @@ public protocol HybridNativeLoggerSpec_protocol: HybridObject {
15
15
 
16
16
  // Methods
17
17
  func write(level: Double, msg: String) throws -> Void
18
+ func flushPendingRepeat() throws -> Void
18
19
  func getLogDirectory() throws -> String
19
20
  func getLogFilePaths() throws -> Promise<[String]>
20
21
  func deleteLogFiles() throws -> Promise<Void>
@@ -128,6 +128,17 @@ open class HybridNativeLoggerSpec_cxx {
128
128
  }
129
129
  }
130
130
 
131
+ @inline(__always)
132
+ public final func flushPendingRepeat() -> bridge.Result_void_ {
133
+ do {
134
+ try self.__implementation.flushPendingRepeat()
135
+ return bridge.create_Result_void_()
136
+ } catch (let __error) {
137
+ let __exceptionPtr = __error.toCpp()
138
+ return bridge.create_Result_void_(__exceptionPtr)
139
+ }
140
+ }
141
+
131
142
  @inline(__always)
132
143
  public final func getLogDirectory() -> bridge.Result_std__string_ {
133
144
  do {
@@ -15,6 +15,7 @@ namespace margelo::nitro::nativelogger {
15
15
  // load custom methods/properties
16
16
  registerHybrids(this, [](Prototype& prototype) {
17
17
  prototype.registerHybridMethod("write", &HybridNativeLoggerSpec::write);
18
+ prototype.registerHybridMethod("flushPendingRepeat", &HybridNativeLoggerSpec::flushPendingRepeat);
18
19
  prototype.registerHybridMethod("getLogDirectory", &HybridNativeLoggerSpec::getLogDirectory);
19
20
  prototype.registerHybridMethod("getLogFilePaths", &HybridNativeLoggerSpec::getLogFilePaths);
20
21
  prototype.registerHybridMethod("deleteLogFiles", &HybridNativeLoggerSpec::deleteLogFiles);
@@ -51,6 +51,7 @@ namespace margelo::nitro::nativelogger {
51
51
  public:
52
52
  // Methods
53
53
  virtual void write(double level, const std::string& msg) = 0;
54
+ virtual void flushPendingRepeat() = 0;
54
55
  virtual std::string getLogDirectory() = 0;
55
56
  virtual std::shared_ptr<Promise<std::vector<std::string>>> getLogFilePaths() = 0;
56
57
  virtual std::shared_ptr<Promise<void>> deleteLogFiles() = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-native-logger",
3
- "version": "1.1.46",
3
+ "version": "1.1.47",
4
4
  "description": "react-native-native-logger",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -80,7 +80,7 @@
80
80
  "nitrogen": "0.31.10",
81
81
  "prettier": "^2.8.8",
82
82
  "react": "19.2.0",
83
- "react-native": "0.83.0",
83
+ "react-native": "patch:react-native@npm%3A0.83.0#~/.yarn/patches/react-native-npm-0.83.0-577d0f2d83.patch",
84
84
  "react-native-builder-bob": "^0.40.13",
85
85
  "react-native-nitro-modules": "0.33.2",
86
86
  "release-it": "^19.0.4",
@@ -3,6 +3,8 @@ import type { HybridObject } from 'react-native-nitro-modules';
3
3
  export interface NativeLogger
4
4
  extends HybridObject<{ ios: 'swift'; android: 'kotlin' }> {
5
5
  write(level: number, msg: string): void;
6
+ /** Flush any pending dedup repeat summary to the log file. Call before log export. */
7
+ flushPendingRepeat(): void;
6
8
  getLogDirectory(): string;
7
9
  getLogFilePaths(): Promise<string[]>;
8
10
  deleteLogFiles(): Promise<void>;