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