日志优化概述

最近更新时间:2025-05-27 16:50:41

我的收藏

简介

本文介绍如何通过终端 COS SDK 提供的日志相关方法对 COS SDK 日志进行统一管理,帮助用户了解 COS SDK 的运行细节以及为自助排障提供支持。
COS SDK 提供的标准化日志系统,对日志进行分级分类和统一格式,支持多渠道输出、文件日志加密、灵活配置,帮助开发者更方便的管理日志,快速定位问题,提高排障效率。

日志说明

日志级别

级别
描述
适用场景
VERBOSE
最详细的调试信息,用于跟踪代码执行流程细节
开发阶段调试
DEBUG
调试信息,用于关键流程的中间状态
问题排查、流程跟踪
INFO
一般性信息,记录关键操作结果
用户行为统计、业务监控
WARN
警告信息,表示潜在问题
异常监控预警
ERROR
错误信息,表示功能失败
错误分析与修复

日志分类

分类
描述
PROCESS
操作过程日志
RESULT
操作结果日志
NETWORK
网络层日志
PROBE
网络探测日志(网络连接导致失败时会进行探测)
ERROR
错误堆栈日志

日志实体

字段
字段key
描述
类型
时间戳
timestamp
精确到毫秒
long
级别
level
日志级别
枚举
分类
category
日志分类
枚举
线程
threadName
当前线程名
字符串
标签
tag
自定义标签,用于业务模块区分(例如 Upload、Download)
字符串
消息内容
message
日志主体信息,支持格式化字符串
字符串
设备 ID
deviceID
设备 ID
字符串
机型
deviceModel
机型
字符串
APP 版本
appVersion
APP版本
字符串
拓展信息
extras
可选字段(例如设备信息、用户信息)
自带 qcloud_platform:Android、iOS 等
输出时和 deviceID、deviceModel、appVersion 合并
map<string, string>

日志输出方式

控制台

兼容各系统的控制台日志,按照各平台 log 格式组织,Android 示例格式为时间 标签 包名 [分类][线程] 消息内容 - 拓展字段map


本地文件

将日志存储到本地文件,支持自动文件分割、加密存储等,完整格式为级别/时间[线程][分类 标签][消息内容][拓展字段 map]


业务回调

通过动态注册和注销管理业务回调,回调中传入日志结构化对象,供开发者自定义处理(例如上报到客户自己的日志系统)。


CLS

将日志结构化对象上报到 cls,支持 cls 多种凭证配置。



基础配置

Android
iOS
Flutter
React Native
Web
通过 COSLogger 进行日志的配置和管理。
注意:
由于 COSLogger 的初始化依赖 CosXmlBaseService,因此需要在 CosXmlService 或 CosXmlSimpleService 首次实例化后调用 COSLogger。
// 通过 CosXmlServiceConfig 中 setDebuggable 方法可以配置控制台和文件日志的开启和关闭,设置为 true 时会开启

