Sources/OT/SLSSpan.m (283 lines of code) (raw):

// // SLSSpan.m // AliyunLogProducer // // Created by gordon on 2022/4/27. // #import "SLSSpan.h" #import "SLSContextManager.h" //#import "NSString+SLS.h" NSString* const SLSINTERNAL = @"INTERNAL"; NSString* const SLSSERVER = @"SERVER"; NSString* const SLSCLIENT = @"CLIENT"; NSString* const SLSPRODUCER = @"PRODUCER"; NSString* const SLSCONSUMER = @"CONSUMER"; typedef void (^_internal_Scope)(void); @interface SLSSpan () @property(nonatomic, strong, readonly) _internal_Scope scope; @property(nonatomic, strong) NSLock *lock; - (void) addEventInternal:(SLSEvent *)event; @end @implementation SLSSpan - (instancetype)init { self = [super init]; if (self) { _attribute = [NSMutableDictionary<NSString*, NSString*> dictionary]; _evetns = [NSMutableArray<SLSEvent*> array]; _links = [NSMutableArray<SLSLink*> array]; _resource = [[SLSResource alloc] init]; _kind = SLSCLIENT; _isGlobal = YES; _lock = [[NSLock alloc] init]; } return self; } - (instancetype) setParent: (SLSSpan *) parent { if (!parent) { return self; } [_lock lock]; _parentSpanID = parent.spanID; _traceID = parent.traceID; [_lock unlock]; return self; } - (SLSSpan *) addAttribute:(SLSAttribute *)attribute, ... NS_REQUIRES_NIL_TERMINATION { [_lock lock]; NSMutableDictionary<NSString*, NSString*> *dict = (NSMutableDictionary<NSString*, NSString*> *) _attribute; [dict setObject:attribute.value forKey:attribute.key]; va_list args; SLSAttribute *arg; va_start(args, attribute); while ((arg = va_arg(args, SLSAttribute*))) { [dict setObject:arg.value forKey:arg.key]; } va_end(args); [_lock unlock]; return self; } - (SLSSpan *) addAttributes:(NSArray<SLSAttribute*> *)attributes { [_lock lock]; NSMutableDictionary<NSString*, NSString*> *dict = (NSMutableDictionary<NSString*, NSString*> *) _attribute; for (SLSAttribute *attr in attributes) { [dict setObject:attr.value forKey:attr.key]; } [_lock unlock]; return self; } - (SLSSpan *) addResource: (SLSResource *) resource { if (resource) { [_lock lock]; [_resource merge:resource]; [_lock unlock]; } return self; } - (SLSSpan *) addEvent:(NSString *)name { [self addEventInternal:[SLSEvent eventWithName:name]]; return self; } - (SLSSpan *) addEvent:(NSString *)name attribute: (SLSAttribute *)attribute, ... NS_REQUIRES_NIL_TERMINATION { SLSEvent *event = [SLSEvent eventWithName:name]; [event addAttribute:attribute, nil]; va_list args; SLSAttribute *arg; va_start(args, attribute); while ((arg = va_arg(args, SLSAttribute*))) { [event addAttribute:arg, nil]; } va_end(args); [self addEventInternal:event]; return self; } - (SLSSpan *) addEvent:(NSString *)name attributes:(NSArray<SLSAttribute *> *)attributes { [self addEventInternal: [[SLSEvent eventWithName:name] addAttributes:attributes] ]; return self; } - (SLSSpan *) addLink: (SLSLink *)link, ... NS_REQUIRES_NIL_TERMINATION { NSMutableArray<SLSLink*> *links = (NSMutableArray<SLSLink*> *)_links; [_lock lock]; [links addObject:link]; [_lock unlock]; va_list args; SLSLink *arg; va_start(args, link); while ((arg = va_arg(args, SLSLink*))) { [_lock lock]; [links addObject:arg]; [_lock unlock]; } va_end(args); return self; } - (SLSSpan *) addLinks: (NSArray<SLSLink *> *)links { if (nil == links) { return self; } [_lock lock]; [((NSMutableArray<SLSLink*> *)_links) addObjectsFromArray:links]; [_lock unlock]; return self; } - (SLSSpan *) recordException:(NSException *)exception { return [self recordException:exception attributes:[NSArray array]]; } - (SLSSpan *) recordException:(NSException *)exception attribute: (SLSAttribute *)attribute, ... NS_REQUIRES_NIL_TERMINATION { NSMutableArray<SLSAttribute *> *attr = [NSMutableArray array]; if (nil != attribute) { [attr addObject:attribute]; } va_list args; SLSAttribute *arg; va_start(args, attribute); while ((arg = va_arg(args, SLSAttribute*))) { [attr addObject:arg]; } va_end(args); return [self recordException:exception attributes:attr]; } - (SLSSpan *) recordException:(NSException *)exception attributes:(NSArray<SLSAttribute *> *)attribute { SLSEvent *event = [[SLSEvent eventWithName:@"exception"] addAttribute: [SLSAttribute of:@"exception.type" value:exception.name], [SLSAttribute of:@"exception.message" value:exception.reason], [SLSAttribute of:@"exception.stacktrace" value:(exception.callStackSymbols ? [[exception.callStackSymbols valueForKey:@"description"] componentsJoinedByString:@"\n"] : @"")], nil ]; [event addAttributes:attribute]; [self addEventInternal:event]; return self; } - (void) addEventInternal:(SLSEvent *)event { [_lock lock]; [((NSMutableArray<SLSEvent*> *) _evetns) addObject:event]; [_lock unlock]; } - (BOOL) end { [_lock lock]; if (_isEnd) { return NO; } _isEnd = YES; _duration = (_end - _start) / 1000; if (nil != _scope) { _scope(); } [_lock unlock]; return YES; } - (NSDictionary<NSString*, NSString*> *) toDict { [_lock lock]; NSMutableDictionary *dict = [NSMutableDictionary dictionary]; [dict setObject:_name forKey:@"name"]; [dict setObject:_kind forKey:@"kind"]; [dict setObject:_traceID forKey:@"traceID"]; [dict setObject:_spanID forKey:@"spanID"]; [dict setObject:_parentSpanID ? _parentSpanID : @"" forKey:@"parentSpanID"]; [dict setObject:_sessionId ? _sessionId : @"" forKey:@"sid"]; [dict setObject:_transactionId ? _transactionId : @"" forKey:@"pid"]; [dict setObject:[NSString stringWithFormat:@"%ld", _start] forKey:@"start"]; [dict setObject:[NSString stringWithFormat:@"%ld", _duration] forKey:@"duration"]; [dict setObject:[NSString stringWithFormat:@"%ld", _end] forKey:@"end"]; [dict setObject:_statusCode == UNSET ? @"UNSET" : (_statusCode == OK ? @"OK" : @"ERROR" ) forKey:@"statusCode"]; [dict setObject:_statusMessage.length > 0 ? _statusMessage : @"" forKey:@"statusMessage"]; [dict setObject:_host ? _host : @"" forKey:@"host"]; // service name default: iOS [dict setObject:_service.length > 0 ? _service : @"iOS" forKey:@"service"]; NSMutableDictionary<NSString*, NSString*> *attributeDict = [NSMutableDictionary<NSString*, NSString*> dictionary]; for (NSString* key in [_attribute allKeys]) { [attributeDict setObject:[_attribute valueForKey:key] forKey:key]; } [dict setObject:[self stringWithDictionary:attributeDict] forKey:@"attribute"]; if (_resource.attributes) { NSMutableDictionary<NSString*, NSString*> *resourceDict = [NSMutableDictionary<NSString*, NSString*> dictionary]; for (SLSAttribute *attr in _resource.attributes) { [resourceDict setObject:attr.value forKey:attr.key]; } [dict setObject:[self stringWithDictionary: resourceDict] forKey:@"resource"]; } if (_evetns && [_evetns count] > 0) { NSMutableArray *logs = [NSMutableArray array]; for (SLSEvent *event in _evetns) { NSMutableDictionary *object = [NSMutableDictionary dictionary]; [object setObject:(event.name.length > 0 ? event.name : @"") forKey:@"name"]; [object setObject:[[NSNumber numberWithLong:event.epochNanos] stringValue] forKey:@"epochNanos"]; [object setObject:[[NSNumber numberWithInt:event.totalAttributeCount] stringValue] forKey:@"totalAttributeCount"]; NSArray<SLSAttribute *> *attributes = event.attributes; NSMutableDictionary<NSString*, NSString*> *attrObject = [NSMutableDictionary dictionary]; for (SLSAttribute *attr in attributes) { [attrObject setObject:attr.value forKey:attr.key]; } [object setObject:attrObject forKey:@"attributes"]; [logs addObject:object]; } [dict setObject:logs forKey:@"logs"]; } if (_links && _links.count > 0) { NSMutableArray *links = [NSMutableArray array]; for (SLSLink *link in _links) { NSMutableDictionary *object = [NSMutableDictionary dictionary]; [object setObject:(link.traceId.length > 0 ? link.traceId : @"") forKey:@"traceID"]; [object setObject:(link.spanId.length > 0 ? link.spanId : @"") forKey:@"spanID"]; NSArray<SLSAttribute *> *attributes = link.attributes; NSMutableDictionary<NSString*, NSString*> *attrObject = [NSMutableDictionary dictionary]; for (SLSAttribute *attr in attributes) { [attrObject setObject:attr.value forKey:attr.key]; } [object setObject:attrObject forKey:@"attributes"]; [links addObject:object]; } [dict setObject:links forKey:@"links"]; } [_lock unlock]; return dict; } - (SLSSpan *) setGlobal: (BOOL) global { [_lock lock]; _isGlobal = global; [_lock unlock]; return self; } - (SLSSpan *) setScope: (void (^)(void)) scope { [_lock lock]; _scope = scope; [_lock unlock]; return self; } - (id)copyWithZone:(nullable NSZone *)zone { SLSSpan *span = [[SLSSpan alloc] init]; [_lock lock]; span.name = _name; span.traceID = _traceID; span.spanID = _spanID; span.parentSpanID = _parentSpanID; span.start = _start; span.end = _end; span.duration = _duration; span.attribute = _attribute; span.statusCode = _statusCode; span.statusMessage = _statusMessage; span.host = _host; span.resource = [_resource copy]; span.service = _service; span.sessionId = _sessionId; span.transactionId = _transactionId; span->_isEnd = _isEnd; [_lock unlock]; return span; } - (NSString *) stringWithDictionary: (NSDictionary *) dictionary { if (![NSJSONSerialization isValidJSONObject:dictionary]) { return [NSString string]; } NSJSONWritingOptions options = kNilOptions; if (@available(iOS 11.0, macOS 10.13, watchOS 4.0, tvOS 11.0, *)) { options = NSJSONWritingSortedKeys; } NSError *error = nil; NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary options:options error:&error ]; if (nil != error) { return [NSString string]; } return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding ]; } @end