Sources/Producer/LogProducerConfig.m (387 lines of code) (raw):

// // LogProducerConfig.m // AliyunLogProducer // // Created by lichao on 2020/9/27. // Copyright © 2020 lichao. All rights reserved. // #ifdef DEBUG #define SLSLog(...) NSLog(__VA_ARGS__) #else #define SLSLog(...) #endif #import "SLSSystemCapabilities.h" #import <Foundation/Foundation.h> #import "LogProducerConfig.h" #import "inner_log.h" #import "TimeUtils.h" #import "SLSURLSession.h" #import "SLSHttpHeader.h" #import "log_define.h" @interface LogProducerConfig () @property(nonatomic, strong) SLSHttpHeaderInjector injector; @property(nonatomic, assign) BOOL enablePersistent; @end @implementation LogProducerConfig static int os_http_post(const char *url, char **header_array, int header_count, const void *data, int data_len, post_log_result *http_response) { size_t request_id_len = sizeof(char) * 256; http_response->requestID = (char*) malloc(request_id_len); memset(http_response->requestID, 0, request_id_len); size_t error_message_len = sizeof(char) * 256; http_response->errorMessage = (char*) malloc(error_message_len); memset(http_response->errorMessage, 0, error_message_len); if(url == NULL || *url == 0 || header_array == NULL || header_count < 1 || data == NULL || data_len <= 0) { http_response->statusCode = 400; strcpy(http_response->requestID, ""); strcpy(http_response->errorMessage, "request is incorrect"); return 400; // bad request } NSString *urlString = [NSString stringWithUTF8String:url]; NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; [request setHTTPMethod:@"POST"]; [request setURL:[NSURL URLWithString:urlString]]; // set headers for(int i=0; i<header_count; i++) { char *kv = header_array[i]; if(kv != NULL) { char *eq = strchr(kv, ':'); if(eq != NULL && eq != kv && eq[1] != 0) { *eq = 0; [request addValue:[NSString stringWithUTF8String:eq+1] forHTTPHeaderField:[NSString stringWithUTF8String:kv]]; *eq = '='; // restore } } } // set body NSData *postData = [NSData dataWithBytes:data length:data_len]; [request setHTTPBody:postData]; // send NSError *error = nil; NSHTTPURLResponse *response = nil; NSData *resData = [SLSURLSession sendSynchronousRequest:request returningResponse:&response error:&error ]; if(response != nil){ int responseCode = (int)[response statusCode]; http_response->statusCode = responseCode; NSDictionary *fields = [response allHeaderFields]; NSString *timeVal = fields[@"x-log-time"]; if ([timeVal length] != 0) { NSInteger serverTime = [timeVal integerValue]; if (serverTime > 1500000000 && serverTime < 4294967294) { [TimeUtils updateServerTime:serverTime]; } } if (responseCode != 200) { NSString *res = [[NSString alloc] initWithData:resData encoding:NSUTF8StringEncoding]; strncpy(http_response->requestID, res.length > 0 ? [res UTF8String] : "", request_id_len); SLSLog(@"%ld %@ %@", [response statusCode], [response allHeaderFields], res); } else { NSString *requestId = fields[@"x-log-requestid"]; strncpy(http_response->requestID, requestId.length > 0 ? [requestId UTF8String] : "", request_id_len); } return responseCode; } else { http_response->statusCode = -1; strcpy(http_response->requestID, ""); if(error != nil){ NSString *errorMessage = [NSString stringWithFormat:@"domain: %@, code: %ld, description: %@", error.domain, (long)error.code, error.localizedDescription]; SLSLog(@"os_http_post error: %@", errorMessage); strncpy(http_response->errorMessage, [errorMessage UTF8String], error_message_len); if (error.code == kCFURLErrorUserCancelledAuthentication) { return 401; } if (error.code == kCFURLErrorBadServerResponse) { return 500; } } return -1; } } static char* nsstring_to_char(NSString *str) { NSUInteger len = [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1; char cStr [len]; [str getCString:cStr maxLength:len encoding:NSUTF8StringEncoding]; return strdup(cStr); } + (void)load{ log_set_http_post_func(os_http_post); } - (id) initWithEndpoint:(NSString *) endpoint project:(NSString *)project logstore:(NSString *)logstore { if (self = [super init]) { self = [self initWithEndpoint:endpoint project:project logstore:logstore accessKeyID:nil accessKeySecret:nil]; } return self; } - (id) initWithEndpoint:(NSString *) endpoint project:(NSString *)project logstore:(NSString *)logstore accessKeyID:(NSString *)accessKeyID accessKeySecret:(NSString *)accessKeySecret { if (self = [super init]) { self = [self initWithEndpoint:endpoint project:project logstore:logstore accessKeyID:accessKeyID accessKeySecret:accessKeySecret securityToken:nil]; } return self; } - (id) initWithEndpoint:(NSString *) endpoint project:(NSString *)project logstore:(NSString *)logstore accessKeyID:(NSString *)accessKeyID accessKeySecret:(NSString *)accessKeySecret securityToken:(NSString *)securityToken { if (self = [super init]) { self->config = create_log_producer_config(); self->config->user_params = (__bridge_retained void *)(self); #if SLS_HOST_MAC log_producer_config_set_source(self->config, "macOS"); #elif SLS_HOST_TV log_producer_config_set_source(self->config, "tvOS"); #else log_producer_config_set_source(self->config, "iOS"); #endif log_producer_config_set_packet_timeout(self->config, 3000); log_producer_config_set_packet_log_count(self->config, 1024); log_producer_config_set_packet_log_bytes(self->config, 1024*1024); log_producer_config_set_send_thread_count(self->config, 1); log_producer_config_set_drop_unauthorized_log(self->config, 0); log_producer_config_set_drop_delay_log(self->config, 0); log_set_get_time_unix_func(time_func); log_set_http_header_inject_func(sls_ios_http_header_inject_func); log_set_http_header_release_inject_func(sls_ios_http_header_release_inject_func); [self setHttpHeaderInjector:^NSArray<NSString *> *(NSArray<NSString *> *srcHeaders) { return [SLSHttpHeader getHeaders:srcHeaders, nil]; }]; [self setEndpoint:endpoint]; [self setProject:project]; [self setLogstore:logstore]; [self setAccessKeyId:accessKeyID]; [self setAccessKeySecret:accessKeySecret]; if ([securityToken length] != 0) { [self ResetSecurityToken:accessKeyID accessKeySecret:accessKeySecret securityToken:securityToken]; } } return self; } void sls_ios_http_header_inject_func(log_producer_config *config, char **src_headers, int src_count, char **dest_headers, int *dest_count) { NSMutableArray<NSString *> *headers = [NSMutableArray array]; for (int i = 0; i < src_count; i ++) { char *kv = src_headers[i]; if (NULL == kv) { continue; } char *eq = strchr(kv, ':'); if (NULL == eq || eq == kv || eq[1] == 0) { continue; } *eq = 0; [headers addObject:[NSString stringWithUTF8String:kv]]; [headers addObject:[NSString stringWithUTF8String:(eq+1)]]; } LogProducerConfig *producer = (__bridge LogProducerConfig *)(config->user_params); NSArray<NSString *> *injectedHeaders = producer->_injector(headers); if(nil == injectedHeaders || injectedHeaders.count == 0) { return; } NSUInteger count = injectedHeaders.count / 2; for (int i = 0; i < count; i ++) { const char *key = [[injectedHeaders objectAtIndex:2*i] UTF8String]; const char *value = [[injectedHeaders objectAtIndex:2*i+1] UTF8String]; unsigned long len = strlen(key) + strlen(value) + strlen(":") + 1; // dynamic alloc 'len' of char* for reduce mem cost char *kv = (char *) malloc(sizeof(char) * len); memset(kv, 0, sizeof(char) * len); strcat(kv, key); strcat(kv, ":"); strcat(kv, value); dest_headers[i] = kv; (*dest_count)++; } } void sls_ios_http_header_release_inject_func(log_producer_config *config, char **dest_headers, int dest_count) { if (0 == dest_count) { return; } for (int i = 0; i < dest_count; i ++) { free(dest_headers[i]); } } - (void) setHttpHeaderInjector: (SLSHttpHeaderInjector) injector { _injector = injector; } unsigned int time_func() { NSInteger timeInMillis = [TimeUtils getTimeInMilliis]; return (unsigned int) timeInMillis; } - (void)setEndpoint:(NSString *)endpoint { if (endpoint.length > 0 && ![[endpoint lowercaseString] hasPrefix:@"http"]) { endpoint = [NSString stringWithFormat:@"https://%@", endpoint]; } self->endpoint = endpoint; log_producer_config_set_endpoint(self->config, [endpoint UTF8String]); } - (NSString *)getEndpoint { return self->endpoint; } - (void)setProject:(NSString *)project { self->project = project; log_producer_config_set_project(self->config, [project UTF8String]); } - (NSString *)getProject { return self->project; } - (void)setLogstore:(NSString *)logstore { self->logstore = logstore; log_producer_config_set_logstore(self->config, [logstore UTF8String]); } - (NSString *) getLogStore { return self->logstore; } - (void)SetTopic:(NSString *) topic { const char *topicChar=[topic UTF8String]; log_producer_config_set_topic(self->config, topicChar); } - (void)SetSource:(NSString *)source { const char *sourceChar = [source UTF8String]; log_producer_config_set_source(self->config, sourceChar); } - (void)AddTag:(NSString *) key value:(NSString *)value { const char *keyChar=[key UTF8String]; const char *valueChar=[value UTF8String]; log_producer_config_add_tag(self->config, keyChar, valueChar); } - (void)SetPacketLogBytes:(int) num { log_producer_config_set_packet_log_bytes(self->config, num); } - (void)SetPacketLogCount:(int) num { log_producer_config_set_packet_log_count(self->config, num); } - (void)SetPacketTimeout:(int) num { log_producer_config_set_packet_timeout(self->config, num); } - (void)SetMaxBufferLimit:(int) num { log_producer_config_set_max_buffer_limit(self->config, num); } - (void)SetSendThreadCount:(int) num { if (_enablePersistent && 1 != num) { num = 1; } log_producer_config_set_send_thread_count(self->config, num); } - (void)SetPersistent:(int) num { _enablePersistent = 1 == num; log_producer_config_set_persistent(self->config, num); if (_enablePersistent) { [self SetSendThreadCount:1]; } } - (void)SetPersistentFilePath:(NSString *) path { const char *pathChar=[path UTF8String]; log_producer_config_set_persistent_file_path(self->config, pathChar); } - (void)SetPersistentForceFlush:(int) num { log_producer_config_set_persistent_force_flush(self->config, num); } - (void)SetPersistentMaxFileCount:(int ) num { log_producer_config_set_persistent_max_file_count(self->config, num); } - (void)SetPersistentMaxFileSize:(int) num { log_producer_config_set_persistent_max_file_size(self->config, num); } - (void)SetPersistentMaxLogCount:(int) num { log_producer_config_set_persistent_max_log_count(self->config, num); } - (void)SetUsingHttp:(int) num; { log_producer_config_set_using_http(self->config, num); } - (void)SetNetInterface:(NSString *) netInterface; { const char *netInterfaceChar=[netInterface UTF8String]; log_producer_config_set_net_interface(self->config, netInterfaceChar); } - (void)SetConnectTimeoutSec:(int) num; { log_producer_config_set_connect_timeout_sec(self->config, num); } - (void)SetSendTimeoutSec:(int) num; { log_producer_config_set_send_timeout_sec(self->config, num); } - (void)SetDestroyFlusherWaitSec:(int) num; { log_producer_config_set_destroy_flusher_wait_sec(self->config, num); } - (void)SetDestroySenderWaitSec:(int) num; { log_producer_config_set_destroy_sender_wait_sec(self->config, num); } - (void)SetCompressType:(int) num; { log_producer_config_set_compress_type(self->config, num); } - (void)SetNtpTimeOffset:(int) num; { log_producer_config_set_ntp_time_offset(self->config, num); } - (void)SetMaxLogDelayTime:(int) num; { log_producer_config_set_max_log_delay_time(self->config, num); } - (void)SetDropDelayLog:(int) num; { log_producer_config_set_drop_delay_log(self->config, num); } - (void)SetDropUnauthorizedLog:(int) num; { log_producer_config_set_drop_unauthorized_log(self->config, num); } - (void)SetGetTimeUnixFunc:(unsigned int (*)()) f; { log_set_get_time_unix_func(f); } - (int)IsValid; { return log_producer_config_is_valid(self->config); } - (int)IsEnabled; { return log_producer_persistent_config_is_enabled(self->config); } - (void)setAccessKeyId:(NSString *)accessKeyId { log_producer_config_set_access_id(self->config, [accessKeyId UTF8String]); } - (void)setAccessKeySecret:(NSString *)accessKeySecret { log_producer_config_set_access_key(self->config, [accessKeySecret UTF8String]); } - (void) setUseWebtracking: (BOOL) enable { log_producer_config_set_use_webtracking(self->config, enable ? 1 : 0); } - (void)ResetSecurityToken:(NSString *) accessKeyID accessKeySecret:(NSString *)accessKeySecret securityToken:(NSString *)securityToken { if ([accessKeyID length] == 0 || [accessKeySecret length] == 0 || [securityToken length] == 0) { return; } const char *accessKeyIDChar=[accessKeyID UTF8String]; const char *accessKeySecretChar=[accessKeySecret UTF8String]; const char *securityTokenChar=[securityToken UTF8String]; log_producer_config_reset_security_token(self->config, accessKeyIDChar, accessKeySecretChar, securityTokenChar); } + (void)Debug { aos_log_set_level(AOS_LOG_DEBUG); } @end