// 是否开启控制台日志
COSLogger.enableLogcat(true);
// 是否开启文件日志
COSLogger.enableLogFile(true);
// 定义日志监听器
CosLogListener listener = new CosLogListener() {
@Override
public void onLog(LogEntity entity) {
Log.d("CosLogListener", entity.getLogcatString());
}
};
// 添加日志监听器
COSLogger.addLogListener(listener);
// 删除日志监听器
COSLogger.removeLogListener(listener);
// 设置全局最小日志等级(渠道设置优先于全局设置)
COSLogger.setMinLevel(LogLevel.VERBOSE);
// 设置控制台最小日志等级
COSLogger.setLogcatMinLevel(LogLevel.VERBOSE);
// 设置文件最小日志等级
COSLogger.setFileMinLevel(LogLevel.VERBOSE);
// 设置cls最小日志等级(必须进行 setCLsChannel 后配置,否则不生效)
COSLogger.setClsMinLevel(LogLevel.VERBOSE);
// 设置设备ID
COSLogger.setDeviceID("DeviceID");
// 设置设备型号
COSLogger.setDeviceModel("DeviceModel");
// 设置APP版本号
COSLogger.setAppVersion("AppVersion");
// 设置拓展字段
Map<String, String> extras = new HashMap<>();
extras.put("userID", "userID");
COSLogger.setExtras(extras);
// 获取日志文件文件列表,参数为最近多少个,例如最近10个日志文件
File[] files = COSLogger.getLogFiles(10);
// 获取日志文件目录路径
String logRootDir = COSLogger.getLogRootDir();
// 添加自定义脱敏规则
COSLogger.addSensitiveRule("(q-ak=)[^&\\\\\\\\s]+", "$1***");
// 移除脱敏规则
COSLogger.removeSensitiveRule("(q-ak=)[^&\\\\\\\\s]+");
通过 QCloudLogger 进行日志的配置和管理。
// 设置控制台日志等级
[QCloudLogger sharedLogger].logLevel = QCloudLogLevelVerbose;
// 设置文件日志等级
[QCloudLogger sharedLogger].logFileLevel = QCloudLogLevelVerbose;
// 设置 cls 最小日志等级(必须进行 QCloudCLSLoggerOutput 配置,否则不生效)
[QCloudLogger sharedLogger].logClsLevel = QCloudLogLevelVerbose;
// 定义日志监听器
QCloudCustomLoggerOutput * output = [[QCloudCustomLoggerOutput alloc]init];
output.callback = ^(QCloudLogModel * _Nonnull model, NSDictionary * _Nonnull extendInfo) {

};
// 添加日志监听器
[[QCloudLogger sharedLogger] addLogger:output];
// 删除日志监听器
[[QCloudLogger sharedLogger] removeLogger:output];
// 设置设备ID
[QCloudLogger sharedLogger].deviceID = @"deviceID";
// 设置设备型号
[QCloudLogger sharedLogger].deviceModel = @"deviceModel";
// 设置APP版本号
[QCloudLogger sharedLogger].appVersion = @"appVersion";
// 设置拓展字段
[QCloudLogger sharedLogger].extendInfo = @{@"userID":@"userID"};
// 获取日志文件目录路径
NSString * logDir = [QCloudLogger sharedLogger].logDirctoryPath;
通过 Cos() 进行日志的配置和管理。
注意:
由于日志的初始化依赖 CosService,因此需要在 registerDefaultService 或 registerDefaultTransferManger 后调用日志相关功能。
// 是否开启控制台日志
await Cos().enableLogcat(true);
// 是否开启文件日志
await Cos().enableLogFile(true);
// 定义日志监听器
loglistener(log) {
print(log.message);
}
// 添加日志监听器
await Cos().addLogListener(loglistener);
// 删除日志监听器
await Cos().removeLogListener(loglistener);
// 设置全局最小日志等级(渠道设置优先于全局设置)
await Cos().setMinLevel(LogLevel.verbose);
// 设置控制台最小日志等级
await Cos().setLogcatMinLevel(LogLevel.verbose);
// 设置文件最小日志等级
await Cos().setFileMinLevel(LogLevel.verbose);
// 设置cls最小日志等级(必须进行 setCLsChannel 后配置,否则不生效)
await Cos().setClsMinLevel(LogLevel.verbose);
// 设置设备ID
await Cos().setDeviceID("DeviceID");
// 设置设备型号
await Cos().setDeviceModel("DeviceModel");
// 设置APP版本号
await Cos().setAppVersion("AppVersion");
// 设置拓展字段
await Cos().setExtras({"userId":"1"});
// 获取日志文件目录路径
String logRootDir = await Cos().getLogRootDir()
通过 Cos 进行日志的配置和管理。
注意:
由于日志的初始化依赖 CosService,因此需要在 registerDefaultService 或 registerDefaultTransferManger 后调用日志相关功能。
// 是否开启控制台日志
await Cos.enableLogcat(true);
// 是否开启文件日志
await Cos.enableLogFile(true);
// 添加日志监听器
await Cos.addLogListener("cos", (log) => {
console.log(log);
})
// 删除日志监听器
await Cos.removeLogListener("cos");
// 设置全局最小日志等级(渠道设置优先于全局设置)
await Cos.setMinLevel(LogLevel.verbose);
// 设置控制台最小日志等级
await Cos.setLogcatMinLevel(LogLevel.verbose);
// 设置文件最小日志等级
await Cos.setFileMinLevel(LogLevel.verbose);
// 设置cls最小日志等级(必须进行 setCLsChannel 后配置,否则不生效)
await Cos.setClsMinLevel(LogLevel.verbose);
// 设置设备ID
await Cos.setDeviceID("DeviceID");
// 设置设备型号
await Cos.setDeviceModel("DeviceModel");
// 设置APP版本号
await Cos.setAppVersion("AppVersion");
// 设置拓展字段
await Cos.setExtras({"userId":"1"});
// 获取日志文件目录路径
let logRootDir = await Cos.getLogRootDir();
初始化 COS 时进行日志的配置和管理。
const cos = new COS({
// 其他配置保持不变
// 本地日志相关
EnableLog: true, // 开启日志开关
EnableLogcat: true, // 日志输出到控制台
LogLevel: 'VERBOSE', // 日志输出级别
LogExtras: { userId: '123' } // 日志输出附加信息
});
cos.on('log-message', msg => {
// 日志回调
console.log(msg);
});

