Sources/OT/SLSContextManager.m (152 lines of code) (raw):
//
// SLSContextManager.m
// Pods
//
// Created by gordon on 2022/9/13.
//
#import "SLSContextManager.h"
//#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0
// #define __HAS_SLS_OT_SWIFT
//#elif __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_12
// #define __HAS_SLS_OT_SWIFT
//#elif __TV_OS_VERSION_MIN_REQUIRED >= __TVOS_10_0
// #define __HAS_SLS_OT_SWIFT
//#endif
#ifdef __HAS_SLS_OT_SWIFT
#if __has_include(<AliyunLogProducer/AliyunLogProducer-Swift.h>)
#import <AliyunLogProducer/AliyunLogProducer-Swift.h>
#elif __has_include(<AliyunLogOT/AliyunLogOT-Swift.h>)
#import <AliyunLogOTSwift/AliyunLogOTSwift-Swift.h>
#elif __has_include("AliyunLogOTSwift/AliyunLogOTSwift-Swift.h")
#import "AliyunLogOTSwift/AliyunLogOTSwift-Swift.h"
#else
// should import AliyunLogOTSwift module in Swift
@import AliyunLogOTSwift;
#endif
#endif
@interface SLSContext ()
@property(nonatomic, strong) SLSSpan *span;
@end
@implementation SLSContext
@end
@interface SLSContextManager ()
@end
@implementation SLSContextManager
NSLock *lock;
SLSSpan *globalSpan;
NSString *startupTimestamp;
NSUserDefaults *userDefaults;
#ifdef __HAS_SLS_OT_SWIFT
ActivityContextManager *contextManager;
#endif
+ (void)initialize {
lock = [[NSLock alloc] init];
#ifdef __HAS_SLS_OT_SWIFT
contextManager = [[ActivityContextManager alloc] init];
#endif
startupTimestamp = [NSString stringWithFormat:@"%lf", [[NSDate date] timeIntervalSince1970]];
userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"sls_cached_span"];
}
+ (SLSContext *) current {
#ifdef __HAS_SLS_OT_SWIFT
if (@available(iOS 10.0, macOS 10.12, watchOS 3.0, tvOS 10.0, *)) {
return [contextManager getCurrentContextValueForKey:@"context"];
}
#endif
SLSContext *context = [[[NSThread currentThread] threadDictionary] objectForKey:@"sls_thread_context"];
if (nil == context) {
context = [[SLSContext alloc] init];
[[[NSThread currentThread] threadDictionary] setObject:context forKey:@"sls_thread_context"];
}
return context;
}
+ (void) update: (nullable SLSSpan *) span {
SLSContext *context = [self current];
context.span = span;
}
+ (SLSSpan *) activeSpan {
return [self current].span;
}
+ (SLSScope) makeCurrent: (SLSSpan *) span {
if (nil == span) {
return ^() {
};
}
SLSContext *beforeContext = [self current];
if (beforeContext.span == span) {
return ^() {
};
}
#ifdef __HAS_SLS_OT_SWIFT
SLSContext *current= [[SLSContext alloc] init];
current.span = span;
[contextManager setCurrentContextValueForKey:@"context" value:current];
return ^() {
[contextManager removeContextValueForKey:@"context" value:current];
[contextManager setCurrentContextValueForKey:@"context" value:beforeContext];
};
#else
SLSContext *current = [[[NSThread currentThread] threadDictionary] objectForKey:span];
if (nil == current) {
current = [[SLSContext alloc] init];
current.span = span;
[[[NSThread currentThread] threadDictionary] setObject:current forKey:span];
}
[[[NSThread currentThread] threadDictionary] setObject:current forKey:@"sls_thread_context"];
return ^() {
[[[NSThread currentThread] threadDictionary] setObject:beforeContext forKey:@"sls_thread_context"];
[[[NSThread currentThread] threadDictionary] removeObjectForKey:span];
};
#endif
}
+ (void) setGlobalActiveSpan: (SLSSpan *) span {
[lock lock];
globalSpan = span;
[lock unlock];
NSArray *array = @[
[NSString stringWithFormat:@"t:%@", span.traceID],
[NSString stringWithFormat:@"s:%@", span.spanID],
[NSString stringWithFormat:@"p:%@", span.parentSpanID.length > 0 ? span.parentSpanID : @""]
];
[userDefaults setObject:array forKey:[NSString stringWithFormat:@"sls_%@", startupTimestamp]];
}
+ (SLSSpan *) getGlobalActiveSpan {
return globalSpan;
}
+ (SLSSpan *) getLastGlobalActiveSpan {
NSArray *keys = [[userDefaults dictionaryRepresentation] allKeys];
NSMutableArray *array = [NSMutableArray array];
for (NSString *key in keys) {
if ([key hasPrefix:@"sls_"]) {
[array addObject:key];
}
}
if (array.count == 0) {
return nil;
}
[array sortUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
return [(NSString *)obj1 compare:obj2 options:NSCaseInsensitiveSearch];
}];
NSArray *finalValue = nil;
if (array.count == 1) {
finalValue = [userDefaults objectForKey:[array objectAtIndex:0]];
} else if ([array containsObject:[NSString stringWithFormat:@"sls_%@", startupTimestamp]]) {
long index = [array indexOfObject:[NSString stringWithFormat:@"sls_%@", startupTimestamp]] - 1;
if (index >= 0) {
finalValue = [userDefaults objectForKey:[array objectAtIndex:index]];
[self removeCachedSpan:array toIndex:index];
} else {
finalValue = [userDefaults objectForKey:[array objectAtIndex:0]];
}
} else {
finalValue = [userDefaults objectForKey:[array objectAtIndex:array.count - 1]];
[self removeCachedSpan:array toIndex:array.count -1];
}
SLSSpan *span = [[SLSSpan alloc] init];
for (NSString *value in finalValue) {
if ([value hasPrefix:@"t:"]) {
[span setTraceID:[[value componentsSeparatedByString:@":"] objectAtIndex:1]];
} else if ([value hasPrefix:@"s:"]) {
[span setSpanID:[[value componentsSeparatedByString:@":"] objectAtIndex:1]];
} else if ([value hasPrefix:@"p:"]) {
NSArray *substrings = [value componentsSeparatedByString:@":"];
if (substrings.count > 1 && [[substrings objectAtIndex:1] length] > 0) {
[span setParentSpanID:[substrings objectAtIndex:1]];
}
}
}
return span;
}
+ (void) removeCachedSpan: (NSArray *) keys toIndex: (long) index {
for (long i = 0; i < index; i ++) {
[userDefaults removeObjectForKey:[keys objectAtIndex:i]];
}
[userDefaults synchronize];
}
@end