Files
hgmj_android/analytics_sdk/lib/utils/logger.dart
T
2026-10-08 11:37:25 +07:00

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);
}
}