文件日志加解密

加密

Android
iOS
Flutter
React Native
通过 COSLogger 进行文件日志的加密配置。
注意:
由于 COSLogger 的初始化依赖 CosXmlBaseService,因此需要在 CosXmlService 或 CosXmlSimpleService 首次实例化后调用 COSLogger。
byte[] key = new byte[] {
// 32个字节的16进制表示(示例值,实际应使用安全随机数生成)
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
};
byte[] iv ={
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
};
COSLogger.setLogFileEncryptionKey(key, iv);
通过 QCloudLogger 进行文件日志的加密配置。
// 32个字节的16进制表示(示例值,实际应使用安全随机数生成)
NSData *keyData = [NSData dataWithBytes:(unsigned char[]){
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
} length:32];

NSData *ivData = [NSData dataWithBytes:(unsigned char[]){
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
} length:16];
[QCloudLogger sharedLogger].aesKey = keyData;
[QCloudLogger sharedLogger].aesIv = ivData;
通过 Cos() 进行文件日志的加密配置。
注意:
由于日志的初始化依赖 CosService,因此需要在 registerDefaultService 或 registerDefaultTransferManger 后调用日志相关功能。
// 创建加密密钥和初始化向量
final key = Uint8List.fromList([
// 32字节的密钥(示例值,实际应使用安全随机数生成)
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
]);

final iv = Uint8List.fromList([
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
]);

// 调用设置日志文件加密密钥的方法
await Cos().setLogFileEncryptionKey(key, iv);
通过 Cos 进行文件日志的加密配置。
注意:
由于日志的初始化依赖 CosService,因此需要在 registerDefaultService 或 registerDefaultTransferManger 后调用日志相关功能。
// 创建32字节的密钥和16字节的IV(示例值,实际应使用安全随机数生成)
const key = new Uint8Array([
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
]);

const iv = new Uint8Array([
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
]);

// 调用设置日志文件加密密钥方法
await Cos.setLogFileEncryptionKey(key, iv);

解密

加密日志文件内容格式为 [4字节长度头][密文数据][4字节长度头][密文数据]...
解密时读取文件后可按块分割密文,分别解密每个块得到原始日志。
以下为 Java 代码示例:
public class AesLogDecryptor {
private static final String ALGORITHM = "AES/CBC/PKCS5Padding";

public static void main(String[] args) {
try {
// key和iv必须和加密时配置的一致
byte[] key = new byte[] {
// 32个字节的16进制表示(示例值,实际应使用安全随机数生成)
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
};
byte[] iv ={
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
};
// 加密的日志文件路径
String encryptedFilePath = "2025-04-10-12-04-21_encrypt.log";
// 解密后输出的日志文件路径
String decryptedFilePath = "2025-04-10-12-04-21_encrypt.log.decrypted";

// 解密文件
decryptLogFile(new File(encryptedFilePath), new File(decryptedFilePath), key, iv);

System.out.println("解密完成,结果已保存到: " + decryptedFilePath);
} catch (Exception e) {
System.err.println("解密过程中发生错误: " + e.getMessage());
e.printStackTrace();
}
}

/**
* 解密加密的日志文件
* @param encryptedFile 加密的日志文件
* @param decryptedFile 解密后的输出文件
* @param key AES 密钥
* @param iv 初始化向量
* @throws Exception 解密过程中可能抛出的异常
*/
public static void decryptLogFile(File encryptedFile, File decryptedFile, byte[] key, byte[] iv) throws Exception {
System.err.print("iv: "+ Arrays.toString(iv));

SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);

try (DataInputStream dis = new DataInputStream(new FileInputStream(encryptedFile));
BufferedWriter writer = new BufferedWriter(new FileWriter(decryptedFile))) {

while (dis.available() > 0) {
// 读取4字节的长度头(大端序)
int length = dis.readInt();

// 读取密文数据
byte[] encrypted = new byte[length];
dis.readFully(encrypted);

// 解密数据
String decrypted = new String(decryptSingle(encrypted, keySpec, ivSpec), StandardCharsets.UTF_8);

// 写入解密后的内容到输出文件
writer.write(decrypted);
}
}
}

