XcodeSwift/AliyunLogSwift/ViewController.swift (204 lines of code) (raw):
//
// ViewController.swift
// AliyunLogSwift
//
// Created by gordon on 2021/12/17.
//
import UIKit
import AliyunLogProducer
import Combine
class ViewController: UIViewController {
fileprivate var client: LogProducerClient!
var cancellables = Set<AnyCancellable>()
var index: Int = 0
var x : Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let utils = DemoUtils.shared
let file = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first
let path = file! + "/log.dat"
let config = LogProducerConfig(endpoint:utils.endpoint, project:utils.project, logstore:utils.logstore, accessKeyID:utils.accessKeyId, accessKeySecret:utils.accessKeySecret)!
// 指定sts token 创建config,过期之前调用ResetSecurityToken重置token
// let config = LogProducerConfig(endpoint:endpoint, project:project, logstore:logstore, accessKeyID:accesskeyid, accessKeySecret:accesskeysecret, securityToken:securityToken)
// 设置主题
config.setTopic("test_topic")
// 设置tag信息,此tag会附加在每条日志上
config.addTag("test", value:"test_tag")
// 每个缓存的日志包的大小上限,取值为1~5242880,单位为字节。默认为1024 * 1024
config.setPacketLogBytes(1024*1024)
// 每个缓存的日志包中包含日志数量的最大值,取值为1~4096,默认为1024
config.setPacketLogCount(1024)
// 被缓存日志的发送超时时间,如果缓存超时,则会被立即发送,单位为毫秒,默认为3000
config.setPacketTimeout(3000)
// 单个Producer Client实例可以使用的内存的上限,超出缓存时add_log接口会立即返回失败
// 默认为64 * 1024 * 1024
config.setMaxBufferLimit(64*1024*1024)
// 发送线程数,默认为1
config.setSendThreadCount(1)
// 1 开启断点续传功能, 0 关闭
// 每次发送前会把日志保存到本地的binlog文件,只有发送成功才会删除,保证日志上传At Least Once
config.setPersistent(1)
// 持久化的文件名,需要保证文件所在的文件夹已创建。
config.setPersistentFilePath(path)
// 是否每次AddLog强制刷新,高可靠性场景建议打开
config.setPersistentForceFlush(1)
// 持久化文件滚动个数,建议设置成10。
config.setPersistentMaxFileCount(10)
// 每个持久化文件的大小,建议设置成1-10M
config.setPersistentMaxFileSize(1024*1024)
// 本地最多缓存的日志数,不建议超过1M,通常设置为65536即可
config.setPersistentMaxLogCount(65536)
//网络连接超时时间,整数,单位秒,默认为10
config.setConnectTimeoutSec(10)
//日志发送超时时间,整数,单位秒,默认为15
config.setSendTimeoutSec(10)
//flusher线程销毁最大等待时间,整数,单位秒,默认为1
config.setDestroyFlusherWaitSec(2)
//sender线程池销毁最大等待时间,整数,单位秒,默认为1
config.setDestroySenderWaitSec(2)
//数据上传时的压缩类型,默认为LZ4压缩, 0 不压缩,1 LZ4压缩, 默认为1
config.setCompressType(1)
//设备时间与标准时间之差,值为标准时间-设备时间,一般此种情况用户客户端设备时间不同步的场景
//整数,单位秒,默认为0;比如当前设备时间为1607064208, 标准时间为1607064308,则值设置为 1607064308 - 1607064208 = 100
config.setNtpTimeOffset(1)
//日志时间与本机时间之差,超过该大小后会根据 `drop_delay_log` 选项进行处理。
//一般此种情况只会在设置persistent的情况下出现,即设备下线后,超过几天/数月启动,发送退出前未发出的日志
//整数,单位秒,默认为7*24*3600,即7天
config.setMaxLogDelayTime(7*24*3600)
//对于超过 `max_log_delay_time` 日志的处理策略
//0 不丢弃,把日志时间修改为当前时间; 1 丢弃,默认为 1 (丢弃)
config.setDropDelayLog(1)
//是否丢弃鉴权失败的日志,0 不丢弃,1丢弃
//整数,默认为 0,即不丢弃
config.setDropUnauthorizedLog(0)
//注册 获取服务器时间 的函数
config.setGetTimeUnixFunc({ () -> UInt32 in
let time = Date().timeIntervalSince1970
return UInt32(time);
})
let callbackFunc: on_log_producer_send_done_function = {config_name,result,log_bytes,compressed_bytes,req_id,error_message,raw_buffer,user_param in
let res = LogProducerResult(rawValue: Int(result))
// print(res!)
// let reqId = req_id == nil ? "":String(cString: req_id!)
// print(reqId)
// let errorMessage = error_message == nil ? "" : String(cString: error_message!)
// print(errorMessage)
// print(log_bytes)
// print(compressed_bytes)
}
client = LogProducerClient(logProducerConfig:config, callback:callbackFunc)
// client = LogProducerClient(logProducerConfig:config)
// DispatchQueue.global().async {
// Thread.sleep(forTimeInterval: 3.0)
// SLSTracer.spanBuilder("for test in async, should independent").build().end()
// }
}
func sendOneLog() {
let log = getOneLog()
// log.putContent("index", value:String(x))
x = x + 1
let res = client?.add(log, flush:1)
print(res!)
}
func sendMulLog(_ num :Int) {
while true {
let time1 = Date().timeIntervalSince1970
for _ in 0..<num {
let log = self.getOneLog()
let res = self.client?.add(log)
}
let time2 = Date().timeIntervalSince1970
if time2 - time1 < 1 {
do {
usleep(useconds_t((1 - (time2 - time1)) * 1000000))
}
}
}
}
func getOneLog() -> Log {
let log = Log()
let logTime = Date().timeIntervalSince1970
log.setTime(useconds_t(logTime))
log.putContent("content_key_1", value:"1abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+")
log.putContent("content_key_2", value:"2abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+")
log.putContent("content_key_3", value:"3abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+")
log.putContent("content_key_4", value:"4abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+")
log.putContent("content_key_5", value:"5abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+")
log.putContent("content_key_6", value:"6abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+")
log.putContent("content_key_7", value:"7abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+")
log.putContent("content_key_8", value:"8abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+")
log.putContent("content_key_9", value:"9abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+")
log.putContent("random", value:String(arc4random()))
log.putContent("content", value:"中文")
return log
}
@IBAction func sendLog(_ sender: Any) {
sendOneLog()
}
@IBAction func mockCrash(_ sender: Any) {
let numbers = [0]
let _ = numbers[1]
}
@IBAction func simpleTrace(_ sender: Any) {
// single span with SpanBuilder
SLSTracer.spanBuilder("span builder")
.setService("iOS")
.addAttributes([SLSAttribute.of("attr_key", value: "attr_value")])
.addResource(SLSResource.of("res_key", value: "res_value"))
.build()
.end()
// single span
var span = SLSTracer.startSpan("span 1")
span.addAttributes([SLSAttribute.of("attr_key", value: "attr_value")])
span.end()
// span with children
span = SLSTracer.startSpan("span with children", active: true)
SLSTracer.startSpan("child span 1").end()
SLSTracer.startSpan("child span 2").end()
span.end()
// span with function block
SLSTracer.withinSpan("span with func block") {
SLSTracer.startSpan("span within block 1").end()
SLSTracer.withinSpan("nested span with func block") {
SLSTracer.startSpan("nested span 1").end()
SLSTracer.startSpan("nested span 2").end()
}
// var array = [String]()
// array.remove(at: 10)
SLSTracer.startSpan("span within block 2").end()
}
// http request with traceid
SLSTracer.withinSpan("span with http request func") {
URLSession.shared.dataTask(with: URL.init(string: "http://sls-mall.caa227ac081f24f1a8556f33d69b96c99.cn-beijing.alicontainer.com/catalogue")!).resume()
}
}
@IBAction func startEngine(_ sender: Any) {
let root = SLSTracer.spanBuilder("执行启动引擎操作").setActive(true).build()
Task {
try await self.connectPower("启动引擎")
}
loadReportStatus().sink { _ in
root.end()
} receiveValue: { ret in
print("load report status result: \(ret)")
}
.store(in: &cancellables)
}
func connectPower(_ source: String) async throws {
SLSTracer.withinSpan("\(source) 1. 接通电源") {
// Thread.sleep(forTimeInterval: 1.0)
}
try await Task.sleep(nanoseconds: 3 * 1_000_000_000)
SLSTracer.withinSpan("\(source) 1.1. 电气系统自检") {
SLSTracer.withinSpan("\(source) 1.1.1. 电池电压检查") {
// Thread.sleep(forTimeInterval: 1.0)
// Task.sleep(2)
}
SLSTracer.withinSpan("\(source) 1.1.2. 电气信号检查") {
// Thread.sleep(forTimeInterval: 1.0)
// Task.sleep(2.0)
}
}
}
//
// func createTask() {
// Task {
// let span: SLSSpan = SLSContextManager.activeSpan()
// print("active span name: \(span.name)")
// }
// }
//
@IBAction func openAirConditioner(_ sender: Any) {
// let root = SLSTracer.spanBuilder("test root").setActive(true).build()
//
// createTask()
//
// root.end()
//
//
//
index += 1;
let root = SLSTracer.spanBuilder("打开空调-\(index)").setActive(true).build()
Task {
try await connectPower("打开空调-\(index)")
}
loadReportStatus().sink { _ in
// root.end()
} receiveValue: { ret in
print("load report status result: \(ret)")
}
.store(in: &cancellables)
root.end()
// SLSTracer.withinSpan("打开空调-\(self.index)") {
// self.connectPower("打开空调-\(self.index)")
//
// self.loadReportStatus().sink { _ in
//
// } receiveValue: { ret in
// print("load report status result: \(ret)")
// }
// .store(in: &self.cancellables)
// }
}
func loadReportStatus() -> Future<Bool, Error> {
let a = Future<Bool, Error> { promise in
SLSTracer.withinSpan("get report status") {
self.getReportStatus { result in
if case let .failure(error) = result {
print("Failed to report status, result: \(error.localizedDescription)")
}
promise(result)
}
}
}
// return a.eraseToAnyPublisher()
return a
}
func getReportStatus(completion: @escaping (Result<Bool, Error>) -> Void) {
// Task.detached {
// do {
// let result = try await self.reportStatus()
// completion(.success(result))
// } catch {
// completion(.failure(error))
// }
// }
Task {
do {
let result = try await self.reportStatus()
completion(.success(result))
} catch {
completion(.failure(error))
}
}
}
func reportStatus() async throws -> Bool {
var urlRequest = URLRequest(url: URL.init(string: "http://sls-mall.caa227ac081f24f1a8556f33d69b96c99.cn-beijing.alicontainer.com/catalogue")!)
urlRequest.httpMethod = "GET"
try await Task.sleep(nanoseconds: 3 * 1_000_000_000)
let session = URLSession.shared
try await session.data(for: urlRequest)
// let (_, response) = try await session.data(for: urlRequest)
// guard (response as? HTTPURLResponse)?.statusCode == 200 else {
// fatalError("Error while fetching data")
// }
return true
}
@IBAction func eventAndExceptionDemo(_ sender: Any) {
SLSTracer.startSpan("span with event")
.addEvent("event name")
.end()
SLSTracer.startSpan("span with event and attribute")
.addEvent("event name with attribute", attributes: [
SLSAttribute.of("attr_key", value: "attr_value"),
SLSAttribute.of("attr_key2", value: "attr_value2")
])
.end()
SLSTracer.startSpan("span with exception")
.recordException(NSException(name: NSExceptionName("mock exception name"), reason: "mock exception reason"))
.end()
SLSTracer.startSpan("span with exception and attribute")
.recordException(NSException(name: NSExceptionName("mock exception name"), reason: "mock exception reason"), attributes: [
SLSAttribute.of("attr_key", value: "attr_value"),
SLSAttribute.of("attr_key2", value: "attr_value2")
])
.end()
}
}