mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 14:25:20 +00:00
Debugging the integration build on real iOS 26.5 devices over the air. - BitLogger DEBUG default minimumLevel now .debug (was .info) so a tap-launched sideload surfaces .debug decision logs without the BITCHAT_LOG_LEVEL env var; env still wins; release unchanged (.info, emits nothing). Extracted defaultMinimumLevel + a test asserting it. - Greppable bracket decision tags at .info (visible even at .info) via SecureLogger, ID-prefixes only, sanitized: [ROUTE] source-route vs flood origination (+reason) + fragment targeted-resync; [GW] uplink accept/reject, downlink rebroadcast/drop, loop skips, drain-timer; [WIFI] offer/accept/decline, AWDL connect, transfer start/complete+bytes, fallback+reason; [PREKEY] seal choice, consume, unknown-prekey open fail, bundle ingest, re-gossip; [SYNC] one concise summary per cycle + per-request served counts (no per-packet spam); [PING]/[TRACE] RTT + computed path. - New OSLog categories: mesh, gateway, transport. - Refactored BLESourceRouteOriginationPolicy.route -> decide returning a Decision enum (flood(reason)/route(hops)) so the flood reason is greppable and unit-tested. - DEBUG-only in-memory ring buffer (LogExportBuffer, ~2000 lines/512KB, thread-safe, off main thread) + App Info "Export Logs" share sheet (iOS UIActivityViewController / macOS NSSavePanel), VoiceOver labels. - DEBUG-only UDP LAN log sink (LogNetworkSink): opt-in, off by default, fire-and-forget, never blocks/throws; each line prefixed with the device nickname for demux; configured via App Info host:port fields. Same sanitized formatted line feeds buffer, sink, and export. All new code is #if DEBUG; release emits nothing and ships no export/sink UI. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
65 lines
2.2 KiB
Swift
65 lines
2.2 KiB
Swift
//
|
|
// LogExportBuffer.swift
|
|
// BitLogger
|
|
//
|
|
// This is free and unencumbered software released into the public domain.
|
|
// For more information, see <https://unlicense.org>
|
|
//
|
|
|
|
#if DEBUG
|
|
import Foundation
|
|
|
|
/// In-memory ring buffer of the most recent sanitized log lines, so a tester
|
|
/// can export logs untethered when live streaming isn't available.
|
|
///
|
|
/// DEBUG-only: never compiled into release builds, matching the rest of the
|
|
/// logging stack. Bounded by both a line count and a byte budget (oldest
|
|
/// evicted first). Appends run on a private serial queue so a hot logging path
|
|
/// never blocks on buffer maintenance and the main thread is never touched.
|
|
///
|
|
/// It stores exactly the SecureLogger-sanitized text (fingerprints truncated,
|
|
/// base64 redacted, peer IDs shortened), so the export carries no secrets.
|
|
public final class LogExportBuffer {
|
|
public static let shared = LogExportBuffer()
|
|
|
|
private let queue = DispatchQueue(label: "chat.bitchat.securelogger.export", qos: .utility)
|
|
private var lines: [String] = []
|
|
private var byteCount = 0
|
|
|
|
private let maxLines: Int
|
|
private let maxBytes: Int
|
|
|
|
init(maxLines: Int = 2000, maxBytes: Int = 512 * 1024) {
|
|
self.maxLines = maxLines
|
|
self.maxBytes = maxBytes
|
|
}
|
|
|
|
/// Append one already-formatted, already-sanitized log line. Non-blocking
|
|
/// (async on the private queue).
|
|
func append(_ line: String) {
|
|
queue.async {
|
|
self.lines.append(line)
|
|
self.byteCount += line.utf8.count + 1 // + newline
|
|
while self.lines.count > self.maxLines || self.byteCount > self.maxBytes {
|
|
guard !self.lines.isEmpty else { break }
|
|
let removed = self.lines.removeFirst()
|
|
self.byteCount -= (removed.utf8.count + 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A newline-joined snapshot of the buffered lines, oldest first. Safe to
|
|
/// call from the main thread (brief synchronous read).
|
|
public func snapshot() -> String {
|
|
queue.sync { lines.joined(separator: "\n") }
|
|
}
|
|
|
|
public func clear() {
|
|
queue.async {
|
|
self.lines.removeAll(keepingCapacity: true)
|
|
self.byteCount = 0
|
|
}
|
|
}
|
|
}
|
|
#endif
|