/**
* 解密单个数据块
* @param ciphertext 密文数据
* @param keySpec 密钥规范
* @param ivSpec 初始化向量规范
* @return 解密后的字节数组
* @throws Exception 解密过程中可能抛出的异常
*/
private static byte[] decryptSingle(byte[] ciphertext, SecretKeySpec keySpec, IvParameterSpec ivSpec) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
return cipher.doFinal(ciphertext);
}
}

将日志上报到 CLS

将 COS SDK 的运行日志上报至 腾讯云日志服务 CLS,您可在 CLS 控制台 上查看具体的日志,便于您后续分析。
说明:
客户端 COS SDK的日志将被上报至腾讯云日志服务 CLS。上报后的日志,按照 CLS 计费规则计费,详情请参见 CLS 计费概述
1. 创建 CLS 日志主题
登录 腾讯云日志服务控制台,创建日志主题后,点击名称进入基本信息页签获取日志主题ID地域,详情请参见 CLS 地域说明,例如:日志主题 ID 为 c09216e3-ade5-4725-a000-000000000000,地域为 ap-guangzhou。
2. 在 COS SDK 中进行配置
Android
iOS
Flutter
React Native
Web
步骤1:安装 CLS SDK
在应用级别(通常是 App 模块下)的 build.gradle 中添加依赖:
dependencies {
...
// 增加这两行
implementation 'com.tencentcloudapi.cls:tencentcloud-cls-sdk-android:1.0.5'
implementation 'com.google.guava:guava:27.0.1-android'
}
步骤2:设置日志上报 CLS 渠道
临时密钥
固定密钥(仅测试)
1. 实现一个 ClsLifecycleCredentialProvider 的子类,实现请求临时密钥并返回结果的过程。
临时密钥的获取可以参考:使用临时密钥访问 CLS获取联合身份临时访问凭证(授权策略中 action 设置为 name/cls:pushLog)。
ClsLifecycleCredentialProvider clsLifecycleCredentialProvider = new ClsLifecycleCredentialProvider() {
@Override
protected ClsSessionCredentials fetchNewCredentials() throws ClsAuthenticationException {
// 首先从您的临时密钥服务器获取包含了密钥信息的响应

// 然后解析响应,获取临时密钥信息
String tmpSecretId = "SECRETID"; // 临时密钥 SecretId
String tmpSecretKey = "SECRETKEY"; // 临时密钥 SecretKey
String sessionToken = "SESSIONTOKEN"; // 临时密钥 Token
long expiredTime = 1556183496L;//临时密钥有效截止时间戳,单位是秒

// 最后返回临时密钥信息对象
return new ClsSessionCredentials(tmpSecretId, tmpSecretKey,
sessionToken, expiredTime);
}
};
注意:
建议用户 使用临时密钥,通过临时授权的方式进一步提高安全性。申请临时密钥时,请遵循 最小权限指引原则,防止泄露目标之外的资源。
如果您一定要使用永久密钥,建议遵循 最小权限指引原则 对永久密钥的权限范围进行限制。
2. 初始化 CLS 上报
// CLS 日志主题的 ID 和地域
String topicId = "c09216e3-ade5-4725-a000-000000000000";
String topicEndpoint = "ap-guangzhou.cls.tencentcs.com";

// clsLifecycleCredentialProvider 为上一步中获取到的 cls 临时密钥提供器
// 设置 CLS 渠道(临时密钥)
COSLogger.setCLsChannel(topicId, topicEndpoint, clsLifecycleCredentialProvider);
您可以使用腾讯云的固定密钥来进行开发阶段的本地调试。由于该方式存在泄露密钥的风险,请务必在上线前替换为非匿名模式的方式。
//用户的 SecretId,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。
//子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
String secretId = "SECRETID";
//用户的 SecretKey,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。
//子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
String secretKey = "SECRETKEY";

// CLS 日志主题的 ID 和地域
String topicId = "c09216e3-ade5-4725-a000-000000000000";
String topicEndpoint = "ap-guangzhou.cls.tencentcs.com";

