219 lines
6.7 KiB
Dart
219 lines
6.7 KiB
Dart
import 'dart:developer' as developer;
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
/// 日志级别枚举
|
|
enum LogLevel {
|
|
debug,
|
|
info,
|
|
warn,
|
|
error,
|
|
}
|
|
|
|
/// 日志工具类:统一管理 SDK 中的所有日志输出
|
|
class Logger {
|
|
Logger._();
|
|
|
|
/// 是否启用日志(默认:仅在 debug 模式下启用)
|
|
static bool enabled = false;
|
|
|
|
/// 外部日志回调(可选)。
|
|
/// 注册后,所有 SDK 日志在控制台输出的同时也会转发给此回调。
|
|
/// 示例:在 example app 中将 SDK 内部日志显示到 UI 面板。
|
|
static void Function(String message, LogLevel level)? onLog;
|
|
|
|
/// 测试专用:替换 dart:developer.log,便于验证长日志走 developer log。
|
|
@visibleForTesting
|
|
static void Function(String message, {String name})? developerLogWriterForTest;
|
|
|
|
/// 测试专用:替换 debugPrint,便于验证长日志分片输出到控制台/logcat。
|
|
@visibleForTesting
|
|
static void Function(String message)? consoleLogWriterForTest;
|
|
|
|
/// Android logcat 单行有长度限制,保守按字符分片,避免超长 JSON 被截断。
|
|
static const int _consoleChunkSize = 800;
|
|
|
|
/// 日志标签映射
|
|
static const Map<String, String> _tags = {
|
|
'AnalyticsSdk': '[AnalyticsSdk]',
|
|
'DomainManager': '[DomainManager]',
|
|
'EventTypeConfigManager': '[EventTypeConfigManager]',
|
|
'GlobalClick': '[GlobalClick]',
|
|
'AdImpressionManager': '[AdImpressionManager]',
|
|
'PageLifecycleObserver': '[PageLifecycleObserver]',
|
|
'InitConfigResult': '[InitConfigResult]',
|
|
};
|
|
|
|
/// 获取日志标签
|
|
static String _getTag(String tag) {
|
|
return _tags[tag] ?? '[$tag]';
|
|
}
|
|
|
|
/// 格式化日志消息
|
|
static String _formatMessage(String tag, String message) {
|
|
return '${_getTag(tag)} $message';
|
|
}
|
|
|
|
/// 输出到 Flutter 控制台;Android 上会进入 logcat 的 flutter 日志流。
|
|
static void _writeConsole(String message) {
|
|
final writer = consoleLogWriterForTest;
|
|
if (writer != null) {
|
|
writer(message);
|
|
} else {
|
|
debugPrint(message);
|
|
}
|
|
}
|
|
|
|
/// 分片输出超长日志,避免 logcat / IDE 控制台按单行截断。
|
|
static void _writeConsoleMessage(String tag, String message) {
|
|
if (message.length <= _consoleChunkSize) {
|
|
_writeConsole(_formatMessage(tag, message));
|
|
return;
|
|
}
|
|
|
|
final tagPrefix = _getTag(tag);
|
|
final total = (message.length + _consoleChunkSize - 1) ~/ _consoleChunkSize;
|
|
for (var index = 0; index < total; index++) {
|
|
final start = index * _consoleChunkSize;
|
|
final end = (start + _consoleChunkSize < message.length) ? start + _consoleChunkSize : message.length;
|
|
_writeConsole(
|
|
'$tagPrefix part ${index + 1}/$total: ${message.substring(start, end)}',
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 输出调试日志
|
|
static void debug(String tag, String message) {
|
|
if (enabled) {
|
|
final msg = _formatMessage(tag, message);
|
|
_writeConsoleMessage(tag, message);
|
|
try {
|
|
onLog?.call(msg, LogLevel.debug);
|
|
} catch (_) {}
|
|
}
|
|
}
|
|
|
|
/// 输出信息日志
|
|
static void info(String tag, String message) {
|
|
if (enabled) {
|
|
final msg = _formatMessage(tag, message);
|
|
_writeConsoleMessage(tag, message);
|
|
try {
|
|
onLog?.call(msg, LogLevel.info);
|
|
} catch (_) {}
|
|
}
|
|
}
|
|
|
|
/// 输出警告日志
|
|
static void warn(String tag, String message) {
|
|
if (enabled) {
|
|
final formattedMessage = '⚠️ $message';
|
|
final msg = _formatMessage(tag, formattedMessage);
|
|
_writeConsoleMessage(tag, formattedMessage);
|
|
try {
|
|
onLog?.call(msg, LogLevel.warn);
|
|
} catch (_) {}
|
|
}
|
|
}
|
|
|
|
/// 输出错误日志
|
|
static void error(String tag, String message, [Object? error, StackTrace? stackTrace]) {
|
|
if (enabled) {
|
|
final errorInfo = error != null ? ', 错误: $error' : '';
|
|
final stackInfo = stackTrace != null ? '\n堆栈: $stackTrace' : '';
|
|
final formattedMessage = '❌ $message$errorInfo$stackInfo';
|
|
final msg = _formatMessage(tag, formattedMessage);
|
|
_writeConsoleMessage(tag, formattedMessage);
|
|
try {
|
|
onLog?.call(msg, LogLevel.error);
|
|
} catch (_) {}
|
|
}
|
|
}
|
|
|
|
/// 输出日志(自动判断级别)
|
|
static void log(String tag, String message, {LogLevel level = LogLevel.debug}) {
|
|
switch (level) {
|
|
case LogLevel.debug:
|
|
debug(tag, message);
|
|
break;
|
|
case LogLevel.info:
|
|
info(tag, message);
|
|
break;
|
|
case LogLevel.warn:
|
|
warn(tag, message);
|
|
break;
|
|
case LogLevel.error:
|
|
error(tag, message);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// 输出 developer log。
|
|
///
|
|
/// 长 JSON 等需要完整复制的日志使用此入口。
|
|
///
|
|
/// developer.log 保留完整单条内容给 DevTools;控制台/logcat 使用分片,避免单行截断。
|
|
static void developerLog(
|
|
String tag,
|
|
String message, {
|
|
LogLevel level = LogLevel.debug,
|
|
}) {
|
|
if (enabled) {
|
|
final msg = _formatMessage(tag, message);
|
|
final writer = developerLogWriterForTest;
|
|
if (writer != null) {
|
|
writer(msg, name: tag);
|
|
} else {
|
|
developer.log(msg, name: tag);
|
|
}
|
|
_writeConsoleMessage(tag, message);
|
|
try {
|
|
onLog?.call(msg, level);
|
|
} catch (_) {}
|
|
}
|
|
}
|
|
|
|
/// 便捷方法:AnalyticsSdk 日志
|
|
static void analyticsSdk(String message, {LogLevel level = LogLevel.debug}) {
|
|
log('AnalyticsSdk', message, level: level);
|
|
}
|
|
|
|
/// 便捷方法:AnalyticsSdk developer log
|
|
static void analyticsSdkDeveloperLog(
|
|
String message, {
|
|
LogLevel level = LogLevel.debug,
|
|
}) {
|
|
developerLog('AnalyticsSdk', message, level: level);
|
|
}
|
|
|
|
/// 便捷方法:DomainManager 日志
|
|
static void domainManager(String message, {LogLevel level = LogLevel.debug}) {
|
|
log('DomainManager', message, level: level);
|
|
}
|
|
|
|
/// 便捷方法:EventTypeConfigManager 日志
|
|
static void eventTypeConfigManager(String message, {LogLevel level = LogLevel.debug}) {
|
|
log('EventTypeConfigManager', message, level: level);
|
|
}
|
|
|
|
/// 便捷方法:GlobalClick 日志
|
|
static void globalClick(String message, {LogLevel level = LogLevel.debug}) {
|
|
log('GlobalClick', message, level: level);
|
|
}
|
|
|
|
/// 便捷方法:AdImpressionManager 日志
|
|
static void adImpressionManager(String message, {LogLevel level = LogLevel.debug}) {
|
|
log('AdImpressionManager', message, level: level);
|
|
}
|
|
|
|
/// 便捷方法:PageLifecycleObserver 日志
|
|
static void pageLifecycleObserver(String message, {LogLevel level = LogLevel.debug}) {
|
|
log('PageLifecycleObserver', message, level: level);
|
|
}
|
|
|
|
/// 便捷方法:InitConfigResult 日志
|
|
static void initConfigResult(String message, {LogLevel level = LogLevel.debug}) {
|
|
log('InitConfigResult', message, level: level);
|
|
}
|
|
}
|