//设置固定密钥CLS渠道(仅测试时使用,不建议在正式环境使用固定密钥)
COSLogger.setCLsChannel(topicId, topicEndpoint, secretId, secretKey);
步骤3:设置网络权限
日志上传是基于 http 的,因此需要对 xxx.cls.tencentcs.com 域名进行 http 开放。
1. 在 res 文件夹下创建一个 xml 文件夹,然后创建一个 network_security_config.xml 文件,文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<!--cls-->
<domain includeSubdomains="true">cls.tencentcs.com</domain>
</domain-config>
</network-security-config>
2. 在 AndroidManifest.xml 文件下的 application 标签增加以下属性:
<application
...
android:networkSecurityConfig="@xml/network_security_config"
...
/>
步骤1:安装 CLS SDK
在 podfile文件中增加 CLS SDK 依赖。
pod "QCloudTrack/Cls"
步骤2:设置日志上报 CLS 渠道
临时密钥
固定密钥(仅测试)
1. 实现一个 ClsLifecycleCredentialProvider 的子类,实现请求临时密钥并返回结果的过程。
临时密钥的获取可以参考:使用临时密钥访问 CLS获取联合身份临时访问凭证(授权策略中 action 设置为 name/cls:pushLog)。
QCloudCLSLoggerOutput * clsOutput = [[QCloudCLSLoggerOutput alloc]initWithTopicId:@"c09216e3-ade5-4725-a000-000000000000" endpoint:@"ap-guangzhou.cls.tencentcs.com"];
[clsOutput setupCredentialsRefreshBlock:^QCloudCredential * _Nonnull{
dispatch_semaphore_t semp = dispatch_semaphore_create(0);
NSMutableURLRequest * mrequest = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:@"临时密钥服务器地址"]];
__block QCloudCredential * credential = nil;
// 首先从您的临时密钥服务器获取包含了密钥信息的响应
[[[NSURLSession sharedSession]dataTaskWithRequest:mrequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (data) {
credential = [QCloudCredential new];
NSDictionary * result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
NSDictionary * credentials = result[@"credentials"];
credential.secretID = credentials[@"tmpSecretId"];
credential.secretKey = credentials[@"tmpSecretKey"];
credential.token = credentials[@"sessionToken"];
credential.expirationDate = [NSDate dateWithTimeIntervalSinceNow:[credentials[@"sessionToken"] integerValue]];
}
dispatch_semaphore_signal(semp);
}]resume];
dispatch_semaphore_wait(semp, DISPATCH_TIME_FOREVER);
return credential;
}];
[[QCloudLogger sharedLogger] addLogger:clsOutput];
注意:
建议用户 使用临时密钥,通过临时授权的方式进一步提高安全性。申请临时密钥时,请遵循 最小权限指引原则,防止泄露目标之外的资源。
如果您一定要使用永久密钥,建议遵循 最小权限指引原则 对永久密钥的权限范围进行限制。
2. 初始化 CLS 上报
// CLS 日志主题的 ID 和地域
String topicId = "c09216e3-ade5-4725-a000-000000000000";
String topicEndpoint = "ap-guangzhou.cls.tencentcs.com";

// clsLifecycleCredentialProvider 为上一步中获取到的 cls 临时密钥提供器
// 设置 CLS 渠道(临时密钥)
COSLogger.setCLsChannel(topicId, topicEndpoint, clsLifecycleCredentialProvider);
您可以使用腾讯云的固定密钥来进行开发阶段的本地调试。由于该方式存在泄露密钥的风险,请务必在上线前替换为非匿名模式的方式。
//用户的 SecretId,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。
//子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
NSString * secretId = @"SECRETID";
//用户的 SecretKey,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。
//子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
NSString * secretKey = @"SECRETKEY";
QCloudCLSLoggerOutput * clsOutput = [[QCloudCLSLoggerOutput alloc]initWithTopicId:@"c09216e3-ade5-4725-a000-000000000000" endpoint:@"ap-guangzhou.cls.tencentcs.com"];
[clsOutput setupPermanentCredentialsSecretId:secretId secretKey:secretKey];
[[QCloudLogger sharedLogger] addLogger:clsOutput];
注意:
日志上传是基于 http 的,因此需要对 xxx.cls.tencentcs.com 域名进行 http 开放。
配置支持 HTTP 请求,需要在项目的 info.plist 文件中添加 App Transport Security Settings -> Allow Arbitrary Loads 并将其设置为 YES。
步骤1:安装 CLS SDK
Android
iOS
在 Android 目录的应用级别(通常是 App 模块下)的 build.gradle 中添加依赖:
dependencies {
...
// 增加这两行
implementation 'com.tencentcloudapi.cls:tencentcloud-cls-sdk-android:1.0.5'
implementation 'com.google.guava:guava:27.0.1-android'
}
在 iOS 目录的应用级别(通常是 App 模块下)的 podfile 中添加依赖:
pod "QCloudTrack/Cls"
步骤2:设置日志上报 CLS 渠道
临时密钥
固定密钥(仅测试)
1. 实现一个 IFetchCLsChannelCredentials 的子类,实现请求临时密钥并返回结果的过程。
临时密钥的获取可以参考:使用临时密钥访问 CLS获取联合身份临时访问凭证(授权策略中 action 设置为 name/cls:pushLog)。
class CLSFetchCLsChannelCredentials implements IFetchCLsChannelCredentials{
@override
Future<SessionQCloudCredentials> fetchCLsChannelSessionCredentials() async {
// 首先从您的临时密钥服务器获取包含了密钥信息的响应
// 然后解析响应,获取临时密钥信息
String tmpSecretId = "SECRETID"; // 临时密钥 SecretId
String tmpSecretKey = "SECRETKEY"; // 临时密钥 SecretKey
String sessionToken = "SESSIONTOKEN"; // 临时密钥 Token
long expiredTime = 1556183496L;//临时密钥有效截止时间戳,单位是秒
// 最后返回临时密钥信息对象
return SessionQCloudCredentials(
secretId: tmpSecretId,
secretKey: tmpSecretKey,
token: sessionToken,
expiredTime: expiredTime
);
}
}
注意:
建议用户 使用临时密钥,通过临时授权的方式进一步提高安全性。申请临时密钥时,请遵循 最小权限指引原则,防止泄露目标之外的资源。
如果您一定要使用永久密钥,建议遵循 最小权限指引原则 对永久密钥的权限范围进行限制。
2. 初始化 CLS 上报
// CLS 日志主题的 ID 和地域
String topicId = "c09216e3-ade5-4725-a000-000000000000";
String topicEndpoint = "ap-guangzhou.cls.tencentcs.com";

// CLSFetchCLsChannelCredentials 为上一步中获取到的 cls 临时密钥提供器
// 设置 CLS 渠道(临时密钥)
await Cos().setCLsChannelSessionCredential(topicId, topicEndpoint, CLSFetchCLsChannelCredentials());
您可以使用腾讯云的固定密钥来进行开发阶段的本地调试。由于该方式存在泄露密钥的风险,请务必在上线前替换为非匿名模式的方式。
//用户的 SecretId,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。
//子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
String secretId = "SECRETID";
//用户的 SecretKey,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。
//子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
String secretKey = "SECRETKEY";

// CLS 日志主题的ID和地域
String topicId = "c09216e3-ade5-4725-a000-000000000000";
String topicEndpoint = "ap-guangzhou.cls.tencentcs.com";

//设置固定密钥CLS渠道(仅测试时使用,不建议在正式环境使用固定密钥)
await Cos().setCLsChannelStaticKey(topicId, topicEndpoint, secretId, secretKey);
步骤3:设置网络权限
日志上传是基于 http 的,因此需要对 xxx.cls.tencentcs.com 域名进行 http 开放。
Android
iOS
在 Android 目录的应用级别(通常是 App 模块下)
1. 在 res 文件夹下创建一个 xml 文件夹,然后创建一个 network_security_config.xml 文件,文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<!--cls-->
<domain includeSubdomains="true">cls.tencentcs.com</domain>
</domain-config>
</network-security-config>
2. 在 AndroidManifest.xml 文件下的 application 标签增加以下属性:
<application
...
android:networkSecurityConfig="@xml/network_security_config"
...
/>
日志上传是基于 http 的,因此需要对 xxx.cls.tencentcs.com 域名进行 http 开放。
配置支持 HTTP 请求,需要在项目的 info.plist 文件中添加 App Transport Security Settings -> Allow Arbitrary Loads 并将其设置为 YES。
步骤1:安装 CLS SDK
Android
iOS
在 Android 目录的应用级别(通常是 App 模块下)的 build.gradle 中添加依赖:
dependencies {
...
// 增加这两行
implementation 'com.tencentcloudapi.cls:tencentcloud-cls-sdk-android:1.0.5'
implementation 'com.google.guava:guava:27.0.1-android'
}
在 iOS 目录的应用级别(通常是 App 模块下)的 podfile 中添加依赖:
pod "QCloudTrack/Cls"
步骤2:设置日志上报 CLS 渠道
临时密钥
固定密钥(仅测试)
临时密钥的获取可以参考:使用临时密钥访问 CLS获取联合身份临时访问凭证(授权策略中 action 设置为 name/cls:pushLog)。
// CLS 日志主题的ID和地域
let topicId = "c09216e3-ade5-4725-a000-000000000000";
let topicEndpoint = "ap-guangzhou.cls.tencentcs.com";

// 设置 CLS 渠道(临时密钥)
Cos.setCLsChannelSessionCredential(topicId, topicEndpoint, async () => {
// 首先从您的临时密钥服务器获取包含了密钥信息的响应
// 然后解析响应,获取临时密钥信息
let tmpSecretId = "SECRETID"; // 临时密钥 SecretId
let tmpSecretKey = "SECRETKEY"; // 临时密钥 SecretKey
let sessionToken = "SESSIONTOKEN"; // 临时密钥 Token
let expiredTime = 1556183496L;//临时密钥有效截止时间戳,单位是秒
// 最后返回临时密钥信息对象
const sessionCredentials = {
tmpSecretId: tmpSecretId,
tmpSecretKey: tmpSecretKey,
expiredTime: expiredTime,
sessionToken: sessionToken
};
return sessionCredentials;
});
注意:
建议用户 使用临时密钥,通过临时授权的方式进一步提高安全性。申请临时密钥时,请遵循 最小权限指引原则,防止泄露目标之外的资源。
如果您一定要使用永久密钥,建议遵循 最小权限指引原则 对永久密钥的权限范围进行限制。
您可以使用腾讯云的固定密钥来进行开发阶段的本地调试。由于该方式存在泄露密钥的风险,请务必在上线前替换为非匿名模式的方式。
//用户的 SecretId,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。
//子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
let secretId = "SECRETID";
//用户的 SecretKey,建议使用子账号密钥,授权遵循最小权限指引,降低使用风险。
//子账号密钥获取可参见 https://cloud.tencent.com/document/product/598/37140
let secretKey = "SECRETKEY";

// CLS 日志主题的 ID 和地域
let topicId = "c09216e3-ade5-4725-a000-000000000000";
let topicEndpoint = "ap-guangzhou.cls.tencentcs.com";

//设置固定密钥 CLS 渠道(仅测试时使用,不建议在正式环境使用固定密钥)
await Cos.setCLsChannelStaticKey(topicId, topicEndpoint, secretId, secretKey)
步骤3:设置网络权限
日志上传是基于 http 的,因此需要对 xxx.cls.tencentcs.com 域名进行 http 开放。
Android
iOS
在 Android 目录的应用级别(通常是 App 模块下)
1. 在 res 文件夹下创建一个 xml 文件夹,然后创建一个 network_security_config.xml 文件,文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<!--cls-->
<domain includeSubdomains="true">cls.tencentcs.com</domain>
</domain-config>
</network-security-config>
2. 在 AndroidManifest.xml 文件下的 application 标签增加以下属性:
<application
...
android:networkSecurityConfig="@xml/network_security_config"
...
/>
日志上传是基于 http 的,因此需要对 xxx.cls.tencentcs.com 域名进行 http 开放。
配置支持 HTTP 请求,需要在项目的 info.plist 文件中添加 App Transport Security Settings -> Allow Arbitrary Loads 并将其设置为 YES。
步骤1:访问 链接下载 CLS 上报 sdk。
const ClsClient = require('demo/common/cls.min.js');
步骤2:设置日志上报 CLS 渠道
const clsClient = new ClsClient({
topicId: 'c09216e3-ade5-4725-a000-000000000000', // 日志主题 id
region: 'ap-guangzhou', // 日志主题所在地域,比如 ap-guangzhou
maxRetainDuration: 30, // 默认 30s
maxRetainSize: 20, // 默认20条
});
const cos = new COS({
ClsLogger: clsClient, // 日志输出到 cls
});


实践建议

下面对一些常见场景给出实践建议,开发者可以根据自身业务场景进行灵活调整。
开发调试:控制台日志 + DEBUG 级别
回捞或主动上报:本地文件日志 + DEBUG 级别
后台日常收集和聚合:业务回调或 CLS + DEBUG 或 INFO