├── .gitignore
├── CHANGELOG.md
├── CMakeLists.txt
├── LICENSE
├── README.md
├── performance.md
├── sample
├── CMakeLists.txt
├── log_config.c
├── log_config.h
├── log_post_logs_sample.c
├── log_producer_benchmark.c
├── log_producer_sample.c
└── video_frame_producer_sample.c
├── save_send_buffer.md
└── src
├── hmac-sha.c
├── hmac-sha.h
├── inner_log.c
├── inner_log.h
├── log_api.c
├── log_api.h
├── log_builder.c
├── log_builder.h
├── log_define.h
├── log_inner_include.h
├── log_multi_thread.h
├── log_producer_client.c
├── log_producer_client.h
├── log_producer_common.c
├── log_producer_common.h
├── log_producer_config.c
├── log_producer_config.h
├── log_producer_manager.c
├── log_producer_manager.h
├── log_producer_sender.c
├── log_producer_sender.h
├── log_queue.c
├── log_queue.h
├── log_util.c
├── log_util.h
├── lz4.c
├── lz4.h
├── md5.c
├── md5.h
├── sds.c
├── sds.h
├── sha1.c
├── sha1.h
├── sha256.c
├── sha256.h
├── zstd.c
└── zstd.h
/.gitignore:
--------------------------------------------------------------------------------
1 | # Mac OS X
2 | .DS_Store
3 |
4 | # CMake
5 | CMakeCache.txt
6 |
7 | build/
8 | .vscode/
9 | CMakeFiles
10 | Makefile
11 | cmake_install.cmake
12 | install_manifest.txt
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log (Producer Lite)
2 | ## 0.1.0 (2018-02-27)
3 | Producer Lite版本发布
4 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | PROJECT(log_c_sdk)
2 |
3 | CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
4 |
5 | set(CMAKE_VERSION 2.0.0)
6 |
7 | # default Release C / CXX flags
8 | set(CMAKE_C_FLAGS " -O3 -Wall -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE")
9 | set(CMAKE_CXX_FLAGS " -O3 -Wall -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE")
10 |
11 | set(CMAKE_C_FLAGS_DEBUG " -g -ggdb -O0 -Wall -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE")
12 | set(CMAKE_CXX_FLAGS_DEBUG " -g -ggdb -O0 -Wall -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE")
13 |
14 | set(CMAKE_C_FLAGS_RELEASE " -O3 -Wall -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE")
15 | set(CMAKE_CXX_FLAGS_RELEASE " -O3 -Wall -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE")
16 |
17 | set(CMAKE_C_FLAGS_MINSIZEREF " -Os -Wall -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE")
18 | set(CMAKE_CXX_FLAGS_MINSIZEREF " -Os -Wall -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE")
19 |
20 | set(CMAKE_C_FLAGS_RELWITHDEBINFO " -O2 -Wall -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE")
21 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO " -O2 -Wall -Werror -fpic -fPIC -D_LARGEFILE64_SOURCE")
22 |
23 | set(CMAKE_C_FLAGS_COVERAGE " ${CMAKE_C_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage")
24 | set(CMAKE_CXX_FLAGS_COVERAGE " ${CMAKE_C_FLAGS_DEBUG} -fprofile-arcs -ftest-coverag")
25 |
26 | set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/build/${CMAKE_BUILD_TYPE}/lib)
27 | set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/build/${CMAKE_BUILD_TYPE}/bin)
28 | set(CMAKE_C_OUTPUT_EXTENSION_REPLACE 1)
29 | set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)
30 |
31 | option(ADD_LOG_KEY_VALUE_FUN "ON for generating add log key&value functions" OFF)
32 | option(FEATURE_ZSTD_COMPRESS "support zstd compress type, disable to get smaller lib size" OFF)
33 |
34 | IF(ADD_LOG_KEY_VALUE_FUN)
35 | add_definitions(-DLOG_KEY_VALUE_FLAG)
36 | ENDIF(ADD_LOG_KEY_VALUE_FUN)
37 |
38 | if(FEATURE_ZSTD_COMPRESS)
39 | add_definitions(-DLOG_FEATURE_ZSTD_COMPRESS)
40 | endif(FEATURE_ZSTD_COMPRESS)
41 |
42 | #curl-config
43 | FIND_PROGRAM(CURL_CONFIG_BIN NAMES curl-config)
44 |
45 | IF (CURL_CONFIG_BIN)
46 | EXECUTE_PROCESS(
47 | COMMAND ${CURL_CONFIG_BIN} --libs
48 | OUTPUT_VARIABLE CURL_LIBRARIES
49 | OUTPUT_STRIP_TRAILING_WHITESPACE
50 | )
51 | ELSE()
52 | MESSAGE(FATAL_ERROR "Could not find curl-config")
53 | ENDIF()
54 |
55 | # Compile and link lib_log_c_sdk
56 | include_directories(${CURL_INCLUDE_DIR})
57 |
58 | aux_source_directory(src SRC_LIST)
59 |
60 |
61 | add_library(${CMAKE_PROJECT_NAME}_static STATIC ${SRC_LIST})
62 | INSTALL(TARGETS ${CMAKE_PROJECT_NAME}_static ARCHIVE DESTINATION lib)
63 |
64 | IF (APPLE)
65 | MESSAGE(STATUS "For mac os, skip build dynamic library")
66 | ELSE ()
67 | add_library(${CMAKE_PROJECT_NAME} SHARED ${SRC_LIST})
68 | target_compile_definitions(${CMAKE_PROJECT_NAME} PUBLIC BUILD_SHARED_LIB)
69 | set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES VERSION ${CMAKE_VERSION} SOVERSION ${CMAKE_VERSION})
70 | INSTALL(TARGETS ${CMAKE_PROJECT_NAME} LIBRARY DESTINATION lib)
71 | ENDIF ()
72 |
73 |
74 |
75 |
76 |
77 | file(GLOB HEADER_FILES src/*.h)
78 |
79 | INSTALL(FILES
80 | ${HEADER_FILES}
81 | DESTINATION include/log_c_sdk)
82 |
83 | add_subdirectory(sample)
84 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 Aliyun inc.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 日志服务C Producer是用纯C编写的日志采集客户端,提供更加精简的环境依赖以及更低的资源占用,试用于各类嵌入式/智能设备的日志采集。
2 |
3 | # 功能特点
4 |
5 | * 异步
6 | * 异步写入,客户端线程无阻塞
7 | * 聚合&压缩 上传
8 | * 支持按超时时间、日志数、日志size聚合数据发送
9 | * 支持lz4压缩
10 | * 支持上下文查询
11 | * 同一个客户端产生的日志在同一上下文中,支持查看某条日志前后相关日志
12 | * 并发发送
13 | * 支持可配置的线程池发送
14 | * 缓存
15 | * 支持缓存上线可设置
16 | * 超过上限后日志写入失败
17 | * 自定义标识
18 | * 日志上传时默认会带上ip
19 | * 支持设置自定义tag、topic
20 |
21 | # 功能优势
22 |
23 | * 客户端高并发写入:可配置的发送线程池,支持每秒数十万条日志写入,详情参见[性能测试](performance.md)。
24 | * 低资源消耗:每秒20W日志写入只消耗30% CPU;同时在低性能硬件(例如树莓派)上,每秒产生100条日志对资源基本无影响。详情参见[性能测试](performance.md)。
25 | * 客户端日志不落盘:数据产生后直接通过网络发往服务端。
26 | * 客户端计算与 I/O 逻辑分离:日志异步输出,不阻塞工作线程。
27 | * 可靠退出:程序退出时,会调用接口将日志持久化,待下次应用启动时将数据发送,保证数据可靠性。详情参见[程序可靠退出方案](save_send_buffer.md)。
28 |
29 | 在以上场景中,C Producer 会简化您程序开发的步骤,您无需关心日志采集细节实现、也不用担心日志采集会影响您的业务正常运行,大大降低数据采集门槛。
30 |
31 | # 与1.0版本(v1分支) C Producer对比
32 | ## 功能对比
33 | 相比1.0版本 C Producer,仅缺少以下功能:
34 | 1. 同一Producer只支持单个Client,不支持多Client设置
35 | 2. 不支持发送优先级设置
36 | 3. 不支持JSON方式的配置文件
37 | 4. 不提供日志相关宏定义包装
38 | 5. 不支持本地调试功能
39 |
40 | ## 性能对比
41 | 性能相对1.0版本 C Producer有30%以上提升。
42 |
43 | ## 资源占用对比
44 | 资源占用相比1.0版本 C Producer大大降低(详细请参考[性能测试](performance.md)):
45 | * 除去libcurl占用,运行期间内存占用80KB左右。
46 | * 编译后的动态库仅有65KB(strip后)
47 |
48 | # 分支选择
49 | C Producer根据不同的设备类型和使用场景做了非常多的定制工作,因此分为几个分支来支持不同的场景,请根据实际需求选择。
50 |
51 | |分支|状态|功能优势|建议使用场景|
52 | |--|--|--|--|
53 | | master | 可用 | 原lite分支,相比v1(1.0f)版本依赖、资源占用、性能等有大幅度提升,是目前SLS性能最强的Producer,推荐使用 | Linux服务器、嵌入式Linux |
54 | | live | 可用 | 主要功能和master版本一致,增加最多平台的编译支持,包括Windows、Mac、Android、IOS等 | 非master支持的环境 |
55 | | bricks | 可用 | 极致精简版本,binary和内存占用极低,但是功能非常弱,建议在资源非常受限的场景中使用 | 资源占用在10KB以内的场景,例如RTOS |
56 | | persistent | 可用 | 相比master增加本地缓存功能,目前用于Android、IOS移动端版本的Native实现,本地缓存功能开启后只能单线程发送,不建议服务端使用 | 建议直接使用Android、IOS官方SDK |
57 |
58 |
59 | * 注意:除以上分支外,不建议使用其他分支
60 |
61 | # 安装方法
62 | ### 下载Producer代码
63 | 您可以使用如下命令获取代码:
64 | ```shell
65 | git clone https://github.com/aliyun/aliyun-log-c-sdk.git
66 | ```
67 |
68 | ### 环境依赖
69 | 需要安装openssl
70 | C Producer使用curl进行网络操作,您需要确认这些库已经安装,并且将它们的头文件目录和库文件目录都加入到了项目中。
71 |
72 | #### libcurl下载以及安装
73 |
74 | libcurl建议 7.49.0 及以上版本
75 |
76 | 请从[这里](http://curl.haxx.se/download.html)下载,并参考[libcurl 安装指南](http://curl.haxx.se/docs/install.html)安装。典型的安装方式如下:
77 | ```shell
78 | ./configure
79 | make
80 | make install
81 | ```
82 |
83 | * 注意:
84 | - 执行./configure时默认是配置安装目录为/usr/local/,如果需要指定安装目录,请使用 ./configure --prefix=/your/install/path/
85 |
86 | #### LOG C SDK的安装
87 |
88 | 安装时请在cmake命令中指定第三方库头文件以及库文件的路径,典型的编译命令如下:
89 | ```shell
90 | cmake .
91 | make
92 | make install
93 | ```
94 |
95 |
96 | * 注意:
97 | - 执行cmake . 时默认会到/usr/local/下面去寻找curl的头文件和库文件。
98 | - 默认编译是Release类型,可以指定以下几种编译类型: Debug, Release, RelWithDebInfo和MinSizeRel,如果要使用Debug类型编译,则执行cmake . -DCMAKE_BUILD_TYPE=Debug
99 | - 如果您在安装curl时指定了安装目录,则需要在执行cmake时指定这些库的路径,比如:
100 | ```shell
101 | cmake . -DCURL_INCLUDE_DIR=/usr/local/include/curl/ -DCURL_LIBRARY=/usr/local/lib/libcurl.a
102 | ```
103 | - 如果要指定安装目录,则需要在cmake时增加: -DCMAKE_INSTALL_PREFIX=/your/install/path/usr/local/
104 |
105 | ## 使用
106 | 一个应用可创建多个producer,每个producer可单独配置目的地址、缓存大小、发送线程数、自定义标识、topic等信息。
107 |
108 | ### 配置参数
109 | 所有参数通过`log_producer_config`结构设置,支持设置的参数如下:
110 |
111 | | 参数 | 说明 | 取值 |
112 | | ------------------------ | ------------------------------------------------------------------------------------ | --------------------------------------- |
113 | | project | 日志服务project | string |
114 | | logstore | 日志服务logstore | string |
115 | | endpoint | 日志服务endpoint | string,以`http:`开头 |
116 | | access_id | 云账号 access id | string |
117 | | access_key | 云账号 access key | string |
118 | | topic | topic名 | string,非必须设置。 |
119 | | add_tag | 自定义的tag | key value 模式,非必须设置。 |
120 | | packet_timeout | 指定被缓存日志的发送超时时间,如果缓存超时,则会被立即发送。 | 整数形式,单位为毫秒。默认为3000。 |
121 | | packet_log_count | 指定每个缓存的日志包中包含日志数量的最大值。 | 整数形式,取值为1~4096。默认2048。 |
122 | | packet_log_bytes | 指定每个缓存的日志包的大小上限。 | 整数形式,取值为1~5242880,单位为字节。默认为 3 * 1024 * 1024。 |
123 | | max_buffer_limit | 指定单个Producer Client实例可以使用的内存的上限。 | 整数形式,单位为字节。默认为64 * 1024 * 1024。 |
124 | | log_queue_size | 缓存队列的最大长度,默认通过 max_buffer_limit/packet_log_bytes + 10 自动计算,可以手动设置以获得更大的队列大小。 | 整数形式,支持32-128000。默认值max_buffer_limit/packet_log_bytes + 10。 |
125 | | send_thread_count | 指定发送线程数量,用于发送数据到日志服务。 | 整数形式,默认0,为0时发送与内部Flush公用一个线程,若您每秒日志发送不超过100条,无需设置此参数。 |
126 | | net_interface | 网络发送绑定的网卡名 | 字符串,为空时表示自动选择可用网卡 |
127 | | connect_timeout_sec | 网络连接超时时间 | 整数,单位秒,默认为10 |
128 | | send_timeout_sec | 日志发送超时时间 | 整数,单位秒,默认为15 |
129 | | destroy_flusher_wait_sec | flusher线程销毁最大等待时间 | 整数,单位秒,默认为1 |
130 | | destroy_sender_wait_sec | sender线程池销毁最大等待时间 | 整数,单位秒,默认为1 |
131 | | compress_type | 压缩类型 | 枚举值,默认为lz4。 |
132 | ### 相关限制
133 | * C Producer销毁时,会尽可能将缓存中的数据发送出去,若您不对未发送的数据进行处理,则有一定概率丢失数据。处理方法参见[程序可靠退出方案](save_send_buffer.md)
134 | * C Producer销毁的最长时间可能为 `send_timeout_sec` + `destroy_flusher_wait_sec` + `destroy_sender_wait_sec`
135 | ### 样例代码
136 |
137 | 请参考`sample`目录中的`log_producer_sample.c`。
138 |
139 |
140 |
141 | ## C-Producer系列介绍
142 |
143 | 
144 |
145 | > 关于C Producer Library的更多内容参见目录:[https://yq.aliyun.com/articles/304602](https://yq.aliyun.com/articles/304602)
146 | 目前针对不同的环境(例如网络服务器、ARM设备、以及RTOS等设备)从大到小我们提供了3种方案:
147 |
148 |
149 | 
150 |
151 | 同时对于Producer我们进行了一系列的性能和资源优化,确保数据采集可以“塞”到任何IOT设备上,其中C Producer Bricks版本更是达到了极致的内存占用(库体积13KB,运行内存4KB以内)。
152 |
153 |
154 | 
155 |
156 |
157 | 使用C Producer系列的客户有: 百万日活的天猫精灵、小朋友们最爱的故事机火火兔、 遍布全球的码牛、钉钉路由器、 兼容多平台的视频播放器、 实时传输帧图像的摄像头等。
158 |
159 | 这些智能SDK每天DAU超百万,遍布在全球各地的设备上,一天传输百TB数据。关于C Producer Library 的细节可以参考这篇文章: [智能设备日志利器:嵌入式日志客户端(C Producer)发布](https://yq.aliyun.com/articles/304602)。
160 |
161 |
162 | 
163 |
164 |
165 | ### 数据采集全球加速
166 | IOT设备作为典型的“端”设备,通常都会部署在全国、甚至全球各地,部署区域的网络条件难以保证,这会对数据采集产生一个巨大的问题:数据采集受网络质量影响,可靠性难以保证。
167 |
168 | 针对以上问题,日志服务联合阿里云CDN推出了一款[全球数据上传自动加速](https://help.aliyun.com/document_detail/86817.html)方案:“基于阿里云CDN硬件资源,全球数据就近接入边缘节点,通过内部高速通道路由至LogHub,大大降低网络延迟和抖动 ”。
169 | 该方案有如下特点:
170 |
171 | * 全网边缘节点覆盖:全球1000+节点,国内700+节点,分布60多个国家和地区,覆盖六大洲
172 | * 智能路由技术:实时探测网络质量,自动根据运营商、网络等状况选择最近接入
173 | * 传输协议优化:CDN节点之间走私有协议、高效安全
174 | * 使用便捷:只需1分钟即可开通加速服务,只需切换到专属加速域名即可获得加速效果
175 |
176 | ## 
177 |
178 | 在我们的日志上传基准测试中,全球7个区域对比整体延时下降50%,在中东,欧洲、澳洲和新加坡等效果明显。除了平均延时下降外,整体稳定性也有较大提升(参见最下图,几乎没有任何抖动,而且超时请求基本为0)。确保无论在全球的何时何地,只要访问这个加速域名,就能够高效、便捷将数据采集到期望Region内。
179 |
180 | 关于全球采集加速的更多内容,可参考我们的文章:[数据采集新形态-全球加速](https://yq.aliyun.com/articles/620453) 。
181 |
182 |
183 | 
184 |
185 |
186 |
187 | 
--------------------------------------------------------------------------------
/performance.md:
--------------------------------------------------------------------------------
1 | # 服务端测试
2 | ## 环境
3 | ### 软硬件环境
4 | * CPU : Intel(R) Xeon(R) CPU E5-2682 v4 @ 2.50GHz
5 | * MEM : 64GB
6 | * OS : Linux version 2.6.32-220.23.2.ali1113.el5.x86_64
7 | * GCC : 4.1.2
8 | * c-producer:动态库 65K、静态库59K (测试使用静态库,编译后的binary 69KB,所有都是strip后)
9 |
10 | ### c-producer配置
11 | * 缓存:64MB
12 | * 聚合时间:3秒 (聚合时间、聚合数据包大小、聚合日志数任一满足即打包发送)
13 | * 聚合数据包大小:4MB
14 | * 聚合日志数:4096
15 | * 发送线程:16
16 | * 自定义tag : 5
17 |
18 | ### 日志样例
19 | 日志样例为2种
20 | 1. 10个键值对,总数据量约为700字节
21 | 1. 4个键值对,数据量约为200字节
22 |
23 | ## 测试结果
24 |
25 | | 发送速率(logs/s) | 平均每次log耗时(us) | 原始数据速率(KB/s) | cpu(%) | mem(MB) |
26 | | ---------------- | ---------------- | ------------------- | ------------------ | ------ |
27 | | 200000 | 1.08 | 84495.5 | 28.8 | 10.58 |
28 | | 100000 | 1.10 | 42247.8 | 14.6 | 8.10 |
29 | | 20000 | 1.09 | 8449.6 | 3.0 | 7.35 |
30 | | 10000 | 1.08 | 4224.7 | 1.6 | 5.12 |
31 | | 2000 | 1.20 | 844.9 | 0.2 | 3.58 |
32 | | 1000 | 1.19 | 463.9 | 0.1 | 3.31 |
33 | | 200 | 1.45(不准确) | 84.5 | 0.0? | 2.81 |
34 | | 100 | 1.70(不准确) | 42.2 | 0.0? | 2.82 |
35 |
36 | # 树莓派测试
37 | ## 软硬件环境
38 | ### 硬件环境
39 | * 型号:树莓派3B
40 | * CPU:Broadcom BCM2837 1.2GHz A53 64位(使用主机USB供电,被降频到600MHz)
41 | * 内存:1GB DDR2
42 | * 网络:百兆网卡(台式机本地网卡提供共享网络,台式机网络为无线网,网络质量不是很好,经常还有timeout)
43 |
44 | ### OS&软件
45 | * OS: Linux 4.9.41-v7+ #1023 SMP armv71 GNU/Linux
46 | * GCC:6.3.0 (Raspbian 6.3.0-18+rpi1)
47 | * c-producer:动态库 72K、静态库65K (测试使用静态库,编译后的binary 87KB,所有都是strip后)
48 |
49 | ### c-producer配置
50 | * 缓存:10MB
51 | * 聚合时间:3秒 (聚合时间、聚合数据包大小、聚合日志数任一满足即打包发送)
52 | * 聚合数据包大小:1MB
53 | * 聚合日志数:1000
54 | * 发送线程:4
55 | * 自定义tag : 5
56 |
57 | ### 日志样例
58 | 日志样例为2种
59 | 1. 10个键值对,总数据量约为700字节
60 | 1. 4个键值对,数据量约为200字节
61 |
62 | ## 测试结果
63 |
64 | | 发送速率(logs/s) | 平均每次log耗时(us) | 原始数据速率(KB/s) | cpu(%) | mem(MB) |
65 | | ---------------- | ---------------- | ------------------- | ------------------ | ------ |
66 | | 20000 | 8.8 | 8449.6 | 31.5 | 5.46 |
67 | | 10000 | 9.3 | 4224.7 | 15.8 | 5.1 |
68 | | 2000 | 9.9 | 844.9 | 2.9 | 3.38 |
69 | | 1000 | 10.5 | 463.9 | 1.4 | 3.11 |
70 | | 200 | 10.1 | 84.5 | 0.3 | 2.41 |
71 | | 100 | 10.6 | 42.2 | 0.1 | 3.01 |
72 | | 20 | 10.3 | 8.4 | 0.0? | 2.96 |
73 | | 10 | 11.1 | 4.2 | 0.0? | 2.80 |
74 |
75 | # 总结
76 | * 服务器端的测试中,C Producer可以轻松到达90M/s的发送速度,每秒上传日志20W,占用CPU只有70%,内存12M
77 | * 在树莓派的测试中,由于CPU的频率只有600MHz,性能差不多是服务器的1/10左右,最高每秒可发送2W条日志
78 | * 服务器在200条/s、树莓派在20条/s的时候,发送数据对于cpu基本无影响(降低到0.01%以内)
79 | * 客户线程发送一条数据(输出一条log)的平均耗时为:服务器1.1us、树莓派10us左右
80 |
81 |
82 | # 附件
83 |
84 | ## 日志样例
85 | ```
86 | Interconnection:Grafana and JDBC/SQL92
87 | LogHub:Real-time log collection and consumption
88 | Search/Analytics:Query and real-time analysis
89 | Visualized:dashboard and report functions
90 | __tag__:__pack_id__:F20B4E7940C80975-0
91 | __tag__:tag_1:val_1
92 | __tag__:tag_2:val_2
93 | __tag__:tag_3:val_3
94 | __tag__:tag_4:val_4
95 | __tag__:tag_5:val_5
96 | __topic__:test_topic
97 | ```
98 |
99 | ```
100 | __tag__:__pack_id__:F20B4E7940C80975-0
101 | __tag__:tag_1:val_1
102 | __tag__:tag_2:val_2
103 | __tag__:tag_3:val_3
104 | __tag__:tag_4:val_4
105 | __tag__:tag_5:val_5
106 | __topic__:test_topic
107 | content_key_1:1abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+
108 | content_key_2:2abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+
109 | content_key_3:3abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+
110 | content_key_4:4abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+
111 | content_key_5:5abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+
112 | content_key_6:6abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+
113 | content_key_7:7abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+
114 | content_key_8:8abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+
115 | content_key_9:9abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+
116 | index:0
117 | ```
118 |
119 | ## 测试代码
120 | ```
121 | #include "inner_log.h"
122 | #include "log_api.h"
123 | #include "log_producer_config.h"
124 | #include "log_producer_client.h"
125 | #include
126 | #include
127 | #include
128 | #include "log_multi_thread.h"
129 |
130 |
131 | void on_log_send_done(const char * config_name, log_producer_result result, size_t log_bytes, size_t compressed_bytes, const char * req_id, const char * message)
132 | {
133 | if (result == LOG_PRODUCER_OK)
134 | {
135 | if (aos_log_level == AOS_LOG_DEBUG)
136 | {
137 | printf("send success, config : %s, result : %d, log bytes : %d, compressed bytes : %d, request id : %s \n",
138 | config_name, (result),
139 | (int)log_bytes, (int)compressed_bytes, req_id);
140 | }
141 |
142 | }
143 | else
144 | {
145 | printf("send fail, config : %s, result : %d, log bytes : %d, compressed bytes : %d, request id : %s, error message : %s\n",
146 | config_name, (result),
147 | (int)log_bytes, (int)compressed_bytes, req_id, message);
148 | }
149 |
150 | }
151 |
152 | log_producer * create_log_producer_wrapper(on_log_producer_send_done_function on_send_done)
153 | {
154 | log_producer_config * config = create_log_producer_config();
155 | // endpoint list: https://help.aliyun.com/document_detail/29008.html
156 | log_producer_config_set_endpoint(config, "${your_endpoint}");
157 | log_producer_config_set_project(config, "${your_project}");
158 | log_producer_config_set_logstore(config, "${your_logstore}");
159 | log_producer_config_set_access_id(config, "${your_access_key_id}");
160 | log_producer_config_set_access_key(config, "${your_access_key_secret}");
161 |
162 | // if you do not need topic or tag, comment it
163 | log_producer_config_set_topic(config, "test_topic");
164 | log_producer_config_add_tag(config, "tag_1", "val_1");
165 | log_producer_config_add_tag(config, "tag_2", "val_2");
166 | log_producer_config_add_tag(config, "tag_3", "val_3");
167 | log_producer_config_add_tag(config, "tag_4", "val_4");
168 | log_producer_config_add_tag(config, "tag_5", "val_5");
169 |
170 | // set resource params
171 | log_producer_config_set_packet_log_bytes(config, 4*1024*1024);
172 | log_producer_config_set_packet_log_count(config, 4096);
173 | log_producer_config_set_packet_timeout(config, 3000);
174 | log_producer_config_set_max_buffer_limit(config, 64*1024*1024);
175 |
176 | // set send thread
177 | log_producer_config_set_send_thread_count(config, 16);
178 |
179 | return create_log_producer(config, on_send_done);
180 | }
181 |
182 | void log_producer_post_logs(int logsPerSecond, int sendSec)
183 | {
184 | //aos_log_level = AOS_LOG_DEBUG;
185 | if (log_producer_env_init(LOG_GLOBAL_ALL) != LOG_PRODUCER_OK) {
186 | exit(1);
187 | }
188 |
189 | log_producer * producer = create_log_producer_wrapper(on_log_send_done);
190 | if (producer == NULL)
191 | {
192 | printf("create log producer by config file fail \n");
193 | exit(1);
194 | }
195 |
196 | log_producer_client * client = get_log_producer_client(producer, NULL);
197 | if (client == NULL)
198 | {
199 | printf("create log producer client by config file fail \n");
200 | exit(1);
201 | }
202 |
203 |
204 | int32_t i = 0;
205 | int32_t totalTime = 0;
206 | for (i = 0; i < sendSec; ++i)
207 | {
208 | int64_t startTime = GET_TIME_US();
209 | int j = 0;
210 | for (; j < logsPerSecond; ++j)
211 | {
212 | char indexStr[32];
213 | sprintf(indexStr, "%d", i * logsPerSecond + j);
214 | log_producer_client_add_log(client, 20, "content_key_1", "1abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
215 | "content_key_2", "2abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
216 | "content_key_3", "3abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
217 | "content_key_4", "4abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
218 | "content_key_5", "5abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
219 | "content_key_6", "6abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
220 | "content_key_7", "7abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
221 | "content_key_8", "8abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
222 | "content_key_9", "9abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
223 | "index", indexStr);
224 |
225 | log_producer_result rst = log_producer_client_add_log(client, 8, "LogHub", "Real-time log collection and consumption",
226 | "Search/Analytics", "Query and real-time analysis",
227 | "Visualized", "dashboard and report functions",
228 | "Interconnection", "Grafana and JDBC/SQL92");
229 | if (rst != LOG_PRODUCER_OK)
230 | {
231 | printf("add log error %d \n", rst);
232 | }
233 | }
234 | int64_t endTime = GET_TIME_US();
235 | aos_error_log("Done : %d %d time %f us \n", i, logsPerSecond, (float)(endTime - startTime) * 1.0 / logsPerSecond / 2);
236 | totalTime += endTime - startTime;
237 | if (endTime - startTime < 1000000)
238 | {
239 | usleep(1000000 - (endTime - startTime));
240 | }
241 | }
242 | aos_error_log("Total done : %f us, avg %f us", (float)totalTime / 180, (float)totalTime / (180 * logsPerSecond * 2));
243 | //sleep(10);
244 |
245 | destroy_log_producer(producer);
246 |
247 | log_producer_env_destroy();
248 | }
249 |
250 | int main(int argc, char *argv[])
251 | {
252 | int logsPerSec = 100;
253 | int sendSec = 180;
254 | if (argc == 3)
255 | {
256 | logsPerSec = atoi(argv[1]);
257 | sendSec = atoi(argv[2]);
258 | }
259 | log_producer_post_logs(logsPerSec, sendSec);
260 | return 0;
261 | }
262 |
263 |
264 | ```
--------------------------------------------------------------------------------
/sample/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | project (log_c_sdk_sample)
2 |
3 | include_directories(${CMAKE_SOURCE_DIR})
4 |
5 | set(POST_LOGS_SOURCE_FILES log_config.c
6 | log_post_logs_sample.c)
7 |
8 |
9 | set(PRODUCER_SAMPLE_SOURCE_FILES log_producer_sample.c)
10 |
11 | set(PRODUCER_BENCHMARK_SOURCE_FILES log_producer_benchmark.c)
12 |
13 | set(PRODUCER_FRAME_SOURCE_FILES video_frame_producer_sample.c)
14 |
15 | include_directories (${CURL_INCLUDE_DIR})
16 | include_directories ("${CMAKE_SOURCE_DIR}/src")
17 |
18 | find_library(CURL_LIBRARY curl)
19 | find_library(PTHREAD_LIBRARY pthread)
20 | find_library(RT_LIBRARY rt)
21 | find_library(M_LIBRARY m)
22 | find_library(SSL_LIBRARY ssl)
23 | find_library(CRYPTO_LIBRARY crypto)
24 | find_library(ZLIB_LIBRARY z)
25 | find_library(DL_LIBRARY dl)
26 |
27 | function(_TARGET_SAMPLE_LIBRARIES SAMPLE_BIN_NAME SOURCE_FILES)
28 | add_executable(${SAMPLE_BIN_NAME} ${SOURCE_FILES})
29 | target_link_libraries(${SAMPLE_BIN_NAME} log_c_sdk_static)
30 | target_link_libraries(${SAMPLE_BIN_NAME} ${CURL_LIBRARY})
31 | target_link_libraries(${SAMPLE_BIN_NAME} ${PTHREAD_LIBRARY})
32 | target_link_libraries(${SAMPLE_BIN_NAME} ${M_LIBRARY})
33 | target_link_libraries(${SAMPLE_BIN_NAME} ${DL_LIBRARY})
34 | target_link_libraries(${SAMPLE_BIN_NAME} ${SSL_LIBRARY})
35 | target_link_libraries(${SAMPLE_BIN_NAME} ${CRYPTO_LIBRARY})
36 | target_link_libraries(${SAMPLE_BIN_NAME} ${ZLIB_LIBRARY})
37 | endfunction()
38 |
39 | _TARGET_SAMPLE_LIBRARIES(log_producer_sample "${PRODUCER_SAMPLE_SOURCE_FILES}")
40 |
41 | _TARGET_SAMPLE_LIBRARIES(log_post_logs_sample "${POST_LOGS_SOURCE_FILES}")
42 |
43 | _TARGET_SAMPLE_LIBRARIES(log_producer_benchmark "${PRODUCER_BENCHMARK_SOURCE_FILES}")
44 |
45 | _TARGET_SAMPLE_LIBRARIES(video_frame_producer_sample "${PRODUCER_FRAME_SOURCE_FILES}")
--------------------------------------------------------------------------------
/sample/log_config.c:
--------------------------------------------------------------------------------
1 | #include "log_config.h"
2 |
3 | // your endpoint
4 | const char LOG_ENDPOINT[] = "";
5 | // your access key id
6 | const char ACCESS_KEY_ID[] = "";
7 | // your access key secret
8 | const char ACCESS_KEY_SECRET[] = "";
9 | // your project name
10 | const char PROJECT_NAME[] = "";
11 | // your logstore name
12 | const char LOGSTORE_NAME[] = "";
13 |
--------------------------------------------------------------------------------
/sample/log_config.h:
--------------------------------------------------------------------------------
1 | #ifndef LOG_TEST_CONFIG_H
2 | #define LOG_TEST_CONFIG_H
3 |
4 | #include "log_define.h"
5 |
6 | LOG_CPP_START
7 |
8 | extern const char LOG_ENDPOINT[];
9 | extern const char ACCESS_KEY_ID[];
10 | extern const char ACCESS_KEY_SECRET[];
11 | extern const char PROJECT_NAME[];
12 | extern const char LOGSTORE_NAME[];
13 |
14 | LOG_CPP_END
15 |
16 | #endif
17 |
--------------------------------------------------------------------------------
/sample/log_post_logs_sample.c:
--------------------------------------------------------------------------------
1 | #include "log_util.h"
2 | #include "log_api.h"
3 | #include "log_config.h"
4 | #include
5 | #include
6 |
7 | // @note this sample is just for SDK's developer, 99% of cases you should use log_producer_sample
8 |
9 | #define POST_LOG_COUNT 10
10 | #define POST_LOG_CONTENT_PAIRS 15
11 |
12 | void post_logs_with_http_cont_lz4_log_option()
13 | {
14 |
15 | sls_log_init(LOG_GLOBAL_ALL);
16 |
17 | int i = 0;
18 | for (i = 0; i < 10; ++i)
19 | {
20 | log_group_builder *bder = log_group_create();
21 | add_source(bder, "10.230.201.117", sizeof("10.230.201.117"));
22 | add_topic(bder, "post_logs_with_http_cont_lz4_log_option",
23 | sizeof("post_logs_with_http_cont_lz4_log_option"));
24 |
25 | add_tag(bder, "taga_key", strlen("taga_key"), "taga_value",
26 | strlen("taga_value"));
27 | add_tag(bder, "tagb_key", strlen("tagb_key"), "tagb_value",
28 | strlen("tagb_value"));
29 | add_pack_id(bder, "123456789ABC", strlen("123456789ABC"), 0);
30 |
31 | int x;
32 | for (x = 0; x < POST_LOG_COUNT; x++)
33 | {
34 | char * keys[POST_LOG_CONTENT_PAIRS];
35 | char * values[POST_LOG_CONTENT_PAIRS];
36 | size_t key_lens[POST_LOG_CONTENT_PAIRS];
37 | size_t val_lens[POST_LOG_CONTENT_PAIRS];
38 | int j = 0;
39 | for (j = 0; j < POST_LOG_CONTENT_PAIRS; j++)
40 | {
41 |
42 | keys[j] = (char *)malloc(64);
43 | sprintf(keys[j], "key_%d", x * j);
44 | values[j] = (char *)malloc(64);
45 | sprintf(values[j], "value_%d", 2 * j);
46 | key_lens[j] = strlen(keys[j]);
47 | val_lens[j] = strlen(values[j]);
48 | }
49 | add_log_full(bder, time(NULL), POST_LOG_CONTENT_PAIRS, keys, key_lens, values, val_lens);
50 | for (j = 0; j < POST_LOG_CONTENT_PAIRS; j++)
51 | {
52 | free(keys[j]);
53 | free(values[j]);
54 | }
55 | }
56 |
57 | // if you want to use this functions, add `-DADD_LOG_KEY_VALUE_FUN=ON` for cmake. eg `cmake . -DADD_LOG_KEY_VALUE_FUN=ON`
58 | #ifdef LOG_KEY_VALUE_FLAG
59 | for (x = 0; x < POST_LOG_COUNT; x++)
60 | {
61 | int j = 0;
62 | add_log_begin(bder);
63 | for (j = 0; j < POST_LOG_CONTENT_PAIRS; j++)
64 | {
65 | char key[64];
66 | sprintf(key, "add_key_%d", x * j);
67 | char value[64];
68 | sprintf(value, "add_value_%d", 2 * j);
69 | add_log_key_value(bder, key, strlen(key), value, strlen(value));
70 | if (j == POST_LOG_CONTENT_PAIRS / 2)
71 | {
72 | add_log_time(bder, time(NULL));
73 | }
74 | }
75 |
76 | add_log_end(bder);
77 | }
78 |
79 | #endif
80 |
81 | log_post_option option;
82 | memset(&option, 0, sizeof(log_post_option));
83 | option.interface = NULL;
84 | option.connect_timeout = 15;
85 | option.operation_timeout = 15;
86 | option.compress_type = i % 2 == 0;
87 | lz4_log_buf *pLZ4Buf = NULL;
88 | if (option.compress_type == 1)
89 | {
90 | printf("post log with lz4 \n");
91 | pLZ4Buf = serialize_to_proto_buf_with_malloc_lz4(bder);
92 | }
93 | else
94 | {
95 | printf("post log with no compress \n");
96 | pLZ4Buf = serialize_to_proto_buf_with_malloc_no_compress(bder);
97 | }
98 |
99 | log_group_destroy(bder);
100 | if (pLZ4Buf == NULL)
101 | {
102 | printf("serialize_to_proto_buf_with_malloc_lz4 failed\n");
103 | exit(1);
104 | }
105 | post_log_result * rst = post_logs_from_lz4buf(LOG_ENDPOINT, ACCESS_KEY_ID,
106 | ACCESS_KEY_SECRET, NULL,
107 | PROJECT_NAME, LOGSTORE_NAME,
108 | pLZ4Buf, &option,
109 | AUTH_VERSION_1, NULL);
110 | printf("result %d %d \n", i, rst->statusCode);
111 | if (rst->errorMessage != NULL)
112 | {
113 | printf("error message %s \n", rst->errorMessage);
114 | }
115 |
116 | if (rst->requestID != NULL)
117 | {
118 | printf("requestID %s \n", rst->requestID);
119 | }
120 | post_log_result_destroy(rst);
121 | free_lz4_log_buf(pLZ4Buf);
122 | }
123 |
124 | sls_log_destroy();
125 | }
126 |
127 | // @note this sample is just for SDK's developer, 99% of cases you should use log_producer_sample
128 | int main(int argc, char *argv[])
129 | {
130 | post_logs_with_http_cont_lz4_log_option();
131 | return 0;
132 | }
133 |
--------------------------------------------------------------------------------
/sample/log_producer_benchmark.c:
--------------------------------------------------------------------------------
1 | //
2 | // Created by ZhangCheng on 26/12/2017.
3 | //
4 |
5 | #include "inner_log.h"
6 | #include "log_api.h"
7 | #include "log_producer_config.h"
8 | #include "log_producer_client.h"
9 | #include
10 | #include
11 | #include
12 | #include "log_multi_thread.h"
13 |
14 | int producer_send_thread_count = 16;
15 |
16 | void builder_speed_test(int32_t logsPerGroup)
17 | {
18 | int32_t startTime = time(NULL);
19 | int32_t count = 0;
20 | for (; count < 1000000; ++count)
21 | {
22 | log_group_builder* bder = log_group_create();
23 | add_source(bder,"mSource",sizeof("mSource"));
24 | add_topic(bder,"mTopic", sizeof("mTopic"));
25 |
26 | add_tag(bder, "taga_key", strlen("taga_key"), "taga_value", strlen("taga_value"));
27 | add_tag(bder, "tagb_key", strlen("tagb_key"), "tagb_value", strlen("tagb_value"));
28 | add_pack_id(bder, "123456789ABC", strlen("123456789ABC"), 0);
29 |
30 | int i = 0;
31 | for (; i < logsPerGroup; ++i)
32 | {
33 | char * keys[] = {
34 | "content_key_1",
35 | "content_key_1",
36 | "content_key_1",
37 | "content_key_1",
38 | "content_key_1",
39 | "content_key_1",
40 | "content_key_1",
41 | "content_key_1",
42 | "content_key_1",
43 | "content_key_1"
44 | };
45 | char * vals[] = {
46 | "1abcdefghijklmnopqrstuvwxyz01234567891abcdefghijklmnopqrstuvwxyz01234567891abcdefghijklmnopqrstuvwxyz01234567891abcdefghijklmnopqrstuvwxyz0123456789",
47 | "2abcdefghijklmnopqrstuvwxyz0123456789",
48 | "2abcdefghijklmnopqrstuvwxyz0123456789",
49 | "2abcdefghijklmnopqrstuvwxyz0123456789",
50 | "2abcdefghijklmnopqrstuvwxyz0123456789",
51 | "2abcdefghijklmnopqrstuvwxyz0123456789",
52 | "2abcdefghijklmnopqrstuvwxyz0123456789",
53 | "2abcdefghijklmnopqrstuvwxyz0123456789",
54 | "2abcdefghijklmnopqrstuvwxyz0123456789",
55 | "xxxxxxxxxxxxxxxxxxxxx"
56 | };
57 | size_t key_lens[] = {
58 | strlen("content_key_1"),
59 | strlen("content_key_1"),
60 | strlen("content_key_1"),
61 | strlen("content_key_1"),
62 | strlen("content_key_1"),
63 | strlen("content_key_1"),
64 | strlen("content_key_1"),
65 | strlen("content_key_1"),
66 | strlen("content_key_1"),
67 | strlen("index")
68 | };
69 | size_t val_lens[] = {
70 | strlen("1abcdefghijklmnopqrstuvwxyz01234567891abcdefghijklmnopqrstuvwxyz01234567891abcdefghijklmnopqrstuvwxyz01234567891abcdefghijklmnopqrstuvwxyz0123456789"),
71 | strlen("2abcdefghijklmnopqrstuvwxyz0123456789"),
72 | strlen("2abcdefghijklmnopqrstuvwxyz0123456789"),
73 | strlen("2abcdefghijklmnopqrstuvwxyz0123456789"),
74 | strlen("2abcdefghijklmnopqrstuvwxyz0123456789"),
75 | strlen("2abcdefghijklmnopqrstuvwxyz0123456789"),
76 | strlen("2abcdefghijklmnopqrstuvwxyz0123456789"),
77 | strlen("2abcdefghijklmnopqrstuvwxyz0123456789"),
78 | strlen("2abcdefghijklmnopqrstuvwxyz0123456789"),
79 | strlen("xxxxxxxxxxxxxxxxxxxxx")
80 | };
81 | add_log_full(bder, (uint32_t)time(NULL), 10, (char **)keys, (size_t *)key_lens, (char **)vals, (size_t *)val_lens);
82 | }
83 | log_buf buf = serialize_to_proto_buf_with_malloc(bder);
84 |
85 | if (count % 1000 == 0)
86 | {
87 | int32_t nowTime = time(NULL);
88 | aos_error_log("Done : %d %d %d %d\n", count, logsPerGroup, nowTime - startTime, (int32_t)buf.n_buffer);
89 | }
90 | log_group_destroy(bder);
91 | }
92 | aos_error_log("total time sec %d ", (time(NULL) - startTime));
93 | }
94 |
95 | void on_log_send_done(const char * config_name, log_producer_result result, size_t log_bytes, size_t compressed_bytes, const char * req_id, const char * message, const unsigned char * raw_buffer)
96 | {
97 | if (result == LOG_PRODUCER_OK)
98 | {
99 | if (aos_log_level == AOS_LOG_DEBUG)
100 | {
101 | printf("send success, config : %s, result : %d, log bytes : %d, compressed bytes : %d, request id : %s \n",
102 | config_name, (result),
103 | (int)log_bytes, (int)compressed_bytes, req_id);
104 | }
105 |
106 | }
107 | else
108 | {
109 | printf("send fail, config : %s, result : %d, log bytes : %d, compressed bytes : %d, request id : %s, error message : %s\n",
110 | config_name, (result),
111 | (int)log_bytes, (int)compressed_bytes, req_id, message);
112 | }
113 |
114 | }
115 |
116 | typedef struct _multi_write_log_param
117 | {
118 | log_producer_client * client;
119 | size_t send_count;
120 | }multi_write_log_param;
121 |
122 | void * write_log_thread(void* param)
123 | {
124 | aos_error_log("Thread start");
125 | multi_write_log_param * write_log_param = (multi_write_log_param *)param;
126 | size_t i = 0;
127 | char buffer[512];
128 | for (; i < write_log_param->send_count; ++i)
129 | {
130 | sprintf(buffer, "The Logstore is a unit in Log Service for the collection, storage, and query of log data, %d", (int)i);
131 | log_producer_client_add_log(write_log_param->client, 8, "Log group", "A log group is a collection of logs and is the basic unit for writing and reading",
132 | "Log topic", "Logs in a Logstore can be classified by log topics",
133 | "Project", "The project is the resource management unit in Log Service and is used to isolate and control resources",
134 | "Logstore", "The Logstore is a unit in Log Service for the collection, storage, and query of log data");
135 | }
136 | aos_error_log("Thread done");
137 | return NULL;
138 | }
139 |
140 | log_producer * create_log_producer_wrapper(on_log_producer_send_done_function on_send_done)
141 | {
142 | log_producer_config * config = create_log_producer_config();
143 | // endpoint list: https://help.aliyun.com/document_detail/29008.html
144 | log_producer_config_set_endpoint(config, "${your_endpoint}");
145 | log_producer_config_set_project(config, "${your_project}");
146 | log_producer_config_set_logstore(config, "${your_logstore}");
147 | log_producer_config_set_access_id(config, "${your_access_key_id}");
148 | log_producer_config_set_access_key(config, "${your_access_key_secret}");
149 | //log_producer_config_set_remote_address(config, "192.168.12.12");
150 |
151 | // if you do not need topic or tag, comment it
152 | log_producer_config_set_topic(config, "test_topic");
153 | log_producer_config_add_tag(config, "tag_1", "val_1");
154 | log_producer_config_add_tag(config, "tag_2", "val_2");
155 | log_producer_config_add_tag(config, "tag_3", "val_3");
156 | log_producer_config_add_tag(config, "tag_4", "val_4");
157 | log_producer_config_add_tag(config, "tag_5", "val_5");
158 |
159 | // set resource params
160 | log_producer_config_set_packet_log_bytes(config, 4*1024*1024);
161 | log_producer_config_set_packet_log_count(config, 4096);
162 | log_producer_config_set_packet_timeout(config, 3000);
163 | log_producer_config_set_max_buffer_limit(config, 64*1024*1024);
164 |
165 | // set send thread
166 | log_producer_config_set_send_thread_count(config, producer_send_thread_count);
167 |
168 | return create_log_producer(config, on_send_done);
169 | }
170 |
171 | #define MUTLI_THREAD_COUNT 16
172 | #define MUTLI_PRODUCER_COUNT 4
173 |
174 | #define GLOBAL_THREAD_FLAG
175 |
176 | void log_producer_multi_thread(size_t logsPerSecond)
177 | {
178 | logsPerSecond *= 100;
179 | if (log_producer_env_init(LOG_GLOBAL_ALL) != LOG_PRODUCER_OK) {
180 | exit(1);
181 | }
182 |
183 | #ifdef GLOBAL_THREAD_FLAG
184 | log_producer_global_send_thread_init(producer_send_thread_count, 100000);
185 | producer_send_thread_count = 0;
186 | #endif
187 |
188 | log_producer * producers[MUTLI_PRODUCER_COUNT];
189 | log_producer_client * clients[MUTLI_PRODUCER_COUNT];
190 | multi_write_log_param param[MUTLI_PRODUCER_COUNT];
191 |
192 | int i = 0;
193 | for (; i < MUTLI_PRODUCER_COUNT; ++i) {
194 | producers[i] = create_log_producer_wrapper(on_log_send_done);
195 | if (producers[i] == NULL)
196 | {
197 | printf("create log producer by config file fail \n");
198 | exit(1);
199 | }
200 | clients[i] = get_log_producer_client(producers[i], NULL);
201 | if (clients[i] == NULL)
202 | {
203 | printf("create log producer client by config file fail \n");
204 | exit(1);
205 | }
206 | param[i].send_count = logsPerSecond;
207 | param[i].client = clients[i] ;
208 | }
209 |
210 |
211 | pthread_t allThread[MUTLI_THREAD_COUNT];
212 | for (i = 0; i < MUTLI_THREAD_COUNT; ++i)
213 | {
214 | pthread_create(&allThread[i], NULL, write_log_thread, ¶m[i % MUTLI_PRODUCER_COUNT]);
215 | }
216 |
217 |
218 | for (i = 0; i < MUTLI_THREAD_COUNT; ++i)
219 | {
220 | pthread_join(allThread[i], NULL);
221 | }
222 | aos_error_log("All thread done");
223 |
224 | for (i = 0; i < MUTLI_PRODUCER_COUNT; ++i) {
225 | destroy_log_producer(producers[i]);
226 | }
227 |
228 | log_producer_env_destroy();
229 |
230 | }
231 |
232 | void log_producer_create_destroy()
233 | {
234 | int count = 0;
235 | while (1)
236 | {
237 | if (log_producer_env_init(LOG_GLOBAL_ALL) != LOG_PRODUCER_OK) {
238 | exit(1);
239 | }
240 |
241 | log_producer * producer = create_log_producer_wrapper(on_log_send_done);
242 | if (producer == NULL)
243 | {
244 | printf("create log producer by config file fail \n");
245 | exit(1);
246 | }
247 |
248 | log_producer_client * client = get_log_producer_client(producer, NULL);
249 | if (client == NULL)
250 | {
251 | printf("create log producer client by config file fail \n");
252 | exit(1);
253 | }
254 |
255 | destroy_log_producer(producer);
256 |
257 | log_producer_env_destroy();
258 | printf("%d \n", count++);
259 | }
260 | }
261 |
262 | void log_producer_post_logs(int logsPerSecond, int sendSec)
263 | {
264 | //aos_log_level = AOS_LOG_DEBUG;
265 | if (log_producer_env_init(LOG_GLOBAL_ALL) != LOG_PRODUCER_OK) {
266 | exit(1);
267 | }
268 |
269 | log_producer * producer = create_log_producer_wrapper(on_log_send_done);
270 | if (producer == NULL)
271 | {
272 | printf("create log producer by config file fail \n");
273 | exit(1);
274 | }
275 |
276 | log_producer_client * client = get_log_producer_client(producer, NULL);
277 | if (client == NULL)
278 | {
279 | printf("create log producer client by config file fail \n");
280 | exit(1);
281 | }
282 |
283 |
284 | int32_t i = 0;
285 | int32_t totalTime = 0;
286 | for (i = 0; i < sendSec; ++i)
287 | {
288 | int64_t startTime = GET_TIME_US();
289 | int j = 0;
290 | for (; j < logsPerSecond; ++j)
291 | {
292 | char indexStr[32];
293 | sprintf(indexStr, "%d", i * logsPerSecond + j);
294 | log_producer_client_add_log(client, 20, "content_key_1", "1abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
295 | "content_key_2", "2abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
296 | "content_key_3", "3abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
297 | "content_key_4", "4abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
298 | "content_key_5", "5abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
299 | "content_key_6", "6abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
300 | "content_key_7", "7abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
301 | "content_key_8", "8abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
302 | "content_key_9", "9abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
303 | "index", indexStr);
304 |
305 | log_producer_result rst = log_producer_client_add_log(client, 8, "LogHub", "Real-time log collection and consumption",
306 | "Search/Analytics", "Query and real-time analysis",
307 | "Visualized", "dashboard and report functions",
308 | "Interconnection", "Grafana and JDBC/SQL92");
309 | if (rst != LOG_PRODUCER_OK)
310 | {
311 | printf("add log error %d \n", rst);
312 | }
313 | }
314 | int64_t endTime = GET_TIME_US();
315 | aos_error_log("Done : %d %d time %f us \n", i, logsPerSecond, (float)(endTime - startTime) * 1.0 / logsPerSecond / 2);
316 | totalTime += endTime - startTime;
317 | if (endTime - startTime < 1000000)
318 | {
319 | usleep(1000000 - (endTime - startTime));
320 | }
321 | }
322 | aos_error_log("Total done : %f us, avg %f us", (float)totalTime / 180, (float)totalTime / (180 * logsPerSecond * 2));
323 | //sleep(10);
324 |
325 | destroy_log_producer(producer);
326 |
327 | log_producer_env_destroy();
328 | }
329 |
330 | int main(int argc, char *argv[])
331 | {
332 | aos_log_level = AOS_LOG_DEBUG;
333 | log_producer_multi_thread(999llu);
334 | return 0;
335 | //aos_log_level = AOS_LOG_TRACE;
336 | int logsPerSec = 100;
337 | int sendSec = 180;
338 | if (argc == 3)
339 | {
340 | logsPerSec = atoi(argv[1]);
341 | sendSec = atoi(argv[2]);
342 | }
343 | //log_producer_create_destroy();
344 | //log_producer_multi_thread(logsPerSec / 10);
345 | log_producer_post_logs(logsPerSec, sendSec);
346 | //builder_speed_test(logsPerSec);
347 | return 0;
348 | }
349 |
350 |
--------------------------------------------------------------------------------
/sample/log_producer_sample.c:
--------------------------------------------------------------------------------
1 | //
2 | // Created by ZhangCheng on 26/12/2017.
3 | //
4 |
5 | #include "log_api.h"
6 | #include "log_producer_config.h"
7 | #include "log_producer_client.h"
8 |
9 | void on_log_send_done(const char * config_name, log_producer_result result, size_t log_bytes, size_t compressed_bytes, const char * req_id, const char * message, const unsigned char * raw_buffer)
10 | {
11 | if (result == LOG_PRODUCER_OK)
12 | {
13 | // @note requst id may be NULL and printf %s NULL is undefined behavior
14 | if (req_id == NULL)
15 | {
16 | req_id = "";
17 | }
18 | printf("send success, config : %s, result : %d, log bytes : %d, compressed bytes : %d, request id : %s \n",
19 | config_name, (result),
20 | (int)log_bytes, (int)compressed_bytes, req_id);
21 | }
22 | else
23 | {
24 | // @note message may be NULL and printf %s NULL is undefined behavior
25 | if (message == NULL)
26 | {
27 | message = "";
28 | }
29 | // @note requst id may be NULL and printf %s NULL is undefined behavior
30 | if (req_id == NULL)
31 | {
32 | req_id = "";
33 | }
34 | printf("send fail, config : %s, result : %d, log bytes : %d, compressed bytes : %d, request id : %s, error message : %s\n",
35 | config_name, (result),
36 | (int)log_bytes, (int)compressed_bytes, req_id, message);
37 | }
38 |
39 | }
40 |
41 | log_producer * create_log_producer_wrapper(on_log_producer_send_done_function on_send_done)
42 | {
43 | log_producer_config * config = create_log_producer_config();
44 | // endpoint list: https://help.aliyun.com/document_detail/29008.html
45 | log_producer_config_set_endpoint(config, "${your_endpoint}");
46 | log_producer_config_set_project(config, "${your_project}");
47 | log_producer_config_set_logstore(config, "${your_logstore}");
48 | log_producer_config_set_access_id(config, "${your_access_key_id}");
49 | log_producer_config_set_access_key(config, "${your_access_key_secret}");
50 |
51 | // @note, if using security token to send log, remember reset token before expired. this function is thread safe
52 | //log_producer_config_reset_security_token(config, "${your_access_key_id}", "${your_access_key_secret}", "${your_access_security_token}");
53 |
54 | // if you do not need topic or tag, comment it
55 | log_producer_config_set_topic(config, "test_topic");
56 | log_producer_config_add_tag(config, "tag_1", "val_1");
57 | log_producer_config_add_tag(config, "tag_2", "val_2");
58 | log_producer_config_add_tag(config, "tag_3", "val_3");
59 | log_producer_config_add_tag(config, "tag_4", "val_4");
60 | log_producer_config_add_tag(config, "tag_5", "val_5");
61 |
62 | // set resource params
63 | log_producer_config_set_packet_log_bytes(config, 4*1024*1024);
64 | log_producer_config_set_packet_log_count(config, 4096);
65 | log_producer_config_set_packet_timeout(config, 3000);
66 | log_producer_config_set_max_buffer_limit(config, 64*1024*1024);
67 |
68 | // set send thread count
69 | log_producer_config_set_send_thread_count(config, 4);
70 |
71 | // set compress type : lz4
72 | log_producer_config_set_compress_type(config, 1);
73 |
74 | // set timeout
75 | log_producer_config_set_connect_timeout_sec(config, 10);
76 | log_producer_config_set_send_timeout_sec(config, 15);
77 | log_producer_config_set_destroy_flusher_wait_sec(config, 1);
78 | log_producer_config_set_destroy_sender_wait_sec(config, 1);
79 |
80 | // set interface
81 | log_producer_config_set_net_interface(config, NULL);
82 |
83 | return create_log_producer(config, on_send_done);
84 | }
85 |
86 |
87 | void log_producer_post_logs()
88 | {
89 | if (log_producer_env_init(LOG_GLOBAL_ALL) != LOG_PRODUCER_OK) {
90 | exit(1);
91 | }
92 |
93 | log_producer * producer = create_log_producer_wrapper(on_log_send_done);
94 | if (producer == NULL)
95 | {
96 | printf("create log producer by config fail \n");
97 | exit(1);
98 | }
99 |
100 | log_producer_client * client = get_log_producer_client(producer, NULL);
101 | if (client == NULL)
102 | {
103 | printf("create log producer client by config fail \n");
104 | exit(1);
105 | }
106 |
107 | int i = 0;
108 | for (; i < 10; ++i)
109 | {
110 | char indexStr[32];
111 | sprintf(indexStr, "%d", i);
112 | log_producer_client_add_log(client, 20, "content_key_1", "1abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
113 | "content_key_2", "2abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
114 | "content_key_3", "3abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
115 | "content_key_4", "4abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
116 | "content_key_5", "5abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
117 | "content_key_6", "6abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
118 | "content_key_7", "7abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
119 | "content_key_8", "8abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
120 | "content_key_9", "9abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+",
121 | "index", indexStr);
122 |
123 | log_producer_result rst = log_producer_client_add_log(client, 8, "LogHub", "Real-time log collection and consumption",
124 | "Search/Analytics", "Query and real-time analysis",
125 | "Visualized", "dashboard and report functions",
126 | "Interconnection", "Grafana and JDBC/SQL92");
127 | if (rst != LOG_PRODUCER_OK)
128 | {
129 | printf("add log error %d \n", rst);
130 | }
131 | }
132 |
133 | destroy_log_producer(producer);
134 |
135 | log_producer_env_destroy();
136 | }
137 |
138 | int main(int argc, char *argv[])
139 | {
140 | log_producer_post_logs();
141 | return 0;
142 | }
143 |
144 |
--------------------------------------------------------------------------------
/sample/video_frame_producer_sample.c:
--------------------------------------------------------------------------------
1 | //
2 | // Created by ZhangCheng on 26/02/2018.
3 | //
4 |
5 | #include "log_api.h"
6 | #include "log_producer_config.h"
7 | #include "log_producer_client.h"
8 | #include "log_multi_thread.h"
9 |
10 |
11 | /**
12 | * 发送数据结果的回调函数
13 | * @param config_name
14 | * @param result
15 | * @param log_bytes
16 | * @param compressed_bytes
17 | * @param req_id
18 | * @param message
19 | */
20 | void on_log_send_done(const char * config_name, log_producer_result result, size_t log_bytes, size_t compressed_bytes, const char * req_id, const char * message, const unsigned char * raw_buffer)
21 | {
22 | if (result == LOG_PRODUCER_OK)
23 | {
24 | printf("send success, config : %s, result : %d, log bytes : %d, compressed bytes : %d, request id : %s \n",
25 | config_name, (result),
26 | (int)log_bytes, (int)compressed_bytes, req_id);
27 |
28 | }
29 | else
30 | {
31 | printf("send fail, config : %s, result : %d, log bytes : %d, compressed bytes : %d, request id : %s, error message : %s\n",
32 | config_name, (result),
33 | (int)log_bytes, (int)compressed_bytes, req_id, message);
34 | }
35 |
36 | }
37 |
38 | /**
39 | * create producer 的一层封装
40 | * @param on_send_done
41 | * @return
42 | */
43 | log_producer * create_log_producer_wrapper(on_log_producer_send_done_function on_send_done)
44 | {
45 | log_producer_config * config = create_log_producer_config();
46 | // endpoint list: https://help.aliyun.com/document_detail/29008.html
47 | log_producer_config_set_endpoint(config, "${your_endpoint}");
48 | log_producer_config_set_project(config, "${your_project}");
49 | log_producer_config_set_logstore(config, "${your_logstore}");
50 | log_producer_config_set_access_id(config, "${your_access_key_id}");
51 | log_producer_config_set_access_key(config, "${your_access_key_secret}");
52 |
53 | // if you do not need topic or tag, comment it
54 | // 设置主题
55 | log_producer_config_set_topic(config, "test_topic");
56 |
57 | // 设置tag信息,此tag会附加在每个关键帧上,建议固定的meta信息使用tag设置
58 | log_producer_config_add_tag(config, "os", "linux");
59 | log_producer_config_add_tag(config, "version", "0.1.0");
60 | log_producer_config_add_tag(config, "type", "type_xxx");
61 |
62 | // set resource param
63 | log_producer_config_set_packet_log_bytes(config, 4*1024*1024);
64 | log_producer_config_set_packet_log_count(config, 4096);
65 | // 设置后台数据聚合上传的时间,默认为3000ms,如有需求可自定义设置
66 | log_producer_config_set_packet_timeout(config, 3000);
67 | // 最大缓存的数据大小,超出缓存时add_log接口会立即返回失败
68 | log_producer_config_set_max_buffer_limit(config, 64*1024*1024);
69 | // 设置不使用压缩
70 | log_producer_config_set_compress_type(config, 0);
71 |
72 | // set send thread count
73 | // 发送线程数,为1即可
74 | log_producer_config_set_send_thread_count(config, 1);
75 |
76 | // on_send_done 为发送的回调函数(发送成功/失败都会返回)
77 | return create_log_producer(config, on_send_done);
78 | }
79 |
80 | #define FRAME_FLAG_KEY_FRAME 1
81 | #define FRAME_FLAG_NONE 0
82 |
83 | /**
84 | * 帧数据的一种封装形式,您可以根据需求自定义调整
85 | */
86 | typedef struct _video_frame {
87 | uint64_t duration;
88 | uint8_t * frame_data;
89 | uint32_t frame_data_size;
90 | uint32_t frame_flag;
91 | uint64_t decoding_timestamp;
92 | uint64_t presentation_timestamp;
93 | uint8_t * extra_info;
94 | uint8_t extra_info_size;
95 | }video_frame;
96 |
97 |
98 | /**
99 | * 发送帧数据,这里是一种示例的封装形式,您可以根据需求进行更改
100 | * @param client producer Client
101 | * @param frame 帧数据
102 | */
103 | void post_frame(log_producer_client * client, video_frame * frame)
104 | {
105 | if (client == NULL || frame == NULL)
106 | {
107 | return;
108 | }
109 |
110 | // 帧数据封装 start
111 | char * g_frame_keys[] = {
112 | (char *)"duration",
113 | (char *)"frame_data",
114 | (char *)"frame_flag",
115 | (char *)"decoding_timestamp",
116 | (char *)"presentation_timestamp",
117 | (char *)"extra_info"
118 | };
119 |
120 | size_t g_frame_keys_len[] = {
121 | strlen("duration"),
122 | strlen("frame_data"),
123 | strlen("frame_flag"),
124 | strlen("decoding_timestamp"),
125 | strlen("presentation_timestamp"),
126 | strlen("extra_info")
127 | };
128 |
129 | char * values[6];
130 |
131 | char duration[32];
132 | sprintf(duration, "%llu", (long long unsigned int)frame->duration);
133 |
134 | char frame_flag[32];
135 | sprintf(frame_flag, "%u", frame->frame_flag);
136 |
137 | char decoding_timestamp[32];
138 | sprintf(decoding_timestamp, "%llu", (long long unsigned int)frame->decoding_timestamp);
139 |
140 | char presentation_timestamp[32];
141 | sprintf(presentation_timestamp, "%llu", (long long unsigned int)frame->presentation_timestamp);
142 |
143 | values[0] = duration;
144 | values[1] = (char *)frame->frame_data;
145 | values[2] = frame_flag;
146 | values[3] = decoding_timestamp;
147 | values[4] = presentation_timestamp;
148 | values[5] = (char *)frame->extra_info;
149 |
150 | size_t values_len[] = {
151 | strlen(duration),
152 | frame->frame_data_size,
153 | strlen(frame_flag),
154 | strlen(decoding_timestamp),
155 | strlen(presentation_timestamp),
156 | frame->extra_info_size
157 | };
158 |
159 | // 帧数据封装 end
160 |
161 |
162 | // 调用producer接口发送数据
163 | log_producer_result rst = log_producer_client_add_log_with_len(client, 6, g_frame_keys, g_frame_keys_len, values, values_len);
164 | // 异常处理
165 | if (rst != LOG_PRODUCER_OK)
166 | {
167 | // 这边可以加入一些异常处理,如果是关键帧发送失败,可以每隔10ms重试一次,超过10次继续失败时再丢弃
168 | if ((frame->frame_flag & FRAME_FLAG_KEY_FRAME) != 0)
169 | {
170 | int try_time = 0;
171 | for (; try_time < 10; ++try_time)
172 | {
173 | usleep(10000);
174 | if (log_producer_client_add_log_with_len(client, 6, g_frame_keys, g_frame_keys_len, values, values_len) == LOG_PRODUCER_OK)
175 | {
176 | break;
177 | }
178 | }
179 | if (try_time == 10)
180 | {
181 | printf("add key frame error %d \n", rst);
182 | }
183 | }
184 | else
185 | {
186 | printf("add normal frame error %d \n", rst);
187 | }
188 | }
189 |
190 | }
191 |
192 | /**
193 | * 示例函数
194 | */
195 | void producer_post_frames()
196 | {
197 | if (log_producer_env_init(LOG_GLOBAL_ALL) != LOG_PRODUCER_OK) {
198 | exit(1);
199 | }
200 |
201 | log_producer * producer = create_log_producer_wrapper(on_log_send_done);
202 | if (producer == NULL)
203 | {
204 | printf("create producer by config fail \n");
205 | exit(1);
206 | }
207 |
208 | log_producer_client * client = get_log_producer_client(producer, NULL);
209 | if (client == NULL)
210 | {
211 | printf("create producer client by config fail \n");
212 | exit(1);
213 | }
214 |
215 | srand(time(NULL));
216 |
217 | int i = 0;
218 | for (; i < 100; ++i)
219 | {
220 | video_frame frame;
221 | // 每10帧有一个为关键帧
222 | frame.frame_flag = i % 10 == 0 ? FRAME_FLAG_KEY_FRAME : FRAME_FLAG_NONE;
223 |
224 | // mock 帧数据
225 | uint32_t data_size = 960*720;
226 | uint8_t * frame_data = (uint8_t *)malloc(data_size);
227 | memset(frame_data, i % 256, data_size);
228 | frame.frame_data_size = data_size;
229 | frame.frame_data = frame_data;
230 |
231 | frame.duration = rand() % 500;
232 | frame.decoding_timestamp = time(NULL);
233 | frame.presentation_timestamp = time(NULL);
234 | char extra_info[32];
235 | sprintf(extra_info, "extra_%d", i);
236 | frame.extra_info = (uint8_t *)extra_info;
237 | frame.extra_info_size = strlen(extra_info);
238 |
239 | // 发送帧数据
240 | post_frame(client, &frame);
241 |
242 | free(frame_data);
243 |
244 | usleep(30000);
245 | }
246 |
247 | destroy_log_producer(producer);
248 | log_producer_env_destroy();
249 | }
250 |
251 | int main(int argc, char *argv[])
252 | {
253 | producer_post_frames();
254 | return 0;
255 | }
256 |
257 |
--------------------------------------------------------------------------------
/save_send_buffer.md:
--------------------------------------------------------------------------------
1 | # 程序可靠退出方案
2 | ## 简介
3 | 在使用日志服务C Producer时,若您的程序需要可靠退出,可以根据此文档介绍实现此功能。
4 |
5 | ## 问题背景
6 | 在程序退出时,C Producer会在给定时间范围内尽可能的将缓存中的日志发送出去,当等待超过`destroy_sender_wait_sec`若还没有发送成功,则会强制停止发送线程池。此时可能出现最后若干日志丢失的情况。
7 |
8 | ## 解决方法
9 | 针对以上问题,日志服务 C Producer提供了相应的数据导出以及导入接口,为应用程序在退出时提供日志数据可靠保存的方式。具体实现方式如下:
10 | 1. 在销毁Producer时,producer会将未发送完的数据通过发送回调函数`on_log_send_done`通知应用程序,错误码为`LOG_PRODUCER_SEND_EXIT_BUFFERED`
11 | 2. 应用程序在接收到此错误码时,将`log_bytes` `compressed_bytes` `buffer` 保存到本地
12 | 3. 在应用程序下一次启动时,读取本地文件,并调用`log_producer_client_add_raw_log_buffer`将上一次未发送完毕的数据发送出去
13 |
14 |
--------------------------------------------------------------------------------
/src/hmac-sha.c:
--------------------------------------------------------------------------------
1 |
2 |
3 | #include
4 | #include
5 | #include "sha1.h"
6 | #include "hmac-sha.h"
7 |
8 | #define IPAD 0x36
9 | #define OPAD 0x5C
10 |
11 |
12 | #ifndef HMAC_SHORTONLY
13 |
14 | void hmac_sha1_init(hmac_sha1_ctx_t *s, const void *key, uint16_t keylength_b){
15 | uint8_t buffer[SHA1_BLOCK_BYTES];
16 | uint8_t i;
17 |
18 | memset(buffer, 0, SHA1_BLOCK_BYTES);
19 | if (keylength_b > SHA1_BLOCK_BITS){
20 | sha1((void*)buffer, key, keylength_b);
21 | } else {
22 | memcpy(buffer, key, (keylength_b+7)/8);
23 | }
24 |
25 | for (i=0; ia));
29 | sha1_nextBlock(&(s->a), buffer);
30 |
31 | for (i=0; ib));
35 | sha1_nextBlock(&(s->b), buffer);
36 |
37 |
38 | #if defined SECURE_WIPE_BUFFER
39 | memset(buffer, 0, SHA1_BLOCK_BYTES);
40 | #endif
41 | }
42 |
43 | void hmac_sha1_nextBlock(hmac_sha1_ctx_t *s, const void *block){
44 | sha1_nextBlock(&(s->a), block);
45 | }
46 | void hmac_sha1_lastBlock(hmac_sha1_ctx_t *s, const void *block, uint16_t length_b){
47 | while(length_b>=SHA1_BLOCK_BITS){
48 | sha1_nextBlock(&s->a, block);
49 | block = (uint8_t*)block + SHA1_BLOCK_BYTES;
50 | length_b -= SHA1_BLOCK_BITS;
51 | }
52 | sha1_lastBlock(&s->a, block, length_b);
53 | }
54 |
55 | void hmac_sha1_final(void *dest, hmac_sha1_ctx_t *s){
56 | sha1_ctx2hash(dest, &s->a);
57 | sha1_lastBlock(&s->b, dest, SHA1_HASH_BITS);
58 | sha1_ctx2hash(dest, &(s->b));
59 | }
60 |
61 | #endif
62 |
63 | /*
64 | * keylength in bits!
65 | * message length in bits!
66 | */
67 | void hmac_sha1(void *dest, const void *key, uint16_t keylength_b, const void *msg, uint32_t msglength_b){ /* a one-shot*/
68 | sha1_ctx_t s;
69 | uint8_t i;
70 | uint8_t buffer[SHA1_BLOCK_BYTES];
71 |
72 | memset(buffer, 0, SHA1_BLOCK_BYTES);
73 |
74 | /* if key is larger than a block we have to hash it*/
75 | if (keylength_b > SHA1_BLOCK_BITS){
76 | sha1((void*)buffer, key, keylength_b);
77 | } else {
78 | memcpy(buffer, key, (keylength_b+7)/8);
79 | }
80 |
81 | for (i=0; i= SHA1_BLOCK_BITS){
87 | sha1_nextBlock(&s, msg);
88 | msg = (uint8_t*)msg + SHA1_BLOCK_BYTES;
89 | msglength_b -= SHA1_BLOCK_BITS;
90 | }
91 | sha1_lastBlock(&s, msg, msglength_b);
92 | /* since buffer still contains key xor ipad we can do ... */
93 | for (i=0; i
3 | #include
4 | #include
5 |
6 |
7 | void aos_log_print_default(const char *message, int lens)
8 | {
9 | puts(message);
10 | }
11 |
12 |
13 | void aos_log_format_default(int level,
14 | const char *file,
15 | int line,
16 | const char *function,
17 | const char *fmt, ...);
18 |
19 | aos_log_level_e aos_log_level = AOS_LOG_WARN;
20 | aos_log_format_pt aos_log_format = aos_log_format_default;
21 | aos_log_print_pt aos_log_output = aos_log_print_default;
22 |
23 |
24 | static const char * _aos_log_level_str[] = {
25 | "NONE",
26 | "NONE",
27 | "FATAL",
28 | "ERROR",
29 | "WARN",
30 | "INFO",
31 | "DEBUG",
32 | "TRACE",
33 | "NONE"
34 | };
35 |
36 |
37 | void aos_log_set_level(aos_log_level_e level)
38 | {
39 | aos_log_level = level;
40 | }
41 |
42 |
43 | void aos_log_format_default(int level,
44 | const char *file,
45 | int line,
46 | const char *function,
47 | const char *fmt, ...)
48 | {
49 | va_list args;
50 | char buffer[1024];
51 | int maxLen = 1020;
52 |
53 | // @note return value maybe < 0 || > maxLen
54 | int len = snprintf(buffer, maxLen, "[%s] [%s:%d] ",
55 | _aos_log_level_str[level],
56 | file, line);
57 | // should never happen
58 | if (len < 0 || len > maxLen) {
59 | puts("[aos_log_format] error log fmt\n");
60 | return;
61 | }
62 |
63 | va_start(args, fmt);
64 | // @note return value maybe < 0 || > maxLen
65 | int rst = vsnprintf(buffer + len, maxLen - len, fmt, args);
66 | va_end(args);
67 | if (rst < 0) {
68 | puts("[aos_log_format] error log fmt\n");
69 | return;
70 | }
71 |
72 | if (rst > maxLen - len) {
73 | rst = maxLen - len;
74 | }
75 | len += rst;
76 |
77 |
78 | while (len > 0 && buffer[len -1] == '\n')
79 | {
80 | len--;
81 | }
82 | buffer[len++] = '\n';
83 | buffer[len] = '\0';
84 |
85 | aos_log_output(buffer, len);
86 | }
87 |
88 | void aos_log_set_format_callback(aos_log_format_pt func)
89 | {
90 | if (func == NULL) {
91 | return;
92 | }
93 | aos_log_format = func;
94 | }
95 |
96 | void aos_log_set_print_callback(aos_log_print_pt func)
97 | {
98 | if (func == NULL) {
99 | return;
100 | }
101 | aos_log_output = func;
102 | }
103 |
--------------------------------------------------------------------------------
/src/inner_log.h:
--------------------------------------------------------------------------------
1 | #ifndef LIBAOS_LOG_H
2 | #define LIBAOS_LOG_H
3 |
4 | #ifdef __cplusplus
5 | extern "C"
6 | {
7 | #endif
8 |
9 | typedef void (*aos_log_format_pt)(int level,
10 | const char *file,
11 | int line,
12 | const char *function,
13 | const char *fmt, ...);
14 | typedef void (*aos_log_print_pt)(const char *message, int len);
15 |
16 | typedef enum {
17 | AOS_LOG_OFF = 1,
18 | AOS_LOG_FATAL,
19 | AOS_LOG_ERROR,
20 | AOS_LOG_WARN,
21 | AOS_LOG_INFO,
22 | AOS_LOG_DEBUG,
23 | AOS_LOG_TRACE,
24 | AOS_LOG_ALL
25 | } aos_log_level_e;
26 |
27 | extern aos_log_level_e aos_log_level;
28 | extern aos_log_format_pt aos_log_format;
29 |
30 | /**
31 | * set inner log callback for format
32 | * @note if format callback is set, print callback has no effect
33 | * @param func callback function
34 | */
35 | void aos_log_set_format_callback(aos_log_format_pt func);
36 |
37 | /**
38 | * set inner log callback for string log print
39 | * @param func callback function
40 | */
41 | void aos_log_set_print_callback(aos_log_print_pt func);
42 |
43 |
44 | #define aos_fatal_log(format, args...) if(aos_log_level>=AOS_LOG_FATAL) \
45 | aos_log_format(AOS_LOG_FATAL, __FILE__, __LINE__, __FUNCTION__, format, ## args)
46 | #define aos_error_log(format, args...) if(aos_log_level>=AOS_LOG_ERROR) \
47 | aos_log_format(AOS_LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, format, ## args)
48 | #define aos_warn_log(format, args...) if(aos_log_level>=AOS_LOG_WARN) \
49 | aos_log_format(AOS_LOG_WARN, __FILE__, __LINE__, __FUNCTION__, format, ## args)
50 | #define aos_info_log(format, args...) if(aos_log_level>=AOS_LOG_INFO) \
51 | aos_log_format(AOS_LOG_INFO, __FILE__, __LINE__, __FUNCTION__, format, ## args)
52 | #define aos_debug_log(format, args...) if(aos_log_level>=AOS_LOG_DEBUG) \
53 | aos_log_format(AOS_LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, format, ## args)
54 | #define aos_trace_log(format, args...) if(aos_log_level>=AOS_LOG_TRACE) \
55 | aos_log_format(AOS_LOG_TRACE, __FILE__, __LINE__, __FUNCTION__, format, ## args)
56 |
57 | #ifdef __cplusplus
58 | }
59 | #endif
60 |
61 | #endif
62 |
--------------------------------------------------------------------------------
/src/log_api.h:
--------------------------------------------------------------------------------
1 | #ifndef LIBLOG_API_H
2 | #define LIBLOG_API_H
3 |
4 | #include "log_define.h"
5 |
6 | #include "log_builder.h"
7 | LOG_CPP_START
8 |
9 | struct _log_post_option
10 | {
11 | char * interface; // net interface to send log, NULL as default
12 | char * remote_address; // remote_address to send log, NULL as default
13 | int connect_timeout; // connection timeout seconds, 0 as default
14 | int operation_timeout; // operation timeout seconds, 0 as default
15 | int compress_type; // 0 no compress, 1 lz4
16 | int using_https; // 0 http, 1 https
17 | };
18 | typedef struct _log_post_option log_post_option;
19 |
20 | log_status_t sls_log_init(int32_t log_global_flag);
21 | void sls_log_destroy();
22 |
23 | post_log_result * post_logs_from_lz4buf(const char *endpoint,
24 | const char * accesskeyId,
25 | const char *accessKey,
26 | const char *stsToken,
27 | const char *project,
28 | const char *logstore,
29 | lz4_log_buf * buffer,
30 | log_post_option * option,
31 | auth_version version,
32 | const char *region);
33 |
34 | void post_log_result_destroy(post_log_result * result);
35 |
36 | LOG_CPP_END
37 | #endif
38 |
--------------------------------------------------------------------------------
/src/log_builder.c:
--------------------------------------------------------------------------------
1 | #include "log_builder.h"
2 | #include "lz4.h"
3 | #include "sds.h"
4 | #include
5 | #include
6 | #include
7 | #include "inner_log.h"
8 |
9 | #ifdef LOG_FEATURE_ZSTD_COMPRESS
10 | #include "zstd.h"
11 | #define LOG_ZSTD_COMPRESS_LEVEL 1
12 | #endif
13 |
14 | // 1+3( 1 ---> header; 2 ---> 128 * 128 = 16KB)
15 | #define INIT_LOG_SIZE_BYTES 3
16 |
17 | /**
18 | * Return the number of bytes required to store a variable-length unsigned
19 | * 32-bit integer in base-128 varint encoding.
20 | *
21 | * \param v
22 | * Value to encode.
23 | * \return
24 | * Number of bytes required.
25 | */
26 | static inline size_t uint32_size(uint32_t v)
27 | {
28 | if (v < (1UL << 7)) {
29 | return 1;
30 | } else if (v < (1UL << 14)) {
31 | return 2;
32 | } else if (v < (1UL << 21)) {
33 | return 3;
34 | } else if (v < (1UL << 28)) {
35 | return 4;
36 | } else {
37 | return 5;
38 | }
39 | }
40 |
41 | /**
42 | * Pack an unsigned 32-bit integer in base-128 varint encoding and return the
43 | * number of bytes written, which must be 5 or less.
44 | *
45 | * \param value
46 | * Value to encode.
47 | * \param[out] out
48 | * Packed value.
49 | * \return
50 | * Number of bytes written to `out`.
51 | */
52 | static inline size_t uint32_pack(uint32_t value, uint8_t *out)
53 | {
54 | unsigned rv = 0;
55 |
56 | if (value >= 0x80) {
57 | out[rv++] = value | 0x80;
58 | value >>= 7;
59 | if (value >= 0x80) {
60 | out[rv++] = value | 0x80;
61 | value >>= 7;
62 | if (value >= 0x80) {
63 | out[rv++] = value | 0x80;
64 | value >>= 7;
65 | if (value >= 0x80) {
66 | out[rv++] = value | 0x80;
67 | value >>= 7;
68 | }
69 | }
70 | }
71 | }
72 | /* assert: value<128 */
73 | out[rv++] = value;
74 | return rv;
75 | }
76 |
77 | static inline uint32_t parse_uint32(unsigned len, const uint8_t *data)
78 | {
79 | uint32_t rv = data[0] & 0x7f;
80 | if (len > 1) {
81 | rv |= ((uint32_t) (data[1] & 0x7f) << 7);
82 | if (len > 2) {
83 | rv |= ((uint32_t) (data[2] & 0x7f) << 14);
84 | if (len > 3) {
85 | rv |= ((uint32_t) (data[3] & 0x7f) << 21);
86 | if (len > 4)
87 | rv |= ((uint32_t) (data[4]) << 28);
88 | }
89 | }
90 | }
91 | return rv;
92 | }
93 |
94 | static unsigned scan_varint(unsigned len, const uint8_t *data)
95 | {
96 | unsigned i;
97 | if (len > 10)
98 | len = 10;
99 | for (i = 0; i < len; i++)
100 | if ((data[i] & 0x80) == 0)
101 | break;
102 | if (i == len)
103 | return 0;
104 | return i + 1;
105 | }
106 |
107 | log_group_builder* log_group_create()
108 | {
109 | log_group_builder* bder = (log_group_builder*)malloc(sizeof(log_group_builder)+sizeof(log_group));
110 | memset(bder, 0, sizeof(log_group_builder)+sizeof(log_group));
111 | bder->grp = (log_group*)((char *)(bder) + sizeof(log_group_builder));
112 | bder->loggroup_size = sizeof(log_group) + sizeof(log_group_builder);
113 | bder->builder_time = time(NULL);
114 | return bder;
115 | }
116 |
117 | void log_group_destroy(log_group_builder* bder)
118 | {
119 | // free tag
120 | log_group* group = bder->grp;
121 | if (group->tags.buffer != NULL)
122 | {
123 | free(group->tags.buffer);
124 | }
125 | // free log
126 | if (group->logs.buffer != NULL)
127 | {
128 | free(group->logs.buffer);
129 | }
130 | if (group->topic != NULL)
131 | {
132 | sdsfree(group->topic);
133 | }
134 | if (group->source != NULL)
135 | {
136 | sdsfree(group->source);
137 | }
138 | // free self
139 | free(bder);
140 | }
141 |
142 |
143 | /**
144 | * adjust buffer, this function will ensure tag's buffer size >= tag->now_buffer_len + new_len
145 | * @param tag
146 | * @param new_len new buffer len
147 | */
148 | void _adjust_buffer(log_tag * tag, uint32_t new_len)
149 | {
150 | if (tag->buffer == NULL)
151 | {
152 | tag->buffer = (char *)malloc(new_len << 2);
153 | tag->max_buffer_len = new_len << 2;
154 | tag->now_buffer = tag->buffer;
155 | tag->now_buffer_len = 0;
156 | return;
157 | }
158 | uint32_t new_buffer_len = tag->max_buffer_len << 1;
159 |
160 | if (new_buffer_len < tag->now_buffer_len + new_len)
161 | {
162 | new_buffer_len = tag->now_buffer_len + new_len;
163 | }
164 |
165 | tag->buffer = (char *)realloc(tag->buffer, new_buffer_len);
166 | tag->now_buffer = tag->buffer + tag->now_buffer_len;
167 | tag->max_buffer_len = new_buffer_len;
168 | }
169 |
170 | void add_log_full(log_group_builder* bder, uint32_t logTime, int32_t pair_count, char ** keys, size_t * key_lens, char ** values, size_t * val_lens)
171 | {
172 | ++bder->grp->n_logs;
173 |
174 | // limit logTime's min value, ensure varint size is 5
175 | if (logTime < 1263563523)
176 | {
177 | logTime = 1263563523;
178 | }
179 |
180 | int32_t i = 0;
181 | int32_t logSize = 6;
182 | for (; i < pair_count; ++i)
183 | {
184 | uint32_t contSize = uint32_size(key_lens[i]) + uint32_size(val_lens[i]) + key_lens[i] + val_lens[i] + 2;
185 | logSize += 1 + uint32_size(contSize) + contSize;
186 | }
187 | int32_t totalBufferSize = logSize + 1 + uint32_size(logSize);
188 |
189 | log_tag * log = &(bder->grp->logs);
190 |
191 | if (log->now_buffer == NULL || log->max_buffer_len < log->now_buffer_len + totalBufferSize)
192 | {
193 | _adjust_buffer(log, totalBufferSize);
194 | }
195 |
196 |
197 | bder->loggroup_size += totalBufferSize;
198 | uint8_t * buf = (uint8_t*)log->now_buffer;
199 |
200 | *buf++ = 0x0A;
201 | buf += uint32_pack(logSize, buf);
202 |
203 | // time
204 | *buf++=0x08;
205 | buf += uint32_pack(logTime, buf);
206 |
207 | // Content
208 | // header
209 | i = 0;
210 | for (; i < pair_count; ++i)
211 | {
212 | *buf++ = 0x12;
213 | buf += uint32_pack(uint32_size(key_lens[i]) + uint32_size(val_lens[i]) + 2 + key_lens[i] + val_lens[i], buf);
214 | *buf++ = 0x0A;
215 | buf += uint32_pack(key_lens[i], buf);
216 | memcpy(buf, keys[i], key_lens[i]);
217 | buf += key_lens[i];
218 | *buf++ = 0x12;
219 | buf += uint32_pack(val_lens[i], buf);
220 | memcpy(buf, values[i], val_lens[i]);
221 | buf += val_lens[i];
222 | }
223 | assert(buf - (uint8_t*)log->now_buffer == totalBufferSize);
224 | log->now_buffer_len += totalBufferSize;
225 | log->now_buffer = (char *)buf;
226 | }
227 |
228 |
229 | void add_source(log_group_builder* bder,const char* src,size_t len)
230 | {
231 | bder->loggroup_size += sizeof(char)*(len) + uint32_size((uint32_t)len) + 1;
232 | bder->grp->source = sdsnewlen(src, len);
233 | }
234 |
235 | void add_topic(log_group_builder* bder,const char* tpc,size_t len)
236 | {
237 | bder->loggroup_size += sizeof(char)*(len) + uint32_size((uint32_t)len) + 1;
238 | bder->grp->topic = sdsnewlen(tpc, len);
239 | }
240 |
241 | void add_pack_id(log_group_builder* bder, const char* pack, size_t pack_len, size_t packNum)
242 | {
243 | char packStr[128];
244 | packStr[127] = '\0';
245 | snprintf(packStr, 127, "%s-%X", pack, (unsigned int)packNum);
246 | add_tag(bder, "__pack_id__", strlen("__pack_id__"), packStr, strlen(packStr));
247 | }
248 |
249 |
250 | void add_tag(log_group_builder* bder, const char* k, size_t k_len, const char* v, size_t v_len)
251 | {
252 | // use only 1 malloc
253 | uint32_t tag_size = sizeof(char) * (k_len + v_len) + uint32_size((uint32_t)k_len) + uint32_size((uint32_t)v_len) + 2;
254 | uint32_t n_buffer = 1 + uint32_size(tag_size) + tag_size;
255 | log_tag * tag = &(bder->grp->tags);
256 | if (tag->now_buffer == NULL || tag->now_buffer_len + n_buffer > tag->max_buffer_len)
257 | {
258 | _adjust_buffer(tag, n_buffer);
259 | }
260 | uint8_t * buf = (uint8_t *)tag->now_buffer;
261 | *buf++ = 0x32;
262 | buf += uint32_pack(tag_size, buf);
263 | *buf++ = 0x0A;
264 | buf += uint32_pack((uint32_t)k_len, buf);
265 | memcpy(buf, k, k_len);
266 | buf += k_len;
267 | *buf++ = 0x12;
268 | buf += uint32_pack((uint32_t)v_len, buf);
269 | memcpy(buf, v, v_len);
270 | buf += v_len;
271 | assert((uint8_t *)tag->now_buffer + n_buffer == buf);
272 | tag->now_buffer = (char *)buf;
273 | tag->now_buffer_len += n_buffer;
274 | bder->loggroup_size += n_buffer;
275 | }
276 |
277 | static uint32_t _log_pack(log_group * grp, uint8_t * buf)
278 | {
279 | uint8_t * start_buf = buf;
280 |
281 | if (grp->logs.buffer != NULL)
282 | {
283 | buf += grp->logs.now_buffer_len;
284 | }
285 | else
286 | {
287 | return 0;
288 | }
289 |
290 | if (grp->topic != NULL)
291 | {
292 | *buf++ = 0x1A;
293 | buf+= uint32_pack((uint32_t)sdslen(grp->topic), buf);
294 | memcpy(buf, grp->topic, sdslen(grp->topic));
295 | buf += sdslen(grp->topic);
296 | }
297 |
298 | if (grp->source != NULL)
299 | {
300 | *buf++ = 0x22;
301 | buf+= uint32_pack((uint32_t)sdslen(grp->source), buf);
302 | memcpy(buf, grp->source, sdslen(grp->source));
303 | buf += sdslen(grp->source);
304 | }
305 |
306 | if (grp->tags.buffer != NULL)
307 | {
308 | memcpy(buf, grp->tags.buffer, grp->tags.now_buffer_len);
309 | buf += grp->tags.now_buffer_len;
310 | }
311 |
312 | return buf - start_buf;
313 | }
314 |
315 | void fix_log_group_time(char * pb_buffer, size_t len, uint32_t new_time)
316 | {
317 | if (len == 0 || pb_buffer == NULL || new_time < 1263563523)
318 | {
319 | return;
320 | }
321 | if (pb_buffer[0] != 0x0A)
322 | {
323 | return;
324 | }
325 | uint8_t * buf = (uint8_t *)pb_buffer;
326 | uint8_t * startBuf = (uint8_t *)pb_buffer;
327 | while (buf - startBuf < len && *buf == 0x0A)
328 | {
329 | ++buf;
330 | unsigned logSizeLen = scan_varint(5, buf);
331 | uint32_t logSize = parse_uint32(logSizeLen, buf);
332 | buf += logSizeLen;
333 | // time
334 | if (*buf == 0x08)
335 | {
336 | uint32_pack(new_time, buf + 1);
337 | }
338 | buf += logSize;
339 | }
340 |
341 | }
342 |
343 |
344 | log_buf serialize_to_proto_buf_with_malloc(log_group_builder* bder)
345 | {
346 | log_buf buf;
347 | buf.buffer = NULL;
348 | buf.n_buffer = 0;
349 | log_tag * log = &(bder->grp->logs);
350 | if (log->buffer == NULL)
351 | {
352 | return buf;
353 | }
354 | if (log->max_buffer_len < bder->loggroup_size)
355 | {
356 | _adjust_buffer(log, bder->loggroup_size - log->now_buffer_len);
357 | }
358 | buf.n_buffer = _log_pack(bder->grp, (uint8_t *)log->buffer);
359 | buf.buffer = log->buffer;
360 | return buf;
361 | }
362 |
363 | lz4_log_buf* serialize_with_malloc_compressed(log_group_builder* bder, log_compress_type compress_type)
364 | {
365 | if (compress_type == LOG_COMPRESS_NONE)
366 | {
367 | log_buf buf = serialize_to_proto_buf_with_malloc(bder);
368 | lz4_log_buf* pLogbuf = (lz4_log_buf*)malloc(sizeof(lz4_log_buf) + buf.n_buffer);
369 | pLogbuf->length = buf.n_buffer;
370 | pLogbuf->raw_length = buf.n_buffer;
371 | pLogbuf->compress_type = compress_type;
372 | memcpy(pLogbuf->data, buf.buffer, buf.n_buffer);
373 | return pLogbuf;
374 | }
375 |
376 | log_tag * log = &(bder->grp->logs);
377 | if (log->buffer == NULL)
378 | {
379 | aos_error_log("fail to serialize to log buf: logs is empty, %d", compress_type);
380 | return NULL;
381 | }
382 | if (log->max_buffer_len < bder->loggroup_size)
383 | {
384 | _adjust_buffer(log, bder->loggroup_size - log->now_buffer_len);
385 | }
386 | size_t length = _log_pack(bder->grp, (uint8_t *)log->buffer);
387 |
388 | size_t compress_bound, compressed_size;
389 | char* compressed_data;
390 | if (compress_type == LOG_COMPRESS_LZ4)
391 | {
392 | compress_bound = LZ4_compressBound(length);
393 | compressed_data = (char *)malloc(compress_bound);
394 | compressed_size = LZ4_compress_default((char *)log->buffer, compressed_data, length, compress_bound);
395 | if(compressed_size <= 0)
396 | {
397 | free(compressed_data);
398 | aos_error_log("fail to serialize to log buf: fail to compress using lz4");
399 | return NULL;
400 | }
401 | }
402 | else if (compress_type == LOG_COMPRESS_ZSTD)
403 | {
404 | #ifdef LOG_FEATURE_ZSTD_COMPRESS
405 | compress_bound = ZSTD_compressBound(length);
406 | compressed_data = (char *)malloc(compress_bound);
407 | compressed_size = ZSTD_compress(compressed_data,
408 | compress_bound,
409 | (char *)log->buffer,
410 | length,
411 | LOG_ZSTD_COMPRESS_LEVEL);
412 | if (ZSTD_isError(compressed_size))
413 | {
414 | free(compressed_data);
415 | aos_error_log("fail to serialize to log buf: fail to compress using zstd");
416 | return NULL;
417 | }
418 | #else
419 | aos_error_log("fail to serialize to log buf, unsupported compress type: zstd");
420 | return NULL;
421 | #endif
422 | }
423 | else
424 | {
425 | aos_error_log("fail to serialize to log buf, unsupported compress type:%d", compress_type);
426 | return NULL;
427 | }
428 | lz4_log_buf* pLogbuf = (lz4_log_buf*)malloc(sizeof(lz4_log_buf) + compressed_size);
429 | pLogbuf->length = compressed_size;
430 | pLogbuf->raw_length = length;
431 | pLogbuf->compress_type = compress_type;
432 | memcpy(pLogbuf->data, compressed_data, compressed_size);
433 | free(compressed_data);
434 | return pLogbuf;
435 | }
436 |
437 | lz4_log_buf* serialize_to_proto_buf_with_malloc_no_compress(log_group_builder* bder)
438 | {
439 | return serialize_with_malloc_compressed(bder, LOG_COMPRESS_NONE);
440 | }
441 |
442 | lz4_log_buf* serialize_to_proto_buf_with_malloc_zstd(log_group_builder* bder)
443 | {
444 | return serialize_with_malloc_compressed(bder, LOG_COMPRESS_ZSTD);
445 | }
446 |
447 | lz4_log_buf* serialize_to_proto_buf_with_malloc_lz4(log_group_builder* bder)
448 | {
449 | return serialize_with_malloc_compressed(bder, LOG_COMPRESS_LZ4);
450 | }
451 |
452 | void free_lz4_log_buf(lz4_log_buf* pBuf)
453 | {
454 | free(pBuf);
455 | }
456 |
457 | #ifdef LOG_KEY_VALUE_FLAG
458 |
459 | void add_log_begin(log_group_builder * bder)
460 | {
461 | log_tag * logs = &bder->grp->logs;
462 | if (logs->buffer == NULL || logs->now_buffer_len + INIT_LOG_SIZE_BYTES > logs->max_buffer_len)
463 | {
464 | _adjust_buffer(logs, INIT_LOG_SIZE_BYTES);
465 | }
466 | bder->grp->log_now_buffer = logs->now_buffer + INIT_LOG_SIZE_BYTES;
467 | }
468 |
469 | void add_log_time(log_group_builder * bder, uint32_t logTime)
470 | {
471 | log_tag * logs = &bder->grp->logs;
472 | // 1 header and 5 time
473 | if (bder->grp->log_now_buffer - logs->buffer + 6 > logs->max_buffer_len)
474 | {
475 | // reset log_now_buffer
476 | size_t delta = bder->grp->log_now_buffer - logs->buffer;
477 | _adjust_buffer(logs, delta + 6);
478 | bder->grp->log_now_buffer = logs->buffer + delta;
479 | }
480 |
481 | uint8_t * buf = (uint8_t *)bder->grp->log_now_buffer;
482 | // time
483 | *buf++=0x08;
484 | buf += uint32_pack(logTime, buf);
485 | bder->grp->log_now_buffer = (char *)buf;
486 | }
487 |
488 | void add_log_key_value(log_group_builder *bder, char * key, size_t key_len, char * value, size_t value_len)
489 | {
490 | // sum total size
491 | uint32_t kv_size = sizeof(char) * (key_len + value_len) + uint32_size((uint32_t)key_len) + uint32_size((uint32_t)value_len) + 2;
492 | kv_size += 1 + uint32_size(kv_size);
493 | log_tag * logs = &bder->grp->logs;
494 | // ensure buffer size
495 | if (bder->grp->log_now_buffer - logs->buffer + kv_size > logs->max_buffer_len )
496 | {
497 | // reset log_now_buffer
498 | size_t delta = bder->grp->log_now_buffer - logs->buffer;
499 | _adjust_buffer(logs, delta + kv_size);
500 | bder->grp->log_now_buffer = logs->buffer + delta;
501 | }
502 | uint8_t * buf = (uint8_t *)bder->grp->log_now_buffer;
503 | // key_value header
504 | *buf++ = 0x12;
505 | buf += uint32_pack(uint32_size(key_len) + uint32_size(value_len) + 2 + key_len + value_len, buf);
506 | // key len
507 | *buf++ = 0x0A;
508 | buf += uint32_pack(key_len, buf);
509 | // key
510 | memcpy(buf, key, key_len);
511 | buf += key_len;
512 | // value len
513 | *buf++ = 0x12;
514 | buf += uint32_pack(value_len, buf);
515 | // value
516 | memcpy(buf, value, value_len);
517 | buf += value_len;
518 | bder->grp->log_now_buffer = (char *)buf;
519 | }
520 |
521 | void add_log_end(log_group_builder * bder)
522 | {
523 | log_tag * logs = &bder->grp->logs;
524 | uint32_t log_size = bder->grp->log_now_buffer - logs->now_buffer - INIT_LOG_SIZE_BYTES;
525 | // check total size and uint32_size(total size)
526 |
527 | int32_t header_size = uint32_size(log_size) + 1;
528 |
529 | if (header_size != INIT_LOG_SIZE_BYTES)
530 | {
531 | int32_t delta_header_size = header_size - (int32_t)INIT_LOG_SIZE_BYTES;
532 | // need check buffer size
533 | if (delta_header_size > 0 && bder->grp->log_now_buffer - logs->buffer + delta_header_size > logs->max_buffer_len)
534 | {
535 | // reset log_now_buffer
536 | size_t delta = bder->grp->log_now_buffer - logs->buffer;
537 | _adjust_buffer(logs, delta + delta_header_size);
538 | bder->grp->log_now_buffer = logs->buffer + delta;
539 | }
540 | // move buffer
541 | memmove(logs->now_buffer + header_size, logs->now_buffer + INIT_LOG_SIZE_BYTES, log_size);
542 | }
543 | // set log header
544 | uint8_t * buf = (uint8_t *)logs->now_buffer;
545 | *buf++ = 0x0A;
546 | buf += uint32_pack(log_size, buf);
547 | // do not need to add header_size
548 | logs->now_buffer = (char *)buf + log_size;
549 | logs->now_buffer_len += header_size + log_size;
550 | // update loggroup size
551 | bder->loggroup_size += header_size + log_size;
552 | }
553 |
554 | #endif
555 |
556 |
--------------------------------------------------------------------------------
/src/log_builder.h:
--------------------------------------------------------------------------------
1 | //
2 | // log_builder.h
3 | // log-c-sdk
4 | //
5 | // Created by 王佳玮 on 16/8/23.
6 | // Copyright © 2016年 wangjwchn. All rights reserved.
7 | //
8 | #ifndef LOG_BUILDER_H
9 | #define LOG_BUILDER_H
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | #include "log_define.h"
16 | LOG_CPP_START
17 |
18 | typedef struct _log_tag{
19 | char * buffer;
20 | char * now_buffer;
21 | uint32_t max_buffer_len;
22 | uint32_t now_buffer_len;
23 | }log_tag;
24 |
25 |
26 | typedef struct _log_group{
27 | char * source;
28 | char * topic;
29 | log_tag tags;
30 | log_tag logs;
31 | size_t n_logs;
32 | #ifdef LOG_KEY_VALUE_FLAG
33 | char * log_now_buffer;
34 | #endif
35 | }log_group;
36 |
37 | // todo: rename to compressed_log_buf
38 | typedef struct _lz4_log_buf{
39 | size_t length;
40 | size_t raw_length;
41 | log_compress_type compress_type;
42 | unsigned char data[0];
43 | }lz4_log_buf;
44 |
45 | typedef struct _log_group_builder{
46 | log_group* grp;
47 | size_t loggroup_size;
48 | void * private_value;
49 | uint32_t builder_time;
50 | }log_group_builder;
51 |
52 | typedef struct _log_buffer {
53 | char * buffer;
54 | uint32_t n_buffer;
55 | }log_buf;
56 |
57 | extern log_buf serialize_to_proto_buf_with_malloc(log_group_builder* bder);
58 | extern lz4_log_buf* serialize_with_malloc_compressed(log_group_builder* bder, log_compress_type compress_type);
59 | extern lz4_log_buf* serialize_to_proto_buf_with_malloc_lz4(log_group_builder* bder);
60 | extern lz4_log_buf* serialize_to_proto_buf_with_malloc_zstd(log_group_builder* bder);
61 | // no compress
62 | extern lz4_log_buf* serialize_to_proto_buf_with_malloc_no_compress(log_group_builder* bder);
63 | extern void free_lz4_log_buf(lz4_log_buf* pBuf);
64 | extern log_group_builder* log_group_create();
65 | extern void log_group_destroy(log_group_builder* bder);
66 | extern void add_log_full(log_group_builder* bder, uint32_t logTime, int32_t pair_count, char ** keys, size_t * key_lens, char ** values, size_t * val_lens);
67 | extern void add_source(log_group_builder* bder,const char* src,size_t len);
68 | extern void add_topic(log_group_builder* bder,const char* tpc,size_t len);
69 | extern void add_tag(log_group_builder* bder,const char* k,size_t k_len,const char* v,size_t v_len);
70 | extern void add_pack_id(log_group_builder* bder, const char* pack, size_t pack_len, size_t packNum);
71 | extern void fix_log_group_time(char * pb_buffer, size_t len, uint32_t new_time);
72 |
73 | // if you want to use this functions, add `-DADD_LOG_KEY_VALUE_FUN=ON` for cmake. eg `cmake . -DADD_LOG_KEY_VALUE_FUN=ON`
74 | #ifdef LOG_KEY_VALUE_FLAG
75 | /**
76 | * call it when you want to add a new log
77 | * @note sequence must be : add_log_begin -> add_log_time/add_log_key_value..... -> add_log_end
78 | * @param bder
79 | */
80 | extern void add_log_begin(log_group_builder * bder);
81 |
82 | /**
83 | * set log's time, must been called only once in one log
84 | * @param bder
85 | * @param logTime
86 | */
87 | extern void add_log_time(log_group_builder * bder, uint32_t logTime);
88 |
89 | /**
90 | * add key&value pair to log tail
91 | * @param bder
92 | * @param key
93 | * @param key_len
94 | * @param value
95 | * @param value_len
96 | */
97 | extern void add_log_key_value(log_group_builder *bder, char * key, size_t key_len, char * value, size_t value_len);
98 |
99 | /**
100 | * add log end, call it when you add time and key&value done
101 | * @param bder
102 | */
103 | extern void add_log_end(log_group_builder * bder);
104 |
105 | #endif
106 |
107 | LOG_CPP_END
108 | #endif /* log_builder_h */
109 |
--------------------------------------------------------------------------------
/src/log_define.h:
--------------------------------------------------------------------------------
1 | #ifndef LIBLOG_DEFINE_H
2 | #define LIBLOG_DEFINE_H
3 |
4 |
5 | #if defined(WIN32) && defined(BUILD_SHARED_LIB)
6 | #define LOG_EXPORT _declspec(dllexport)
7 | #else
8 | #define LOG_EXPORT
9 | #endif
10 |
11 | #ifdef __cplusplus
12 | # define LOG_CPP_START extern "C" {
13 | # define LOG_CPP_END }
14 | #else
15 | # define LOG_CPP_START
16 | # define LOG_CPP_END
17 | #endif
18 |
19 | #define LOG_GLOBAL_SSL (1<<0)
20 | #define LOG_GLOBAL_WIN32 (1<<1)
21 | #define LOG_GLOBAL_ALL (LOG_GLOBAL_SSL|LOG_GLOBAL_WIN32)
22 | #define LOG_GLOBAL_NOTHING (0)
23 |
24 | typedef int log_status_t;
25 |
26 | struct _post_log_result
27 | {
28 | int statusCode;
29 | char * errorMessage;
30 | char * requestID;
31 | };
32 |
33 | typedef struct _post_log_result post_log_result;
34 |
35 | enum _auth_version
36 | {
37 | AUTH_VERSION_1 = 1,
38 | AUTH_VERSION_4
39 | };
40 |
41 | typedef enum _auth_version auth_version;
42 |
43 | typedef enum {
44 | LOG_COMPRESS_NONE = 0,
45 | LOG_COMPRESS_LZ4 = 1,
46 | LOG_COMPRESS_ZSTD = 2, // FEATURE_ZSTD_COMPRESS
47 | } log_compress_type;
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/src/log_inner_include.h:
--------------------------------------------------------------------------------
1 | #ifndef LOG_INNER_INCLUDE_H
2 | #define LOG_INNER_INCLUDE_H
3 |
4 | //操作系统头文件
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #ifdef WIN32
13 | #define inline __inline
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | typedef int socklen_t;
20 |
21 |
22 |
23 | #elif defined(_VXWORKS)
24 |
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 |
42 | #include
43 | #include
44 | #include
45 | #include
46 | #include
47 | #include
48 | #include
49 | #include
50 | #include
51 | #include //for vx6
52 | #include
53 | #include
54 |
55 | #else
56 |
57 | #include
58 | #include
59 | #include
60 | #include
61 | #include
62 | #include
63 | #include
64 |
65 | #endif
66 |
67 |
68 | #if defined WIN32 || defined _VXWORKS
69 |
70 | typedef unsigned char u_char;
71 | typedef unsigned char u_int8;
72 | typedef unsigned short u_int16;
73 | typedef unsigned int u_int32;
74 | typedef unsigned __int64 u_int64;
75 | typedef signed char int8;
76 | typedef signed short int16;
77 | typedef signed int int32;
78 | typedef signed __int64 int64;
79 |
80 | #elif defined __linux__
81 |
82 | typedef unsigned char u_char;
83 | typedef unsigned char u_int8;
84 | typedef unsigned short u_int16;
85 | typedef unsigned int u_int32;
86 | typedef unsigned long long u_int64;
87 | typedef signed char int8;
88 | typedef signed short int16;
89 | typedef signed int int32;
90 | typedef long long int64;
91 |
92 | typedef int SOCKET;
93 | #define SOCKET_ERROR -1
94 | #define INVALID_SOCKET -1
95 | #define __in // 参数输入
96 | #define __out // 参数输出
97 | #define closesocket close
98 | #define stricmp strcasecmp
99 | typedef int BOOL;
100 | #define TRUE 1
101 | #define FALSE 0
102 |
103 | #define Sleep(param) usleep(1000*(param))
104 | #define strcpy_s(a, b, c) strcpy(a, c)
105 | #define sprintf_s(a, b, c) sprintf(a, c)
106 | #define strncpy_s(a, b, c, d) strncpy(a, c, d)
107 | #define vsprintf_s(a, b, c, d) vsprintf(a, c, d)
108 | #define _strdup strdup
109 | #define _stricmp stricmp
110 |
111 |
112 | #endif
113 |
114 | #endif //LOG_INNER_INCLUDE_H
115 |
--------------------------------------------------------------------------------
/src/log_multi_thread.h:
--------------------------------------------------------------------------------
1 | #ifndef LOG_MULTI_THREAD_UTIL_H
2 | #define LOG_MULTI_THREAD_UTIL_H
3 |
4 | #include "log_inner_include.h"
5 |
6 |
7 | //不同操作系统资源相关的工具宏定义
8 | #ifdef WIN32
9 | /// * @brief 临界区资源
10 | typedef LPCRITICAL_SECTION CRITICALSECTION;
11 | #define INVALID_CRITSECT NULL
12 |
13 | /**
14 | ********************************************************************
15 | * 创建互斥锁
16 | ********************************************************************
17 | */
18 | static inline CRITICALSECTION CreateCriticalSection()
19 | {
20 | CRITICALSECTION cs = (CRITICAL_SECTION *)malloc(sizeof(CRITICAL_SECTION));
21 | InitializeCriticalSection(cs);
22 | return cs;
23 | }
24 |
25 | /**
26 | ********************************************************************
27 | * 删除互斥锁
28 | ********************************************************************
29 | */
30 | static inline void DeleteCriticalSection(CRITICALSECTION cs) {
31 | if (cs != INVALID_CRITSECT) {
32 | DeleteCriticalSection(cs);
33 | free(cs);
34 | }
35 | }
36 |
37 | /// * @brief 加锁
38 | #define CS_ENTER(cs) EnterCriticalSection(cs)
39 | /// * @brief 解锁
40 | #define CS_LEAVE(cs) LeaveCriticalSection(cs)
41 |
42 | /// * @brief 互斥锁
43 | #define MUTEX CRITICAL_SECTION
44 | /// * @brief 加锁
45 | #define MUTEX_LOCK(mutex) EnterCriticalSection(&mutex)
46 | /// * @brief 解锁
47 | #define MUTEX_UNLOCK(mutex) LeaveCriticalSection(&mutex)
48 | /// * @brief 互斥锁初始化
49 | #define MUTEX_INIT(mutex) InitializeCriticalSection(&mutex)
50 | /// * @brief 互斥锁销毁
51 | #define MUTEX_DESTROY(mutex) DeleteCriticalSection(&mutex)
52 |
53 | //信号量资源
54 | /// * @brief 信号量
55 | typedef HANDLE SEMA;
56 | /// * @brief 等待信号量一定时间
57 | #define SEMA_WAIT_TIME(sema, delay) WaitForSingleObject(sema, delay)
58 | /// * @brief 一直阻塞地进行等待信号量
59 | #define SEMA_WAIT(sema) WaitForSingleObject(sema, INFINITE)
60 | /// * @brief 释放信号量
61 | #define SEMA_POST(sema) ReleaseSemaphore(sema, 1, NULL)
62 | /// * @brief 尝试获取一个信号量
63 | #define SEMA_TRYWAIT(sema) WaitForSingleObject(sema, 0)
64 | /// * @brief 销毁信号量
65 | #define SEMA_DESTROY(sema) CloseHandle(sema)
66 | /// * @brief 初始化信号量, 输入的为:信号量的最大值,初始信号量个数
67 | #define SEMA_INIT(sema, initCount, maxCount) sema = CreateSemaphore(NULL, initCount, maxCount, NULL)
68 | /// * @brief 初始一个带有名称的信号量,用于多进程交互
69 | #define SEMA_INIT_NAME(sema, initCount, maxCount, semaName) sema = CreateSemaphore(NULL, initCount, maxCount, semaName)
70 | /// * @brief 信号量等待超时
71 | #define SEMA_WAIT_TIMEOUT WAIT_TIMEOUT
72 | /// * @brief 等待到信号量
73 | #define SEMA_WAIT_OK WAIT_OBJECT_0
74 |
75 | typedef HANDLE THREAD
76 |
77 | #define snprintf sprintf_s
78 |
79 | #define ATOMICINT volatile long
80 |
81 | #define ATOMICINT_INC(pAtopicInt) InterlockedIncrement(pAtopicInt)
82 | #define ATOMICINT_DEC(pAtopicInt) InterlockedDecrement(pAtopicInt)
83 | #define ATOMICINT_ADD(pAtopicInt, addVal) InterlockedAdd(pAtopicInt, addVal)
84 | #define ATOMICINT_EXCHANGEADD(pAtopicInt, addVal) InterlockedExchangeAdd(pAtopicInt, addVal)
85 | #define ATOMICINT_EXCHANGE(pAtopicInt, exchangeVal) InterlockedExchange(pAtopicInt, exchangeVal)
86 | #define ATOMICINT_COMPAREEXCAHNGE(pAtopicInt, exchangeVal, cmpVal) InterlockedCompareExchange(pAtopicInt, exchangeVal, cmpVal)
87 |
88 | #elif defined(_VXWORKS)
89 |
90 | //临界区资源
91 | typedef SEM_ID CRITICALSECTION;
92 | #define INVALID_CRITSECT NULL
93 | static inline CRITICALSECTION CreateCriticalSection(int spinCount = 0)
94 | {
95 | CRITICALSECTION cs = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE);
96 | if (cs == NULL)
97 | {
98 | perror("vxworks create MUTUAL EXCLUSION SEMAPHORE failed\n");
99 | }
100 | return cs;
101 | }
102 |
103 | static inline void DeleteCriticalSection(CRITICALSECTION & cs)
104 | {
105 | semDelete(cs);
106 | cs = INVALID_CRITSECT;
107 | }
108 |
109 | #define CS_ENTER(cs) semTake(cs, WAIT_FOREVER)
110 | #define CS_LEAVE(cs) semGive(cs)
111 |
112 | #define MUTEX SEM_ID
113 | #define MUTEX_LOCK(mutex) semTake(mutex, WAIT_FOREVER)
114 | #define MUTEX_UNLOCK(mutex) semGive(mutex)
115 | #define MUTEX_INIT(mutex) mutex = semBCreate(SEM_Q_FIFO,SEM_FULL)
116 | #define MUTEX_DESTROY(mutex) semDelete(mutex)
117 | //信号量资源
118 | #define SEMA SEM_ID
119 | #define SEMA_WAIT_TIME(sema,delay) semTake(sema, delay)
120 | #define SEMA_WAIT(sema) semTake(sema, WAIT_FOREVER)
121 | #define SEMA_POST(sema) semGive(sema)
122 | #define SEMA_DESTROY(sema) semDelete(sema)
123 | #define SEMA_INIT(sema, initCount, maxCount) sema = semCCreate(SEM_Q_FIFO,initCount)
124 | #define SEMA_WAIT_TIMEOUT ERROR
125 | //线程资源
126 | #define THREADID int
127 | #define SOCKET int
128 | #define closesocket(s_) close(s_)
129 | #define SOCKET_ERROR -1
130 |
131 | #else
132 |
133 | //临界区资源
134 | typedef pthread_mutex_t* CRITICALSECTION;
135 | #define INVALID_CRITSECT NULL
136 |
137 | static inline CRITICALSECTION CreateCriticalSection() {
138 | CRITICALSECTION cs = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
139 | assert(cs != INVALID_CRITSECT);
140 | pthread_mutex_init(cs, NULL);
141 | return cs;
142 | }
143 |
144 | static inline void DeleteCriticalSection(CRITICALSECTION cs) {
145 | if (cs != INVALID_CRITSECT) {
146 | pthread_mutex_destroy(cs);
147 | free(cs);
148 | }
149 | }
150 |
151 | #define CS_ENTER(cs) pthread_mutex_lock(cs)
152 | #define CS_LEAVE(cs) pthread_mutex_unlock(cs)
153 |
154 | typedef pthread_cond_t* COND;
155 | typedef int COND_WAIT_T;
156 | #define COND_WAIT_OK 0
157 | #define COND_WAIT_TIMEOUT ETIMEDOUT
158 |
159 | #define INVALID_COND NULL
160 |
161 | static inline COND CreateCond() {
162 | COND cond = (COND)malloc(sizeof(pthread_cond_t));
163 | assert(cond != INVALID_CRITSECT);
164 | pthread_cond_init(cond, NULL);
165 | return cond;
166 | }
167 |
168 | static inline void DeleteCond(COND cond) {
169 | if (cond != INVALID_COND) {
170 | pthread_cond_destroy(cond);
171 | free(cond);
172 | }
173 | }
174 |
175 | #define COND_SIGNAL(cond) pthread_cond_signal(cond)
176 | #define COND_SIGNAL_ALL(cond) pthread_cond_broadcast(cond)
177 |
178 | static inline COND_WAIT_T COND_WAIT_TIME(COND cond, CRITICALSECTION cs, int32_t waitMs) {
179 | struct timeval now;
180 | struct timespec outTime;
181 | gettimeofday(&now, NULL);
182 |
183 | now.tv_usec += ((waitMs) % 1000) * 1000;
184 | if (now.tv_usec > 1000000)
185 | {
186 | now.tv_usec -= 1000000;
187 | ++now.tv_sec;
188 | }
189 | outTime.tv_sec = now.tv_sec + (waitMs) / 1000;
190 | outTime.tv_nsec = now.tv_usec * 1000;
191 | return pthread_cond_timedwait(cond, cs, &outTime);
192 | }
193 |
194 | static inline int64_t GET_TIME_US() {
195 | struct timeval now;
196 | gettimeofday(&now, NULL);
197 | return (int64_t)now.tv_sec * 1000000 + now.tv_usec;
198 | }
199 |
200 |
201 | #define MUTEX pthread_mutex_t
202 | #define SEMA sem_t
203 | #define MUTEX_LOCK(mutex) pthread_mutex_lock(&mutex)
204 | #define MUTEX_UNLOCK(mutex) pthread_mutex_unlock(&mutex)
205 | #define MUTEX_INIT(mutex) pthread_mutex_init(&mutex,NULL)
206 | #define MUTEX_DESTROY(mutex) pthread_mutex_destroy(&mutex)
207 |
208 | // not supported in mac os
209 | #ifdef __linux__
210 | static inline int sema_wait_time_(sem_t* sema, unsigned int delayMs)
211 | {
212 | struct timespec ts;
213 |
214 | struct timeval tv;
215 |
216 | gettimeofday(&tv, NULL);
217 | tv.tv_usec += (delayMs % 1000) * 1000;
218 | tv.tv_sec += delayMs / 1000;
219 | if (tv.tv_usec > 1000000) {
220 | tv.tv_usec -= 1000000;
221 | ++tv.tv_sec;
222 | }
223 |
224 | ts.tv_sec = tv.tv_sec;
225 | ts.tv_nsec = tv.tv_usec * 1000;
226 |
227 | return sem_timedwait(sema, &ts) == 0 ? 0 : ETIMEDOUT;
228 | }
229 |
230 | #define SEMA_WAIT_TIME(sema,delay) sema_wait_time_(&sema,delay)
231 |
232 | #endif
233 |
234 | #define SEMA_WAIT(sema) sem_wait(&sema)
235 | #define SEMA_POST(sema) sem_post(&sema)
236 | #define SEMA_TRYWAIT(sema) sem_trywait(&sema)
237 | #define SEMA_DESTROY(sema) sem_destroy(&sema)
238 | #define SEMA_INIT(sema, initCount, maxCount) sem_init(&sema,0,initCount)
239 | #define SEMA_INIT_NAME(sema, initCount, maxCount, semaName) sema = sem_open(semaName, O_CREAT, 0, initCount)
240 | #define WAIT_OBJECT_0 0
241 | #define WAIT_TIMEOUT ETIMEDOUT
242 | #define SEMA_WAIT_TIMEOUT ETIMEDOUT
243 | #define SEMA_WAIT_OK 0
244 |
245 | typedef pthread_t THREAD;
246 | #define THREAD_INIT(thread, func, param) pthread_create(&(thread), NULL, func, param)
247 | #define THREAD_JOIN(thread) pthread_join(thread, NULL)
248 |
249 | #define ATOMICINT volatile long
250 |
251 | #define ATOMICINT_INC(pAtopicInt) __sync_add_and_fetch(pAtopicInt, 1)
252 | #define ATOMICINT_DEC(pAtopicInt) __sync_add_and_fetch(pAtopicInt, -1)
253 | #define ATOMICINT_ADD(pAtopicInt, addVal) __sync_add_and_fetch(pAtopicInt, addVal)
254 | #define ATOMICINT_EXCHANGEADD(pAtopicInt, addVal) __sync_fetch_and_add(pAtopicInt, addVal)
255 | #define ATOMICINT_EXCHANGE(pAtopicInt, exchangeVal) __sync_val_compare_and_swap(pAtopicInt, *pAtopicInt, exchangeVal)
256 | #define ATOMICINT_COMPAREEXCAHNGE(pAtopicInt, exchangeVal, cmpVal) __sync_val_compare_and_swap(pAtopicInt, cmpVal, exchangeVal)
257 |
258 | typedef struct _FILETIME
259 | {
260 | unsigned long dwLowDateTime;
261 | unsigned long dwHighDateTime;
262 | } FILETIME;
263 |
264 | #endif //WIN32
265 |
266 | #endif //LOG_MULTI_THREAD_UTIL_H
267 |
--------------------------------------------------------------------------------
/src/log_producer_client.c:
--------------------------------------------------------------------------------
1 | //
2 | // Created by ZhangCheng on 20/11/2017.
3 | //
4 |
5 | #include "log_producer_client.h"
6 | #include "log_producer_manager.h"
7 | #include "inner_log.h"
8 | #include "log_api.h"
9 | #include
10 | #include
11 |
12 |
13 | static uint32_t s_init_flag = 0;
14 | static log_producer_result s_last_result = 0;
15 |
16 | extern log_queue * g_sender_data_queue;
17 | extern THREAD * g_send_threads;
18 | extern int32_t g_send_thread_count;
19 | extern volatile uint8_t g_send_thread_destroy;
20 |
21 | extern void * log_producer_send_thread_global(void * param);
22 | extern void log_producer_send_thread_global_inner(log_producer_send_param * send_param);
23 | extern void destroy_log_producer_manager_tail(log_producer_manager * manager);
24 |
25 | typedef struct _producer_client_private {
26 |
27 | log_producer_manager * producer_manager;
28 | log_producer_config * producer_config;
29 | }producer_client_private ;
30 |
31 | struct _log_producer {
32 | log_producer_client * root_client;
33 | };
34 |
35 | log_producer_result log_producer_env_init(int32_t log_global_flag)
36 | {
37 | // if already init, just return s_last_result
38 | if (s_init_flag == 1)
39 | {
40 | return s_last_result;
41 | }
42 | s_init_flag = 1;
43 | if (0 != sls_log_init(log_global_flag))
44 | {
45 | s_last_result = LOG_PRODUCER_INVALID;
46 | }
47 | else
48 | {
49 | s_last_result = LOG_PRODUCER_OK;
50 | }
51 | return s_last_result;
52 | }
53 |
54 | void log_producer_env_destroy()
55 | {
56 | if (s_init_flag == 0)
57 | {
58 | return;
59 | }
60 | s_init_flag = 0;
61 |
62 | // destroy global send threads
63 | if (g_send_threads != NULL) {
64 | g_send_thread_destroy = 1;
65 | aos_info_log("join global sender thread pool begin, thread count : %d", g_send_thread_count);
66 | int32_t threadId = 0;
67 | for (; threadId < g_send_thread_count; ++threadId)
68 | {
69 | THREAD_JOIN(g_send_threads[threadId]);
70 | aos_info_log("join one global sender thread pool done, thread id : %d", threadId);
71 | }
72 | free(g_send_threads);
73 | aos_info_log("flush out global sender queue begin");
74 | while (log_queue_size(g_sender_data_queue) > 0)
75 | {
76 | // @note : we must process all data in queue, otherwise this will cause memory leak
77 | log_producer_send_param * send_param = (log_producer_send_param *)log_queue_trypop(g_sender_data_queue);
78 | log_producer_send_thread_global_inner(send_param);
79 | }
80 | aos_info_log("flush out global sender queue success");
81 | log_queue_destroy(g_sender_data_queue);
82 | g_sender_data_queue = NULL;
83 | g_send_thread_destroy = 0;
84 | g_send_thread_count = 0;
85 | g_send_threads = NULL;
86 | aos_info_log("join global sender thread pool success");
87 | }
88 | sls_log_destroy();
89 | }
90 |
91 | log_producer * create_log_producer(log_producer_config * config, on_log_producer_send_done_function send_done_function)
92 | {
93 | if (!log_producer_config_is_valid(config))
94 | {
95 | return NULL;
96 | }
97 | log_producer * producer = (log_producer *)malloc(sizeof(log_producer));
98 | log_producer_client * producer_client = (log_producer_client *)malloc(sizeof(log_producer_client));
99 | producer_client_private * client_private = (producer_client_private *)malloc(sizeof(producer_client_private));
100 | producer_client->private_data = client_private;
101 | client_private->producer_config = config;
102 | client_private->producer_manager = create_log_producer_manager(config);
103 | client_private->producer_manager->send_done_function = send_done_function;
104 |
105 | if(client_private->producer_manager == NULL)
106 | {
107 | // free
108 | free(producer_client);
109 | free(client_private);
110 | free(producer);
111 | return NULL;
112 | }
113 | aos_debug_log("create producer client success, config : %s", config->logstore);
114 | producer_client->valid_flag = 1;
115 | producer->root_client = producer_client;
116 | return producer;
117 | }
118 |
119 |
120 | void destroy_log_producer(log_producer * producer)
121 | {
122 | if (producer == NULL)
123 | {
124 | return;
125 | }
126 | log_producer_client * client = producer->root_client;
127 | client->valid_flag = 0;
128 | producer_client_private * client_private = (producer_client_private *)client->private_data;
129 | destroy_log_producer_manager(client_private->producer_manager);
130 |
131 | free(client_private);
132 | free(client);
133 | free(producer);
134 | }
135 |
136 | extern log_producer_client * get_log_producer_client(log_producer * producer, const char * config_name)
137 | {
138 | if (producer == NULL)
139 | {
140 | return NULL;
141 | }
142 | return producer->root_client;
143 | }
144 |
145 | void log_producer_client_network_recover(log_producer_client * client)
146 | {
147 | if (client == NULL)
148 | {
149 | return;
150 | }
151 | log_producer_manager * manager = ((producer_client_private *)client->private_data)->producer_manager;
152 | manager->networkRecover = 1;
153 | }
154 |
155 | log_producer_result log_producer_client_add_log(log_producer_client * client, int32_t kv_count, ...)
156 | {
157 | if (client == NULL || !client->valid_flag)
158 | {
159 | return LOG_PRODUCER_INVALID;
160 | }
161 | va_list argp;
162 | va_start(argp, kv_count);
163 |
164 | int32_t pairs = kv_count / 2;
165 |
166 | char ** keys = (char **)malloc(pairs * sizeof(char *));
167 | char ** values = (char **)malloc(pairs * sizeof(char *));
168 | size_t * key_lens = (size_t *)malloc(pairs * sizeof(size_t));
169 | size_t * val_lens = (size_t *)malloc(pairs * sizeof(size_t));
170 |
171 | int32_t i = 0;
172 | for (; i < pairs; ++i)
173 | {
174 | const char * key = va_arg(argp, const char *);
175 | const char * value = va_arg(argp, const char *);
176 | keys[i] = (char *)key;
177 | values[i] = (char *)value;
178 | key_lens[i] = strlen(key);
179 | val_lens[i] = strlen(value);
180 | }
181 |
182 | log_producer_manager * manager = ((producer_client_private *)client->private_data)->producer_manager;
183 |
184 | log_producer_result rst = log_producer_manager_add_log(manager, (uint32_t)time(NULL), pairs, keys, key_lens, values, val_lens);
185 | free(keys);
186 | free(values);
187 | free(key_lens);
188 | free(val_lens);
189 | return rst;
190 | }
191 |
192 | log_producer_result log_producer_client_add_log_with_len(log_producer_client * client, int32_t pair_count, char ** keys, size_t * key_lens, char ** values, size_t * val_lens)
193 | {
194 | return log_producer_client_add_log_with_len_time(client, (uint32_t)time(NULL), pair_count, keys, key_lens, values, val_lens);
195 | }
196 |
197 | log_producer_result log_producer_client_add_log_with_len_time(log_producer_client * client, uint32_t time_sec, int32_t pair_count, char ** keys, size_t * key_lens, char ** values, size_t * value_lens)
198 | {
199 | if (client == NULL || !client->valid_flag)
200 | {
201 | return LOG_PRODUCER_INVALID;
202 | }
203 |
204 | log_producer_manager * manager = ((producer_client_private *)client->private_data)->producer_manager;
205 |
206 | return log_producer_manager_add_log(manager, time_sec, pair_count, keys, key_lens, values, value_lens);
207 |
208 | }
209 |
210 |
211 |
212 | log_producer_result log_producer_client_add_raw_log_buffer(log_producer_client * client, size_t log_bytes, size_t compressed_bytes, const unsigned char * raw_buffer)
213 | {
214 | if (client == NULL || !client->valid_flag || raw_buffer == NULL)
215 | {
216 | return LOG_PRODUCER_INVALID;
217 | }
218 |
219 | log_producer_manager * manager = ((producer_client_private *)client->private_data)->producer_manager;
220 |
221 | return log_producer_manager_send_raw_buffer(manager, log_bytes, compressed_bytes, raw_buffer);
222 | }
223 |
224 | log_producer_result log_producer_global_send_thread_init(int32_t log_global_send_thread_count, int32_t log_global_send_queue_size)
225 | {
226 | if (log_global_send_thread_count <= 0 || log_global_send_queue_size <= 0 || g_send_threads != NULL) {
227 | return LOG_PRODUCER_INVALID;
228 | }
229 | g_send_thread_count = log_global_send_thread_count;
230 | g_send_threads = (THREAD *)malloc(sizeof(THREAD) * g_send_thread_count);
231 |
232 | g_sender_data_queue = log_queue_create(log_global_send_queue_size);
233 | g_send_thread_destroy = 0;
234 | int32_t threadId = 0;
235 | for (; threadId < g_send_thread_count; ++threadId)
236 | {
237 | THREAD_INIT(g_send_threads[threadId], log_producer_send_thread_global, g_sender_data_queue);
238 | }
239 | return LOG_PRODUCER_OK;
240 | }
241 |
--------------------------------------------------------------------------------
/src/log_producer_client.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by ZhangCheng on 20/11/2017.
3 | //
4 |
5 | #ifndef LOG_C_SDK_LOG_PRODUCER_CLIENT_H
6 | #define LOG_C_SDK_LOG_PRODUCER_CLIENT_H
7 |
8 |
9 | #include "log_define.h"
10 | #include "log_producer_config.h"
11 | LOG_CPP_START
12 |
13 |
14 | /**
15 | * log producer client
16 | */
17 | typedef struct _log_producer_client
18 | {
19 | volatile int32_t valid_flag;
20 | int32_t log_level;
21 | void * private_data;
22 | }log_producer_client;
23 |
24 | typedef struct _log_producer log_producer;
25 |
26 | /**
27 | * init log producer environment
28 | * @param log_global_flag global log config flag
29 | * @note should been called before create any log producer client
30 | * @note no multi thread safe
31 | * @return OK if success, others the error code
32 | */
33 | LOG_EXPORT log_producer_result log_producer_env_init(int32_t log_global_flag);
34 |
35 | /**
36 | * create global send thread pool
37 | *
38 | * @note if producer have no send thread, use global send thread pool to send logs
39 | * @note this thread pool will been destroyed when you call log_producer_env_destroy
40 | * @note not thread safe
41 | *
42 | * @param log_global_send_thread_count
43 | * @param log_global_send_queue_size recommend values : for server apps, set 10000; for client apps, set 1000; for iot devices, set 100
44 | * @return
45 | */
46 | LOG_EXPORT log_producer_result log_producer_global_send_thread_init(int32_t log_global_send_thread_count, int32_t log_global_send_queue_size);
47 |
48 | /**
49 | * destroy log producer environment
50 | * @note should been called after all log producer clients destroyed
51 | * @note no multi thread safe
52 | */
53 | LOG_EXPORT void log_producer_env_destroy();
54 |
55 | /**
56 | * create log producer with a producer config
57 | * @param config log_producer_config
58 | * @param send_done_function this function will be called when send done(can be ok or fail), set to NULL if you don't care about it
59 | * @return producer client ptr, NULL if create fail
60 | */
61 | LOG_EXPORT log_producer * create_log_producer(log_producer_config * config, on_log_producer_send_done_function send_done_function);
62 |
63 | /**
64 | * destroy log producer
65 | * @param producer
66 | * @note no multi thread safe
67 | */
68 | LOG_EXPORT void destroy_log_producer(log_producer * producer);
69 |
70 | /**
71 | * get client from producer
72 | * @param producer
73 | * @param config_name useless now, set NULL
74 | * @return the specific producer client, root client if config_name is NULL or no specific config,
75 | */
76 | LOG_EXPORT log_producer_client * get_log_producer_client(log_producer * producer, const char * config_name);
77 |
78 |
79 | /**
80 | * force send data when network recover
81 | * @param client
82 | */
83 | LOG_EXPORT void log_producer_client_network_recover(log_producer_client * client);
84 |
85 | /**
86 | * add log to producer, this may return LOG_PRODUCER_DROP_ERROR if buffer is full.
87 | * if you care about this log very much, retry when return LOG_PRODUCER_DROP_ERROR.
88 | *
89 | * @example log_producer_client_add_log(client, 4, "key_1", "value_1", "key_2", "value_2")
90 | * @note log param ... must be const char * or char * with '\0' ended
91 | * @note multi thread safe
92 | * @param client
93 | * @param kv_count key value count
94 | * @param ... log params : key, value pairs, must be const char * or char *
95 | * @return ok if success, LOG_PRODUCER_DROP_ERROR if buffer is full, LOG_PRODUCER_INVALID if client is destroyed.
96 | */
97 | LOG_EXPORT log_producer_result log_producer_client_add_log(log_producer_client * client, int32_t kv_count, ...);
98 |
99 | /**
100 | * add log to producer, this may return LOG_PRODUCER_DROP_ERROR if buffer is full.
101 | * if you care about this log very much, retry when return LOG_PRODUCER_DROP_ERROR.
102 | *
103 | * @param client
104 | * @param pair_count key value pair count
105 | * @note pair_count not kv_count
106 | * @param keys the key array
107 | * @param key_lens the key len array
108 | * @param values the value array
109 | * @param value_lens the value len array
110 | * @return ok if success, LOG_PRODUCER_DROP_ERROR if buffer is full, LOG_PRODUCER_INVALID if client is destroyed.
111 | */
112 | LOG_EXPORT log_producer_result log_producer_client_add_log_with_len(log_producer_client * client, int32_t pair_count, char ** keys, size_t * key_lens, char ** values, size_t * value_lens);
113 |
114 | /**
115 | * add log to producer, this may return LOG_PRODUCER_DROP_ERROR if buffer is full.
116 | * if you care about this log very much, retry when return LOG_PRODUCER_DROP_ERROR.
117 | *
118 | * @param client
119 | * @param time_sec log time
120 | * @param pair_count key value pair count
121 | * @note pair_count not kv_count
122 | * @param keys the key array
123 | * @param key_lens the key len array
124 | * @param values the value array
125 | * @param value_lens the value len array
126 | * @param flush if this log info need to send right, 1 mean flush and 0 means NO
127 | * @return ok if success, LOG_PRODUCER_DROP_ERROR if buffer is full, LOG_PRODUCER_INVALID if client is destroyed, LOG_PRODUCER_PERSISTENT_ERROR is save binlog failed.
128 | */
129 | LOG_EXPORT log_producer_result log_producer_client_add_log_with_len_time(log_producer_client * client, uint32_t time_sec, int32_t pair_count, char ** keys, size_t * key_lens, char ** values, size_t * value_lens);
130 |
131 |
132 | /**
133 | * add raw log buffer to client, this function is used to send buffers which can not send out when producer has destroyed
134 | * @param client
135 | * @param log_bytes
136 | * @param compressed_bytes
137 | * @param raw_buffer
138 | * @return ok if success, LOG_PRODUCER_DROP_ERROR if buffer is full, LOG_PRODUCER_INVALID if client is destroyed.
139 | */
140 | LOG_EXPORT log_producer_result log_producer_client_add_raw_log_buffer(log_producer_client * client, size_t log_bytes, size_t compressed_bytes, const unsigned char * raw_buffer);
141 |
142 | LOG_CPP_END
143 |
144 | #endif //LOG_C_SDK_LOG_PRODUCER_CLIENT_H
145 |
--------------------------------------------------------------------------------
/src/log_producer_common.c:
--------------------------------------------------------------------------------
1 | //
2 | // Created by ZhangCheng on 21/11/2017.
3 | //
4 |
5 | #include "log_producer_common.h"
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | log_producer_result LOG_PRODUCER_OK = 0;
12 | log_producer_result LOG_PRODUCER_INVALID = 1;
13 | log_producer_result LOG_PRODUCER_WRITE_ERROR = 2;
14 | log_producer_result LOG_PRODUCER_DROP_ERROR = 3;
15 | log_producer_result LOG_PRODUCER_SEND_NETWORK_ERROR = 4;
16 | log_producer_result LOG_PRODUCER_SEND_QUOTA_ERROR = 5;
17 | log_producer_result LOG_PRODUCER_SEND_UNAUTHORIZED = 6;
18 | log_producer_result LOG_PRODUCER_SEND_SERVER_ERROR = 7;
19 | log_producer_result LOG_PRODUCER_SEND_DISCARD_ERROR = 8;
20 | log_producer_result LOG_PRODUCER_SEND_TIME_ERROR = 9;
21 | log_producer_result LOG_PRODUCER_SEND_EXIT_BUFFERED = 10;
22 |
23 |
24 | int is_log_producer_result_ok(log_producer_result rst)
25 | {
26 | return rst == LOG_PRODUCER_OK;
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/src/log_producer_common.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by ZhangCheng on 21/11/2017.
3 | //
4 |
5 | #ifndef LOG_C_SDK_LOG_PRODUCER_COMMON_H_H
6 | #define LOG_C_SDK_LOG_PRODUCER_COMMON_H_H
7 |
8 | #include "log_define.h"
9 | #include
10 | #include
11 | LOG_CPP_START
12 |
13 |
14 | /**
15 | * log producer result for all operation
16 | */
17 | typedef int log_producer_result;
18 |
19 | /**
20 | * callback function for producer client
21 | * @param config_name this is logstore name
22 | * @param result send result
23 | * @param log_bytes log group packaged bytes
24 | * @param compressed_bytes lz4 compressed bytes
25 | * @param req_id request id. Must check NULL when use it
26 | * @param error_message if send result is not ok, error message is set. Must check NULL when use it
27 | * @param raw_buffer lz4 buffer
28 | * @note you can only read raw_buffer, but can't modify or free it
29 | */
30 | typedef void (*on_log_producer_send_done_function)(const char * config_name, log_producer_result result, size_t log_bytes, size_t compressed_bytes, const char * req_id, const char * error_message, const unsigned char * raw_buffer);
31 |
32 | extern log_producer_result LOG_PRODUCER_OK;
33 | extern log_producer_result LOG_PRODUCER_INVALID;
34 | extern log_producer_result LOG_PRODUCER_WRITE_ERROR;
35 | extern log_producer_result LOG_PRODUCER_DROP_ERROR;
36 | extern log_producer_result LOG_PRODUCER_SEND_NETWORK_ERROR;
37 | extern log_producer_result LOG_PRODUCER_SEND_QUOTA_ERROR;
38 | extern log_producer_result LOG_PRODUCER_SEND_UNAUTHORIZED;
39 | extern log_producer_result LOG_PRODUCER_SEND_SERVER_ERROR;
40 | extern log_producer_result LOG_PRODUCER_SEND_DISCARD_ERROR;
41 | extern log_producer_result LOG_PRODUCER_SEND_TIME_ERROR;
42 | // this error code is passed when producer is being destroyed, you should save this buffer to local
43 | extern log_producer_result LOG_PRODUCER_SEND_EXIT_BUFFERED;
44 |
45 |
46 | /**
47 | * check if rst if ok
48 | * @param rst
49 | * @return 1 if ok, 0 not ok
50 | */
51 | LOG_EXPORT int is_log_producer_result_ok(log_producer_result rst);
52 |
53 |
54 | LOG_CPP_END
55 |
56 | #endif //LOG_C_SDK_LOG_PRODUCER_COMMON_H_H
57 |
--------------------------------------------------------------------------------
/src/log_producer_config.c:
--------------------------------------------------------------------------------
1 | //
2 | // Created by ZhangCheng on 20/11/2017.
3 | //
4 |
5 | #include "log_producer_config.h"
6 | #include "sds.h"
7 | #include
8 | #include
9 | #include "inner_log.h"
10 |
11 | static void _set_default_producer_config(log_producer_config * pConfig)
12 | {
13 | pConfig->logBytesPerPackage = 3 * 1024 * 1024;
14 | pConfig->logCountPerPackage = 2048;
15 | pConfig->packageTimeoutInMS = 3000;
16 | pConfig->maxBufferBytes = 64 * 1024 * 1024;
17 |
18 | pConfig->connectTimeoutSec = 10;
19 | pConfig->sendTimeoutSec = 15;
20 | pConfig->destroySenderWaitTimeoutSec = 1;
21 | pConfig->destroyFlusherWaitTimeoutSec = 1;
22 | pConfig->compressType = LOG_COMPRESS_LZ4;
23 | pConfig->using_https = 0;
24 | }
25 |
26 |
27 | static void _copy_config_string(const char * value, sds * src_value)
28 | {
29 | if (value == NULL || src_value == NULL)
30 | {
31 | return;
32 | }
33 | size_t strLen = strlen(value);
34 | if (*src_value == NULL)
35 | {
36 | *src_value = sdsnewEmpty(strLen);
37 | }
38 | *src_value = sdscpylen(*src_value, value, strLen);
39 | }
40 |
41 |
42 | log_producer_config * create_log_producer_config()
43 | {
44 | log_producer_config* pConfig = (log_producer_config*)malloc(sizeof(log_producer_config));
45 | memset(pConfig, 0, sizeof(log_producer_config));
46 | _set_default_producer_config(pConfig);
47 | pConfig->authVersion = AUTH_VERSION_1;
48 | pConfig->region = NULL;
49 | return pConfig;
50 | }
51 |
52 |
53 | void destroy_log_producer_config(log_producer_config * pConfig)
54 | {
55 | if (pConfig->project != NULL)
56 | {
57 | sdsfree(pConfig->project);
58 | }
59 | if (pConfig->logstore != NULL)
60 | {
61 | sdsfree(pConfig->logstore);
62 | }
63 | if (pConfig->endpoint != NULL)
64 | {
65 | sdsfree(pConfig->endpoint);
66 | }
67 | if (pConfig->accessKey != NULL)
68 | {
69 | sdsfree(pConfig->accessKey);
70 | }
71 | if (pConfig->accessKeyId != NULL)
72 | {
73 | sdsfree(pConfig->accessKeyId);
74 | }
75 | if (pConfig->topic != NULL)
76 | {
77 | sdsfree(pConfig->topic);
78 | }
79 | if (pConfig->source != NULL)
80 | {
81 | sdsfree(pConfig->source);
82 | }
83 | if (pConfig->netInterface != NULL)
84 | {
85 | sdsfree(pConfig->netInterface);
86 | }
87 | if (pConfig->remote_address != NULL)
88 | {
89 | sdsfree(pConfig->remote_address);
90 | }
91 | if (pConfig->securityToken != NULL)
92 | {
93 | sdsfree(pConfig->securityToken);
94 | }
95 | if (pConfig->securityTokenLock != NULL)
96 | {
97 | DeleteCriticalSection(pConfig->securityTokenLock);
98 | }
99 | if (pConfig->tagCount > 0 && pConfig->tags != NULL)
100 | {
101 | int i = 0;
102 | for (; i < pConfig->tagCount; ++i)
103 | {
104 | sdsfree(pConfig->tags[i].key);
105 | sdsfree(pConfig->tags[i].value);
106 | }
107 | free(pConfig->tags);
108 | }
109 | if (pConfig->region != NULL)
110 | {
111 | sdsfree(pConfig->region);
112 | }
113 | free(pConfig);
114 | }
115 |
116 | #ifdef LOG_PRODUCER_DEBUG
117 | void log_producer_config_print(log_producer_config * pConfig, FILE * file)
118 | {
119 | fprintf(file, "endpoint : %s\n", pConfig->endpoint);
120 | fprintf(file,"project : %s\n", pConfig->project);
121 | fprintf(file,"logstore : %s\n", pConfig->logstore);
122 | fprintf(file,"accessKeyId : %s\n", pConfig->accessKeyId);
123 | fprintf(file,"accessKey : %s\n", pConfig->accessKey);
124 | fprintf(file,"configName : %s\n", pConfig->configName);
125 | fprintf(file,"topic : %s\n", pConfig->topic);
126 | fprintf(file,"logLevel : %d\n", pConfig->logLevel);
127 |
128 | fprintf(file,"packageTimeoutInMS : %d\n", pConfig->packageTimeoutInMS);
129 | fprintf(file, "logCountPerPackage : %d\n", pConfig->logCountPerPackage);
130 | fprintf(file, "logBytesPerPackage : %d\n", pConfig->logBytesPerPackage);
131 | fprintf(file, "maxBufferBytes : %d\n", pConfig->maxBufferBytes);
132 |
133 |
134 | fprintf(file, "tags: \n");
135 | int32_t i = 0;
136 | for (i = 0; i < pConfig->tagCount; ++i)
137 | {
138 | fprintf(file, "tag key : %s, value : %s \n", pConfig->tags[i].key, pConfig->tags[i].value);
139 | }
140 |
141 | }
142 | #endif
143 |
144 | void log_producer_config_set_packet_timeout(log_producer_config * config, int32_t time_out_ms)
145 | {
146 | if (config == NULL || time_out_ms < 0)
147 | {
148 | return;
149 | }
150 | config->packageTimeoutInMS = time_out_ms;
151 | }
152 | void log_producer_config_set_packet_log_count(log_producer_config * config, int32_t log_count)
153 | {
154 | if (config == NULL || log_count < 0)
155 | {
156 | return;
157 | }
158 | config->logCountPerPackage = log_count;
159 | }
160 | void log_producer_config_set_packet_log_bytes(log_producer_config * config, int32_t log_bytes)
161 | {
162 | if (config == NULL || log_bytes < 0)
163 | {
164 | return;
165 | }
166 | config->logBytesPerPackage = log_bytes;
167 | }
168 | void log_producer_config_set_max_buffer_limit(log_producer_config * config, int64_t max_buffer_bytes)
169 | {
170 | if (config == NULL || max_buffer_bytes < 0)
171 | {
172 | return;
173 | }
174 | config->maxBufferBytes = max_buffer_bytes;
175 | }
176 |
177 | void log_producer_config_set_send_thread_count(log_producer_config * config, int32_t thread_count)
178 | {
179 | if (config == NULL || thread_count < 0)
180 | {
181 | return;
182 | }
183 | config->sendThreadCount = thread_count;
184 | }
185 |
186 |
187 | void log_producer_config_set_net_interface(log_producer_config * config, const char * net_interface)
188 | {
189 | if (config == NULL || net_interface == NULL)
190 | {
191 | return;
192 | }
193 | _copy_config_string(net_interface, &config->netInterface);
194 | }
195 |
196 | void log_producer_config_set_remote_address(log_producer_config * config, const char * remote_address)
197 | {
198 | if (config == NULL || remote_address == NULL)
199 | {
200 | return;
201 | }
202 | _copy_config_string(remote_address, &config->remote_address);
203 | }
204 |
205 | void log_producer_config_set_connect_timeout_sec(log_producer_config * config, int32_t connect_timeout_sec)
206 | {
207 | if (config == NULL || connect_timeout_sec <= 0)
208 | {
209 | return;
210 | }
211 | config->connectTimeoutSec = connect_timeout_sec;
212 | }
213 |
214 |
215 | void log_producer_config_set_send_timeout_sec(log_producer_config * config, int32_t send_timeout_sec)
216 | {
217 | if (config == NULL || send_timeout_sec <= 0)
218 | {
219 | return;
220 | }
221 | config->sendTimeoutSec = send_timeout_sec;
222 | }
223 |
224 | void log_producer_config_set_destroy_flusher_wait_sec(log_producer_config * config, int32_t destroy_flusher_wait_sec)
225 | {
226 | if (config == NULL || destroy_flusher_wait_sec <= 0)
227 | {
228 | return;
229 | }
230 | config->destroyFlusherWaitTimeoutSec = destroy_flusher_wait_sec;
231 | }
232 |
233 | void log_producer_config_set_destroy_sender_wait_sec(log_producer_config * config, int32_t destroy_sender_wait_sec)
234 | {
235 | if (config == NULL || destroy_sender_wait_sec <= 0)
236 | {
237 | return;
238 | }
239 | config->destroySenderWaitTimeoutSec = destroy_sender_wait_sec;
240 | }
241 |
242 | void log_producer_config_set_compress_type(log_producer_config * config, int32_t compress_type)
243 | {
244 | if (config == NULL ||
245 | compress_type < (int32_t)LOG_COMPRESS_NONE ||
246 | compress_type > (int32_t)LOG_COMPRESS_ZSTD)
247 | {
248 | return;
249 | }
250 | config->compressType = (log_compress_type)compress_type;
251 | }
252 |
253 | void log_producer_config_set_using_http(log_producer_config * config, int32_t using_https)
254 | {
255 | if (config == NULL || using_https < 0)
256 | {
257 | return;
258 | }
259 | config->using_https = using_https;
260 | }
261 |
262 | void log_producer_config_set_log_queue_size(log_producer_config * config, int32_t log_queue_size)
263 | {
264 | if (config == NULL || log_queue_size < 0)
265 | {
266 | return;
267 | }
268 | config->logQueueSize = log_queue_size;
269 | }
270 |
271 | void log_producer_config_add_tag(log_producer_config * pConfig, const char * key, const char * value)
272 | {
273 | if(key == NULL || value == NULL)
274 | {
275 | return;
276 | }
277 | ++pConfig->tagCount;
278 | if (pConfig->tags == NULL || pConfig->tagCount > pConfig->tagAllocSize)
279 | {
280 | if(pConfig->tagAllocSize == 0)
281 | {
282 | pConfig->tagAllocSize = 4;
283 | }
284 | else
285 | {
286 | pConfig->tagAllocSize *= 2;
287 | }
288 | log_producer_config_tag * tagArray = (log_producer_config_tag *)malloc(sizeof(log_producer_config_tag) * pConfig->tagAllocSize);
289 | if (pConfig->tags != NULL)
290 | {
291 | memcpy(tagArray, pConfig->tags, sizeof(log_producer_config_tag) * (pConfig->tagCount - 1));
292 | free(pConfig->tags);
293 | }
294 | pConfig->tags = tagArray;
295 | }
296 | int32_t tagIndex = pConfig->tagCount - 1;
297 | pConfig->tags[tagIndex].key = sdsnew(key);
298 | pConfig->tags[tagIndex].value = sdsnew(value);
299 |
300 | }
301 |
302 |
303 | void log_producer_config_set_endpoint(log_producer_config * config, const char * endpoint)
304 | {
305 | if (strlen(endpoint) < 8) {
306 | return;
307 | }
308 | if (strncmp(endpoint, "http://", 7) == 0)
309 | {
310 | endpoint += 7;
311 | }
312 | else if (strncmp(endpoint, "https://", 8) == 0)
313 | {
314 | config->using_https = 1;
315 | endpoint += 8;
316 | }
317 | _copy_config_string(endpoint, &config->endpoint);
318 | }
319 |
320 | void log_producer_config_set_project(log_producer_config * config, const char * project)
321 | {
322 | _copy_config_string(project, &config->project);
323 | }
324 | void log_producer_config_set_logstore(log_producer_config * config, const char * logstore)
325 | {
326 | _copy_config_string(logstore, &config->logstore);
327 | }
328 |
329 | void log_producer_config_set_access_id(log_producer_config * config, const char * access_id)
330 | {
331 | _copy_config_string(access_id, &config->accessKeyId);
332 | }
333 |
334 | void log_producer_config_set_access_key(log_producer_config * config, const char * access_key)
335 | {
336 | _copy_config_string(access_key, &config->accessKey);
337 | }
338 |
339 |
340 | void log_producer_config_reset_security_token(log_producer_config * config, const char * access_id, const char * access_secret, const char * security_token)
341 | {
342 | if (config->securityTokenLock == NULL)
343 | {
344 | config->securityTokenLock = CreateCriticalSection();
345 | }
346 | CS_ENTER(config->securityTokenLock);
347 | _copy_config_string(access_id, &config->accessKeyId);
348 | _copy_config_string(access_secret, &config->accessKey);
349 | _copy_config_string(security_token, &config->securityToken);
350 | CS_LEAVE(config->securityTokenLock);
351 | }
352 |
353 | void log_producer_config_set_auth_version(log_producer_config * config, auth_version auth_version)
354 | {
355 | config->authVersion = auth_version;
356 | }
357 |
358 | void log_producer_config_set_region(log_producer_config * config, const char * region)
359 | {
360 | _copy_config_string(region, &config->region);
361 | }
362 |
363 | void log_producer_config_get_security(log_producer_config * config, char ** access_id, char ** access_secret, char ** security_token)
364 | {
365 | if (config->securityTokenLock == NULL)
366 | {
367 | _copy_config_string(config->accessKeyId, access_id);
368 | _copy_config_string(config->accessKey, access_secret);
369 | }
370 | else
371 | {
372 | CS_ENTER(config->securityTokenLock);
373 | _copy_config_string(config->accessKeyId, access_id);
374 | _copy_config_string(config->accessKey, access_secret);
375 | _copy_config_string(config->securityToken, security_token);
376 | CS_LEAVE(config->securityTokenLock);
377 | }
378 | }
379 |
380 | void log_producer_config_set_topic(log_producer_config * config, const char * topic)
381 | {
382 | _copy_config_string(topic, &config->topic);
383 | }
384 |
385 | void log_producer_config_set_source(log_producer_config * config, const char * source)
386 | {
387 | _copy_config_string(source, &config->source);
388 | }
389 |
390 | int log_producer_config_is_valid(log_producer_config * config)
391 | {
392 | if (config == NULL)
393 | {
394 | aos_error_log("invalid producer config");
395 | return 0;
396 | }
397 | if (config->endpoint == NULL || config->project == NULL || config->logstore == NULL)
398 | {
399 | aos_error_log("invalid producer config destination params");
400 | return 0;
401 | }
402 | if (config->accessKey == NULL || config->accessKeyId == NULL)
403 | {
404 | aos_error_log("invalid producer config authority params");
405 | return 0;
406 | }
407 | if (config->packageTimeoutInMS < 0 || config->maxBufferBytes < 0 || config->logCountPerPackage < 0 || config->logBytesPerPackage < 0)
408 | {
409 | aos_error_log("invalid producer config log merge and buffer params");
410 | return 0;
411 | }
412 | return 1;
413 | }
414 |
--------------------------------------------------------------------------------
/src/log_producer_config.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by ZhangCheng on 20/11/2017.
3 | //
4 |
5 | #ifndef LOG_C_SDK_LOG_PRODUCER_CONFIG_H
6 | #define LOG_C_SDK_LOG_PRODUCER_CONFIG_H
7 |
8 | #include "log_define.h"
9 | #include "log_producer_common.h"
10 | #include
11 | #include
12 | #include
13 | #include "log_multi_thread.h"
14 | LOG_CPP_START
15 |
16 |
17 | typedef struct _log_producer_config_tag
18 | {
19 | char * key;
20 | char * value;
21 | }log_producer_config_tag;
22 |
23 | typedef struct _log_producer_config
24 | {
25 | char * endpoint;
26 | char * project;
27 | char * logstore;
28 | char * accessKeyId;
29 | char * accessKey;
30 | char * securityToken;
31 | char * topic;
32 | char * source;
33 | auth_version authVersion;
34 | char * region;
35 | CRITICALSECTION securityTokenLock;
36 | log_producer_config_tag * tags;
37 | int32_t tagAllocSize;
38 | int32_t tagCount;
39 |
40 | int32_t sendThreadCount;
41 |
42 | int32_t packageTimeoutInMS;
43 | int32_t logCountPerPackage;
44 | int32_t logBytesPerPackage;
45 | int32_t maxBufferBytes;
46 | int32_t logQueueSize;
47 |
48 | char * netInterface;
49 | char * remote_address;
50 | int32_t connectTimeoutSec;
51 | int32_t sendTimeoutSec;
52 | int32_t destroyFlusherWaitTimeoutSec;
53 | int32_t destroySenderWaitTimeoutSec;
54 |
55 | log_compress_type compressType;
56 | int32_t using_https; // default http, 0 http, 1 https
57 |
58 | }log_producer_config;
59 |
60 |
61 | /**
62 | * create a empty producer config, should set config params manually
63 | * @return empty producer config
64 | */
65 | LOG_EXPORT log_producer_config * create_log_producer_config();
66 |
67 |
68 | /**
69 | * set producer config endpoint
70 | * @note if endpoint start with "https", then set using_https 1
71 | * @note strlen(endpoint) must >= 8
72 | * @param config
73 | * @param endpoint
74 | */
75 | LOG_EXPORT void log_producer_config_set_endpoint(log_producer_config * config, const char * endpoint);
76 |
77 | /**
78 | * set producer config project
79 | * @param config
80 | * @param project
81 | */
82 | LOG_EXPORT void log_producer_config_set_project(log_producer_config * config, const char * project);
83 |
84 | /**
85 | * set producer config logstore
86 | * @param config
87 | * @param logstore
88 | */
89 | LOG_EXPORT void log_producer_config_set_logstore(log_producer_config * config, const char * logstore);
90 |
91 | /**
92 | * set producer config access id
93 | * @param config
94 | * @param access_id
95 | */
96 | LOG_EXPORT void log_producer_config_set_access_id(log_producer_config * config, const char * access_id);
97 |
98 |
99 | /**
100 | * set producer config access key
101 | * @param config
102 | * @param access_id
103 | */
104 | LOG_EXPORT void log_producer_config_set_access_key(log_producer_config * config, const char * access_id);
105 |
106 | /**
107 | * set producer config auth_version
108 | * @param config
109 | * @param auth_version
110 | */
111 | LOG_EXPORT void log_producer_config_set_auth_version(log_producer_config * config, auth_version auth_version);
112 |
113 |
114 | /**
115 | * set producer config region
116 | * @param config
117 | * @param region
118 | */
119 | LOG_EXPORT void log_producer_config_set_region(log_producer_config * config, const char * region);
120 |
121 |
122 | /**
123 | * reset producer config security token (thread safe)
124 | * @note if you want to use security token to send logs, you must call this function when create config and reset token before expired.
125 | * if token has expired, producer will drop logs after 6 hours
126 | * @param config
127 | * @param access_id
128 | */
129 | LOG_EXPORT void log_producer_config_reset_security_token(log_producer_config * config, const char * access_id, const char * access_secret, const char * security_token);
130 |
131 |
132 | /**
133 | * inner api
134 | */
135 | LOG_EXPORT void log_producer_config_get_security(log_producer_config * config, char ** access_id, char ** access_secret, char ** security_token);
136 |
137 | /**
138 | * set producer config topic
139 | * @param config
140 | * @param topic
141 | */
142 | LOG_EXPORT void log_producer_config_set_topic(log_producer_config * config, const char * topic);
143 |
144 | /**
145 | * set producer source, this source will been set to every loggroup's "source" field
146 | * @param config
147 | * @param source
148 | */
149 | LOG_EXPORT void log_producer_config_set_source(log_producer_config * config, const char * source);
150 |
151 | /**
152 | * add tag, this tag will been set to every loggroup's "tag" field
153 | * @param config
154 | * @param key
155 | * @param value
156 | */
157 | LOG_EXPORT void log_producer_config_add_tag(log_producer_config * config, const char * key, const char * value);
158 |
159 | /**
160 | * set loggroup timeout, if delta time from first log's time >= time_out_ms, current loggroup will been flushed out
161 | * @param config
162 | * @param time_out_ms
163 | */
164 | LOG_EXPORT void log_producer_config_set_packet_timeout(log_producer_config * config, int32_t time_out_ms);
165 |
166 | /**
167 | * set loggroup max log count, if loggoup's logs count >= log_count, current loggroup will been flushed out
168 | * @param config
169 | * @param log_count
170 | */
171 | LOG_EXPORT void log_producer_config_set_packet_log_count(log_producer_config * config, int32_t log_count);
172 |
173 | /**
174 | * set loggroup max log bytes, if loggoup's log bytes >= log_bytes, current loggroup will been flushed out
175 | * @param config
176 | * @param log_bytes
177 | */
178 | LOG_EXPORT void log_producer_config_set_packet_log_bytes(log_producer_config * config, int32_t log_bytes);
179 |
180 | /**
181 | * set max buffer size, if total buffer size > max_buffer_bytes, all send will fail immediately
182 | * @param config
183 | * @param max_buffer_bytes
184 | */
185 | LOG_EXPORT void log_producer_config_set_max_buffer_limit(log_producer_config * config, int64_t max_buffer_bytes);
186 |
187 | /**
188 | * set send thread count, default is 0.
189 | * @note if thread count is 0, flusher thread is in the charge of send logs.
190 | * @note if thread count > 1, then producer will create $(thread_count) threads to send logs.
191 | * @param config
192 | * @param thread_count
193 | */
194 | LOG_EXPORT void log_producer_config_set_send_thread_count(log_producer_config * config, int32_t thread_count);
195 |
196 | /**
197 | * set interface to send log out
198 | * @param config
199 | * @param net_interface
200 | */
201 | LOG_EXPORT void log_producer_config_set_net_interface(log_producer_config * config, const char * net_interface);
202 |
203 | /**
204 | * set remote_address to send log out
205 | * @param config
206 | * @param remote_address
207 | */
208 | LOG_EXPORT void log_producer_config_set_remote_address(log_producer_config * config, const char * remote_address);
209 |
210 | /**
211 | * set connect timeout seconds
212 | * @param config
213 | * @param connect_timeout_sec
214 | */
215 | LOG_EXPORT void log_producer_config_set_connect_timeout_sec(log_producer_config * config, int32_t connect_timeout_sec);
216 |
217 | /**
218 | * set send timeout seconds
219 | * @param config
220 | * @param send_timeout_sec
221 | */
222 | LOG_EXPORT void log_producer_config_set_send_timeout_sec(log_producer_config * config, int32_t send_timeout_sec);
223 |
224 | /**
225 | * set wait seconds when destroy flusher
226 | * @param config
227 | * @param destroy_flusher_wait_sec
228 | */
229 | LOG_EXPORT void log_producer_config_set_destroy_flusher_wait_sec(log_producer_config * config, int32_t destroy_flusher_wait_sec);
230 |
231 | /**
232 | * set wait seconds when destroy sender
233 | * @param config
234 | * @param destroy_sender_wait_sec
235 | */
236 | LOG_EXPORT void log_producer_config_set_destroy_sender_wait_sec(log_producer_config * config, int32_t destroy_sender_wait_sec);
237 |
238 | /**
239 | * set compress type, default 1 (lz4)
240 | * @param config
241 | * @param compress_type only support 1 or 0. 1 -> lz4, 0 -> no compress
242 | */
243 | LOG_EXPORT void log_producer_config_set_compress_type(log_producer_config * config, int32_t compress_type);
244 |
245 | /**
246 | * default http, 0 http, 1 https
247 | * @param config
248 | * @param using_https
249 | */
250 | LOG_EXPORT void log_producer_config_set_using_http(log_producer_config * config, int32_t using_https);
251 |
252 |
253 | /**
254 | * default http, 0 http, 1 https
255 | * @param config
256 | * @param log_queue_size
257 | */
258 | LOG_EXPORT void log_producer_config_set_log_queue_size(log_producer_config * config, int32_t log_queue_size);
259 |
260 |
261 |
262 | /**
263 | * destroy config, this will free all memory allocated by this config
264 | * @param config
265 | */
266 | LOG_EXPORT void destroy_log_producer_config(log_producer_config * config);
267 |
268 | #ifdef LOG_PRODUCER_DEBUG
269 | /**
270 | * print this config
271 | * @param config
272 | */
273 | void log_producer_config_print(log_producer_config * config, FILE * pFile);
274 |
275 | #endif
276 |
277 | /**
278 | * check if given config is valid
279 | * @param config
280 | * @return 1 valid, 0 invalid
281 | */
282 | LOG_EXPORT int log_producer_config_is_valid(log_producer_config * config);
283 |
284 |
285 |
286 | LOG_CPP_END
287 |
288 | #endif //LOG_C_SDK_LOG_PRODUCER_CONFIG_H
289 |
--------------------------------------------------------------------------------
/src/log_producer_manager.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by ZhangCheng on 20/11/2017.
3 | //
4 |
5 | #ifndef LOG_C_SDK_LOG_PRODUCER_MANAGER_H
6 | #define LOG_C_SDK_LOG_PRODUCER_MANAGER_H
7 |
8 | #include "log_define.h"
9 | LOG_CPP_START
10 |
11 | #include "log_producer_config.h"
12 | #include "log_producer_sender.h"
13 | #include "log_builder.h"
14 | #include "log_queue.h"
15 | #include "log_multi_thread.h"
16 |
17 | typedef struct _log_producer_manager
18 | {
19 | log_producer_config * producer_config;
20 | volatile uint32_t shutdown;
21 | volatile uint32_t networkRecover;
22 | volatile uint32_t totalBufferSize;
23 | log_queue * loggroup_queue;
24 | log_queue * sender_data_queue;
25 | THREAD * send_threads;
26 | THREAD flush_thread;
27 | CRITICALSECTION lock;
28 | COND triger_cond;
29 | log_group_builder * builder;
30 | int32_t firstLogTime;
31 | char * source;
32 | char * pack_prefix;
33 | volatile uint32_t pack_index;
34 | on_log_producer_send_done_function send_done_function;
35 | log_producer_send_param ** send_param_queue;
36 | uint64_t send_param_queue_size;
37 | volatile uint64_t send_param_queue_read;
38 | volatile uint64_t send_param_queue_write;
39 | ATOMICINT ref_count; // only used when global send thread works
40 | }log_producer_manager;
41 |
42 | extern log_producer_manager * create_log_producer_manager(log_producer_config * producer_config);
43 | extern void destroy_log_producer_manager(log_producer_manager * manager);
44 |
45 | extern log_producer_result log_producer_manager_add_log(log_producer_manager * producer_manager, uint32_t log_time, int32_t pair_count, char ** keys, size_t * key_lens, char ** values, size_t * val_lens);
46 |
47 | extern log_producer_result log_producer_manager_send_raw_buffer(log_producer_manager * producer_manager, size_t log_bytes, size_t compressed_bytes, const unsigned char * raw_buffer);
48 |
49 | LOG_CPP_END
50 |
51 | #endif //LOG_C_SDK_LOG_PRODUCER_MANAGER_H
52 |
--------------------------------------------------------------------------------
/src/log_producer_sender.c:
--------------------------------------------------------------------------------
1 | //
2 | // Created by ZhangCheng on 20/11/2017.
3 | //
4 |
5 | #include "log_producer_sender.h"
6 | #include "log_api.h"
7 | #include "log_producer_manager.h"
8 | #include "inner_log.h"
9 | #include "lz4.h"
10 | #include "sds.h"
11 | #include
12 | #include
13 | #include
14 |
15 | const char* LOGE_SERVER_BUSY = "ServerBusy";
16 | const char* LOGE_INTERNAL_SERVER_ERROR = "InternalServerError";
17 | const char* LOGE_UNAUTHORIZED = "Unauthorized";
18 | const char* LOGE_WRITE_QUOTA_EXCEED = "WriteQuotaExceed";
19 | const char* LOGE_SHARD_WRITE_QUOTA_EXCEED = "ShardWriteQuotaExceed";
20 | const char* LOGE_TIME_EXPIRED = "RequestTimeExpired";
21 |
22 | #define SEND_SLEEP_INTERVAL_MS 100
23 | #define MAX_NETWORK_ERROR_SLEEP_MS 3600000
24 | #define BASE_NETWORK_ERROR_SLEEP_MS 1000
25 | #define MAX_QUOTA_ERROR_SLEEP_MS 60000
26 | #define BASE_QUOTA_ERROR_SLEEP_MS 3000
27 | #define INVALID_TIME_TRY_INTERVAL 3000
28 |
29 | #define DROP_FAIL_DATA_TIME_SECOND (3600 * 6)
30 |
31 | #define SEND_TIME_INVALID_FIX
32 |
33 | extern volatile uint8_t g_send_thread_destroy;
34 |
35 | extern void destroy_log_producer_manager_tail(log_producer_manager * manager);
36 |
37 | typedef struct _send_error_info
38 | {
39 | log_producer_send_result last_send_error;
40 | int32_t last_sleep_ms;
41 | int32_t first_error_time;
42 | }send_error_info;
43 |
44 | int32_t log_producer_on_send_done(log_producer_send_param * send_param, post_log_result * result, send_error_info * error_info);
45 |
46 | #ifdef SEND_TIME_INVALID_FIX
47 |
48 | void _rebuild_time(lz4_log_buf * lz4_buf, lz4_log_buf ** new_lz4_buf)
49 | {
50 | aos_debug_log("rebuild log.");
51 | char * buf = (char *)malloc(lz4_buf->raw_length);
52 | if (LZ4_decompress_safe((const char* )lz4_buf->data, buf, lz4_buf->length, lz4_buf->raw_length) <= 0)
53 | {
54 | free(buf);
55 | aos_fatal_log("LZ4_decompress_safe error");
56 | return;
57 | }
58 | uint32_t nowTime = time(NULL);
59 | fix_log_group_time(buf, lz4_buf->raw_length, nowTime);
60 |
61 | int compress_bound = LZ4_compressBound(lz4_buf->raw_length);
62 | char *compress_data = (char *)malloc(compress_bound);
63 | int compressed_size = LZ4_compress_default((char *)buf, compress_data, lz4_buf->raw_length, compress_bound);
64 | if(compressed_size <= 0)
65 | {
66 | aos_fatal_log("LZ4_compress_default error");
67 | free(buf);
68 | free(compress_data);
69 | return;
70 | }
71 | *new_lz4_buf = (lz4_log_buf*)malloc(sizeof(lz4_log_buf) + compressed_size);
72 | (*new_lz4_buf)->length = compressed_size;
73 | (*new_lz4_buf)->raw_length = lz4_buf->raw_length;
74 | memcpy((*new_lz4_buf)->data, compress_data, compressed_size);
75 | free(buf);
76 | free(compress_data);
77 | return;
78 | }
79 |
80 | #endif
81 |
82 | void * log_producer_send_thread(void * param)
83 | {
84 | log_producer_manager * producer_manager = (log_producer_manager *)param;
85 |
86 | if (producer_manager->sender_data_queue == NULL)
87 | {
88 | return NULL;
89 | }
90 |
91 | while (!producer_manager->shutdown)
92 | {
93 | void * send_param = log_queue_pop(producer_manager->sender_data_queue, 30);
94 | if (send_param != NULL)
95 | {
96 | log_producer_send_fun(send_param);
97 | }
98 | }
99 |
100 | return NULL;
101 | }
102 |
103 | void log_producer_send_thread_global_inner(log_producer_send_param * send_param)
104 | {
105 | if (send_param != NULL)
106 | {
107 | log_producer_manager * producer_manager = (log_producer_manager *)send_param->producer_manager;
108 | log_producer_send_fun(send_param);
109 | // @note after log_producer_send_fun, send_param has been destroyed
110 | if (ATOMICINT_DEC(&producer_manager->ref_count) == 0)
111 | {
112 | aos_info_log("producer's ref count is 0, destroy this producer, project : %s, logstore : %s",
113 | producer_manager->producer_config->project, producer_manager->producer_config->logstore);
114 | destroy_log_producer_manager_tail(producer_manager);
115 | }
116 | }
117 | }
118 |
119 | void * log_producer_send_thread_global(void * param)
120 | {
121 | log_queue * send_log_queue = (log_queue * )param;
122 |
123 | while (!g_send_thread_destroy)
124 | {
125 | log_producer_send_param * send_param = (log_producer_send_param *)log_queue_pop(send_log_queue, 300);
126 | log_producer_send_thread_global_inner(send_param);
127 | }
128 |
129 | return NULL;
130 | }
131 |
132 | void * log_producer_send_fun(void * param)
133 | {
134 | log_producer_send_param * send_param = (log_producer_send_param *)param;
135 | if (send_param->magic_num != LOG_PRODUCER_SEND_MAGIC_NUM)
136 | {
137 | aos_fatal_log("invalid send param, magic num not found, num 0x%x", send_param->magic_num);
138 | return NULL;
139 | }
140 |
141 | if (send_param->log_buf == NULL)
142 | {
143 | aos_info_log("receive producer destroy event, project : %s, logstore : %s", send_param->producer_config->project, send_param->producer_config->logstore);
144 | free(send_param);
145 | return NULL;
146 | }
147 |
148 | log_producer_config * config = send_param->producer_config;
149 |
150 | send_error_info error_info;
151 | memset(&error_info, 0, sizeof(error_info));
152 |
153 | log_producer_manager * producer_manager = (log_producer_manager *)send_param->producer_manager;
154 |
155 | do
156 | {
157 | if (producer_manager->shutdown)
158 | {
159 | aos_info_log("send fail but shutdown signal received, force exit");
160 | if (producer_manager->send_done_function != NULL)
161 | {
162 | producer_manager->send_done_function(producer_manager->producer_config->logstore, LOG_PRODUCER_SEND_EXIT_BUFFERED, send_param->log_buf->raw_length, send_param->log_buf->length,
163 | NULL, "producer is being destroyed, producer has no time to send this buffer out", send_param->log_buf->data);
164 | }
165 | break;
166 | }
167 | lz4_log_buf * send_buf = send_param->log_buf;
168 | #ifdef SEND_TIME_INVALID_FIX
169 | uint32_t nowTime = time(NULL);
170 | if (nowTime - send_param->builder_time > 600 || send_param->builder_time > nowTime || error_info.last_send_error == LOG_SEND_TIME_ERROR)
171 | {
172 | _rebuild_time(send_param->log_buf, &send_buf);
173 | send_param->builder_time = nowTime;
174 | }
175 | #endif
176 | log_post_option option;
177 | memset(&option, 0, sizeof(log_post_option));
178 | option.connect_timeout = config->connectTimeoutSec;
179 | option.operation_timeout = config->sendTimeoutSec;
180 | option.interface = config->netInterface;
181 | option.compress_type = config->compressType;
182 | option.remote_address = config->remote_address;
183 | option.using_https = config->using_https;
184 |
185 | sds accessKeyId = NULL;
186 | sds accessKey = NULL;
187 | sds stsToken = NULL;
188 | log_producer_config_get_security(config, &accessKeyId, &accessKey, &stsToken);
189 |
190 | post_log_result * rst = post_logs_from_lz4buf(config->endpoint, accessKeyId,
191 | accessKey, stsToken,
192 | config->project, config->logstore,
193 | send_buf, &option,
194 | config->authVersion, config->region);
195 | sdsfree(accessKeyId);
196 | sdsfree(accessKey);
197 | sdsfree(stsToken);
198 |
199 | int32_t sleepMs = log_producer_on_send_done(send_param, rst, &error_info);
200 |
201 | post_log_result_destroy(rst);
202 |
203 | // tmp buffer, free
204 | if (send_buf != send_param->log_buf)
205 | {
206 | free(send_buf);
207 | }
208 |
209 | if (sleepMs <= 0)
210 | {
211 | break;
212 | }
213 | int i =0;
214 | for (i = 0; i < sleepMs; i += SEND_SLEEP_INTERVAL_MS)
215 | {
216 | usleep(SEND_SLEEP_INTERVAL_MS * 1000);
217 | if (producer_manager->shutdown || producer_manager->networkRecover)
218 | {
219 | break;
220 | }
221 | }
222 |
223 | if (producer_manager->networkRecover)
224 | {
225 | producer_manager->networkRecover = 0;
226 | }
227 |
228 | }while(1);
229 |
230 | // at last, free all buffer
231 | free_lz4_log_buf(send_param->log_buf);
232 | free(send_param);
233 |
234 | return NULL;
235 |
236 | }
237 |
238 | int32_t log_producer_on_send_done(log_producer_send_param * send_param, post_log_result * result, send_error_info * error_info)
239 | {
240 | log_producer_send_result send_result = AosStatusToResult(result);
241 | log_producer_manager * producer_manager = (log_producer_manager *)send_param->producer_manager;
242 | if (producer_manager->send_done_function != NULL)
243 | {
244 | log_producer_result callback_result = send_result == LOG_SEND_OK ?
245 | LOG_PRODUCER_OK :
246 | (LOG_PRODUCER_SEND_NETWORK_ERROR + send_result - LOG_SEND_NETWORK_ERROR);
247 | producer_manager->send_done_function(producer_manager->producer_config->logstore,
248 | callback_result,
249 | send_param->log_buf->raw_length,
250 | send_param->log_buf->length,
251 | result->requestID,
252 | result->errorMessage,
253 | send_param->log_buf->data);
254 | }
255 | switch (send_result)
256 | {
257 | case LOG_SEND_OK:
258 | break;
259 | case LOG_SEND_TIME_ERROR:
260 | // if no this marco, drop data
261 | #ifdef SEND_TIME_INVALID_FIX
262 | error_info->last_send_error = LOG_SEND_TIME_ERROR;
263 | error_info->last_sleep_ms = INVALID_TIME_TRY_INTERVAL;
264 | return error_info->last_sleep_ms;
265 | #else
266 | break;
267 | #endif
268 | case LOG_SEND_QUOTA_EXCEED:
269 | if (error_info->last_send_error != LOG_SEND_QUOTA_EXCEED)
270 | {
271 | error_info->last_send_error = LOG_SEND_QUOTA_EXCEED;
272 | error_info->last_sleep_ms = BASE_QUOTA_ERROR_SLEEP_MS;
273 | error_info->first_error_time = time(NULL);
274 | }
275 | else
276 | {
277 | if (error_info->last_sleep_ms < MAX_QUOTA_ERROR_SLEEP_MS)
278 | {
279 | error_info->last_sleep_ms *= 2;
280 | }
281 |
282 | #ifndef SEND_TIME_INVALID_FIX
283 | // only drop data when SEND_TIME_INVALID_FIX not defined
284 | if (time(NULL) - error_info->first_error_time > DROP_FAIL_DATA_TIME_SECOND)
285 | {
286 | break;
287 | }
288 | #endif
289 | }
290 | aos_warn_log("send quota error, project : %s, logstore : %s, buffer len : %d, raw len : %d, code : %d, error msg : %s",
291 | send_param->producer_config->project,
292 | send_param->producer_config->logstore,
293 | (int)send_param->log_buf->length,
294 | (int)send_param->log_buf->raw_length,
295 | result->statusCode,
296 | result->errorMessage);
297 | return error_info->last_sleep_ms;
298 | case LOG_SEND_SERVER_ERROR :
299 | case LOG_SEND_NETWORK_ERROR:
300 | if (error_info->last_send_error != LOG_SEND_NETWORK_ERROR)
301 | {
302 | error_info->last_send_error = LOG_SEND_NETWORK_ERROR;
303 | error_info->last_sleep_ms = BASE_NETWORK_ERROR_SLEEP_MS;
304 | error_info->first_error_time = time(NULL);
305 | }
306 | else
307 | {
308 | if (error_info->last_sleep_ms < MAX_NETWORK_ERROR_SLEEP_MS)
309 | {
310 | error_info->last_sleep_ms *= 2;
311 | }
312 | #ifndef SEND_TIME_INVALID_FIX
313 | // only drop data when SEND_TIME_INVALID_FIX not defined
314 | if (time(NULL) - error_info->first_error_time > DROP_FAIL_DATA_TIME_SECOND)
315 | {
316 | break;
317 | }
318 | #endif
319 | }
320 | aos_warn_log("send network error, project : %s, logstore : %s, buffer len : %d, raw len : %d, code : %d, error msg : %s",
321 | send_param->producer_config->project,
322 | send_param->producer_config->logstore,
323 | (int)send_param->log_buf->length,
324 | (int)send_param->log_buf->raw_length,
325 | result->statusCode,
326 | result->errorMessage == NULL ? "" : result->errorMessage);
327 | return error_info->last_sleep_ms;
328 | default:
329 | // discard data
330 | break;
331 |
332 | }
333 |
334 | CS_ENTER(producer_manager->lock);
335 | producer_manager->totalBufferSize -= send_param->log_buf->length;
336 | CS_LEAVE(producer_manager->lock);
337 | if (send_result == LOG_SEND_OK)
338 | {
339 | aos_debug_log("send success, project : %s, logstore : %s, buffer len : %d, raw len : %d, total buffer : %d, code : %d, error msg : %s",
340 | send_param->producer_config->project,
341 | send_param->producer_config->logstore,
342 | (int)send_param->log_buf->length,
343 | (int)send_param->log_buf->raw_length,
344 | (int)producer_manager->totalBufferSize,
345 | result->statusCode,
346 | result->errorMessage);
347 | }
348 | else
349 | {
350 | aos_warn_log("send fail, discard data, project : %s, logstore : %s, buffer len : %d, raw len : %d, total buffer : %d, code : %d, error msg : %s",
351 | send_param->producer_config->project,
352 | send_param->producer_config->logstore,
353 | (int)send_param->log_buf->length,
354 | (int)send_param->log_buf->raw_length,
355 | (int)producer_manager->totalBufferSize,
356 | result->statusCode,
357 | result->errorMessage);
358 | }
359 |
360 | return 0;
361 | }
362 |
363 | log_producer_result log_producer_send_data(log_producer_send_param * send_param)
364 | {
365 | log_producer_send_fun(send_param);
366 | return LOG_PRODUCER_OK;
367 | }
368 |
369 | log_producer_send_result AosStatusToResult(post_log_result * result)
370 | {
371 | if (result->statusCode / 100 == 2)
372 | {
373 | return LOG_SEND_OK;
374 | }
375 | if (result->statusCode <= 0)
376 | {
377 | return LOG_SEND_NETWORK_ERROR;
378 | }
379 | if (result->statusCode >= 500 || result->requestID == NULL)
380 | {
381 | return LOG_SEND_SERVER_ERROR;
382 | }
383 | if (result->statusCode == 403)
384 | {
385 | return LOG_SEND_QUOTA_EXCEED;
386 | }
387 | if (result->statusCode == 401 || result->statusCode == 404)
388 | {
389 | return LOG_SEND_UNAUTHORIZED;
390 | }
391 | if (result->errorMessage != NULL && strstr(result->errorMessage, LOGE_TIME_EXPIRED) != NULL)
392 | {
393 | return LOG_SEND_TIME_ERROR;
394 | }
395 | return LOG_SEND_DISCARD_ERROR;
396 |
397 | }
398 |
399 | log_producer_send_param * create_log_producer_send_param(log_producer_config * producer_config,
400 | void * producer_manager,
401 | lz4_log_buf * log_buf,
402 | uint32_t builder_time)
403 | {
404 | log_producer_send_param * param = (log_producer_send_param *)malloc(sizeof(log_producer_send_param));
405 | param->producer_config = producer_config;
406 | param->producer_manager = producer_manager;
407 | param->log_buf = log_buf;
408 | param->magic_num = LOG_PRODUCER_SEND_MAGIC_NUM;
409 | param->builder_time = builder_time;
410 | return param;
411 | }
412 |
413 | log_producer_send_param * create_log_producer_destroy_param(log_producer_config * producer_config, void *producer_manager)
414 | {
415 | log_producer_send_param * param = (log_producer_send_param *)malloc(sizeof(log_producer_send_param));
416 | param->producer_config = producer_config;
417 | param->producer_manager = producer_manager;
418 | param->log_buf = NULL;
419 | param->magic_num = LOG_PRODUCER_SEND_MAGIC_NUM;
420 | param->builder_time = 0;
421 | return param;
422 | }
423 |
424 |
425 |
--------------------------------------------------------------------------------
/src/log_producer_sender.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by ZhangCheng on 20/11/2017.
3 | //
4 |
5 | #ifndef LOG_C_SDK_LOG_PRODUCER_SENDER_H
6 | #define LOG_C_SDK_LOG_PRODUCER_SENDER_H
7 |
8 |
9 | #include "log_define.h"
10 | #include "log_producer_config.h"
11 | #include "log_builder.h"
12 | LOG_CPP_START
13 |
14 | #define LOG_PRODUCER_SEND_MAGIC_NUM 0x1B35487A
15 |
16 | typedef int32_t log_producer_send_result;
17 |
18 | #define LOG_SEND_OK 0
19 | #define LOG_SEND_NETWORK_ERROR 1
20 | #define LOG_SEND_QUOTA_EXCEED 2
21 | #define LOG_SEND_UNAUTHORIZED 3
22 | #define LOG_SEND_SERVER_ERROR 4
23 | #define LOG_SEND_DISCARD_ERROR 5
24 | #define LOG_SEND_TIME_ERROR 6
25 |
26 | extern const char* LOGE_SERVER_BUSY;//= "ServerBusy";
27 | extern const char* LOGE_INTERNAL_SERVER_ERROR;//= "InternalServerError";
28 | extern const char* LOGE_UNAUTHORIZED;//= "Unauthorized";
29 | extern const char* LOGE_WRITE_QUOTA_EXCEED;//="WriteQuotaExceed";
30 | extern const char* LOGE_SHARD_WRITE_QUOTA_EXCEED;//= "ShardWriteQuotaExceed";
31 | extern const char* LOGE_TIME_EXPIRED;//= "RequestTimeExpired";
32 |
33 |
34 | typedef struct _log_producer_send_param
35 | {
36 | log_producer_config * producer_config;
37 | void * producer_manager;
38 | lz4_log_buf * log_buf;
39 | uint32_t magic_num;
40 | uint32_t builder_time;
41 | }log_producer_send_param;
42 |
43 | extern void * log_producer_send_fun(void * send_param);
44 |
45 | extern log_producer_result log_producer_send_data(log_producer_send_param * send_param);
46 |
47 | extern log_producer_send_result AosStatusToResult(post_log_result * result);
48 |
49 | extern log_producer_send_param * create_log_producer_send_param(log_producer_config * producer_config,
50 | void * producer_manager,
51 | lz4_log_buf * log_buf,
52 | uint32_t builder_time);
53 |
54 | extern log_producer_send_param * create_log_producer_destroy_param(log_producer_config * producer_config, void * producer_manager);
55 |
56 | LOG_CPP_END
57 |
58 | #endif //LOG_C_SDK_LOG_PRODUCER_SENDER_H
59 |
--------------------------------------------------------------------------------
/src/log_queue.c:
--------------------------------------------------------------------------------
1 | //
2 | // Created by ZhangCheng on 29/12/2017.
3 | //
4 | #include "log_queue.h"
5 | #include "log_multi_thread.h"
6 |
7 |
8 | struct _log_queue{
9 | void ** data;
10 | int64_t head;
11 | int64_t tail;
12 | int32_t size;
13 | CRITICALSECTION mutex;
14 | COND notempty;
15 | };
16 |
17 | log_queue * log_queue_create(int32_t size)
18 | {
19 | void * buffer = malloc(sizeof(void *) * size + sizeof(log_queue));
20 | memset(buffer, 0, sizeof(void *) * size + sizeof(log_queue));
21 | log_queue * queue = (log_queue *)buffer;
22 | queue->data = (void **)(buffer + sizeof(log_queue));
23 | queue->size = size;
24 | queue->mutex = CreateCriticalSection();
25 | queue->notempty = CreateCond();
26 | return queue;
27 | }
28 |
29 | void log_queue_destroy(log_queue * queue)
30 | {
31 | DeleteCriticalSection(queue->mutex);
32 | DeleteCond(queue->notempty);
33 | free(queue);
34 | }
35 |
36 | int32_t log_queue_size(log_queue * queue)
37 | {
38 | CS_ENTER(queue->mutex);
39 | int32_t len = queue->tail - queue->head;
40 | CS_LEAVE(queue->mutex);
41 | return len;
42 | }
43 |
44 | int32_t log_queue_isfull(log_queue * queue)
45 | {
46 | CS_ENTER(queue->mutex);
47 | int32_t rst = (int32_t)((queue->tail - queue->head) == queue->size);
48 | CS_LEAVE(queue->mutex);
49 | return rst;
50 | }
51 |
52 | int32_t log_queue_push(log_queue * queue, void * data)
53 | {
54 | CS_ENTER(queue->mutex);
55 | if (queue->tail - queue->head == queue->size)
56 | {
57 | CS_LEAVE(queue->mutex);
58 | return -1;
59 | }
60 | queue->data[queue->tail++ % queue->size] = data;
61 | CS_LEAVE(queue->mutex);
62 | COND_SIGNAL(queue->notempty);
63 | return 0;
64 | }
65 |
66 | void * log_queue_pop(log_queue * queue, int32_t waitMs) {
67 | CS_ENTER(queue->mutex);
68 | if (queue->tail == queue->head) {
69 | COND_WAIT_TIME(queue->notempty, queue->mutex, waitMs);
70 | }
71 | void * result = NULL;
72 | if (queue->tail > queue->head)
73 | {
74 | result = queue->data[queue->head++ % queue->size];
75 | }
76 | CS_LEAVE(queue->mutex);
77 | return result;
78 | }
79 |
80 | void * log_queue_trypop(log_queue * queue)
81 | {
82 | CS_ENTER(queue->mutex);
83 | void * result = NULL;
84 | if (queue->tail > queue->head)
85 | {
86 | result = queue->data[queue->head++ % queue->size];
87 | }
88 | CS_LEAVE(queue->mutex);
89 | return result;
90 | }
91 |
92 |
--------------------------------------------------------------------------------
/src/log_queue.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by ZhangCheng on 29/12/2017.
3 | //
4 |
5 | #ifndef LOG_C_SDK_LOG_QUEUE_H
6 | #define LOG_C_SDK_LOG_QUEUE_H
7 |
8 | #include
9 |
10 | typedef struct _log_queue log_queue;
11 |
12 | log_queue * log_queue_create(int32_t max_size);
13 |
14 | void log_queue_destroy(log_queue * queue);
15 |
16 | int32_t log_queue_size(log_queue * queue);
17 |
18 | int32_t log_queue_isfull(log_queue * queue);
19 |
20 |
21 | int32_t log_queue_push(log_queue * queue, void * data);
22 |
23 | void * log_queue_pop(log_queue * queue, int32_t waitMs);
24 |
25 | void * log_queue_trypop(log_queue * queue);
26 |
27 | #endif //LOG_C_SDK_LOG_QUEUE_H
28 |
--------------------------------------------------------------------------------
/src/log_util.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "log_util.h"
4 | #include "md5.h"
5 | #include "hmac-sha.h"
6 | #include
7 |
8 | static const char *g_hex_hash = "0123456789ABCDEF";
9 |
10 | void md5_to_string(const char * buffer, int bufLen, char * md5)
11 | {
12 | unsigned char md5Buf[16];
13 | mbedtls_md5((const unsigned char *)buffer, bufLen, md5Buf);
14 | int i = 0;
15 | for(; i < 32; i+=2)
16 | {
17 | md5[i] = g_hex_hash[md5Buf[i >> 1] >> 4];
18 | md5[i+1] = g_hex_hash[md5Buf[i >> 1] & 0xF];
19 | }
20 | }
21 |
22 | int aos_base64_encode(const unsigned char *in, int inLen, char *out)
23 | {
24 | static const char *ENC =
25 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
26 |
27 | char *original_out = out;
28 |
29 | while (inLen) {
30 | // first 6 bits of char 1
31 | *out++ = ENC[*in >> 2];
32 | if (!--inLen) {
33 | // last 2 bits of char 1, 4 bits of 0
34 | *out++ = ENC[(*in & 0x3) << 4];
35 | *out++ = '=';
36 | *out++ = '=';
37 | break;
38 | }
39 | // last 2 bits of char 1, first 4 bits of char 2
40 | *out++ = ENC[((*in & 0x3) << 4) | (*(in + 1) >> 4)];
41 | in++;
42 | if (!--inLen) {
43 | // last 4 bits of char 2, 2 bits of 0
44 | *out++ = ENC[(*in & 0xF) << 2];
45 | *out++ = '=';
46 | break;
47 | }
48 | // last 4 bits of char 2, first 2 bits of char 3
49 | *out++ = ENC[((*in & 0xF) << 2) | (*(in + 1) >> 6)];
50 | in++;
51 | // last 6 bits of char 3
52 | *out++ = ENC[*in & 0x3F];
53 | in++, inLen--;
54 | }
55 |
56 | return (int)(out - original_out);
57 | }
58 |
59 | int signature_to_base64(const char * sig, int sigLen, const char * key, int keyLen, char * base64)
60 | {
61 | unsigned char sha1Buf[20];
62 | hmac_sha1(sha1Buf, key, keyLen << 3, sig, sigLen << 3);
63 | return aos_base64_encode((const unsigned char *)sha1Buf, 20, base64);
64 | }
65 |
66 | void sha256_to_hex_string(uint8_t hash[32], char hex_str[65]) {
67 | const char hex_digits[] = "0123456789abcdef";
68 | int i;
69 | for (i = 0; i < 32; ++i) {
70 | hex_str[i * 2] = hex_digits[(hash[i] >> 4) & 0x0F];
71 | hex_str[i * 2 + 1] = hex_digits[hash[i] & 0x0F];
72 | }
73 | hex_str[64] = '\0'; // Null-terminate the string
74 | }
75 |
76 | char *sha256_hash_to_hex(const char *input, uint32 length) {
77 | if (!input) {
78 | return NULL;
79 | }
80 |
81 | sha256_context ctx;
82 | uint8_t hash[32];
83 | char *output = (char*)malloc(65); // 64 chars for hex + 1 for '\0'
84 | if (output == NULL) {
85 | return NULL; // Allocation failed
86 | }
87 |
88 | sha256_starts(&ctx);
89 | sha256_update(&ctx, (uint8_t *)input, length);
90 | sha256_finish(&ctx, hash);
91 |
92 | sha256_to_hex_string(hash, output);
93 |
94 | return output;
95 | }
--------------------------------------------------------------------------------
/src/log_util.h:
--------------------------------------------------------------------------------
1 | #ifndef LIBLOG_UTIL_H
2 | #define LIBLOG_UTIL_H
3 |
4 | #include "log_define.h"
5 | #include "sha256.h"
6 | #include
7 | LOG_CPP_START
8 |
9 | void md5_to_string(const char * buffer, int bufLen, char * md5);
10 |
11 | int signature_to_base64(const char * sig, int sigLen, const char * key, int keyLen, char * base64);
12 |
13 | void sha256_to_hex_string(uint8_t hash[32], char hex_str[65]);
14 | char *sha256_hash_to_hex(const char *input, uint32 length);
15 |
16 | LOG_CPP_END
17 | #endif
18 |
--------------------------------------------------------------------------------
/src/md5.c:
--------------------------------------------------------------------------------
1 | #include "md5.h"
2 | #include
3 |
4 | /*
5 | * 32-bit integer manipulation macros (little endian)
6 | */
7 | #ifndef GET_UINT32_LE
8 | #define GET_UINT32_LE(n,b,i) \
9 | { \
10 | (n) = ( (uint32_t) (b)[(i) ] ) \
11 | | ( (uint32_t) (b)[(i) + 1] << 8 ) \
12 | | ( (uint32_t) (b)[(i) + 2] << 16 ) \
13 | | ( (uint32_t) (b)[(i) + 3] << 24 ); \
14 | }
15 | #endif
16 |
17 | #ifndef PUT_UINT32_LE
18 | #define PUT_UINT32_LE(n,b,i) \
19 | { \
20 | (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \
21 | (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \
22 | (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \
23 | (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \
24 | }
25 | #endif
26 |
27 | void mbedtls_md5_init( mbedtls_md5_context *ctx )
28 | {
29 | memset( ctx, 0, sizeof( mbedtls_md5_context ) );
30 | }
31 |
32 | void mbedtls_md5_clone( mbedtls_md5_context *dst,
33 | const mbedtls_md5_context *src )
34 | {
35 | *dst = *src;
36 | }
37 |
38 | /*
39 | * MD5 context setup
40 | */
41 | void mbedtls_md5_starts( mbedtls_md5_context *ctx )
42 | {
43 | ctx->total[0] = 0;
44 | ctx->total[1] = 0;
45 |
46 | ctx->state[0] = 0x67452301;
47 | ctx->state[1] = 0xEFCDAB89;
48 | ctx->state[2] = 0x98BADCFE;
49 | ctx->state[3] = 0x10325476;
50 | }
51 |
52 | #if !defined(MBEDTLS_MD5_PROCESS_ALT)
53 | void mbedtls_md5_process( mbedtls_md5_context *ctx, const unsigned char data[64] )
54 | {
55 | uint32_t X[16], A, B, C, D;
56 |
57 | GET_UINT32_LE( X[ 0], data, 0 );
58 | GET_UINT32_LE( X[ 1], data, 4 );
59 | GET_UINT32_LE( X[ 2], data, 8 );
60 | GET_UINT32_LE( X[ 3], data, 12 );
61 | GET_UINT32_LE( X[ 4], data, 16 );
62 | GET_UINT32_LE( X[ 5], data, 20 );
63 | GET_UINT32_LE( X[ 6], data, 24 );
64 | GET_UINT32_LE( X[ 7], data, 28 );
65 | GET_UINT32_LE( X[ 8], data, 32 );
66 | GET_UINT32_LE( X[ 9], data, 36 );
67 | GET_UINT32_LE( X[10], data, 40 );
68 | GET_UINT32_LE( X[11], data, 44 );
69 | GET_UINT32_LE( X[12], data, 48 );
70 | GET_UINT32_LE( X[13], data, 52 );
71 | GET_UINT32_LE( X[14], data, 56 );
72 | GET_UINT32_LE( X[15], data, 60 );
73 |
74 | #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
75 |
76 | #define P(a,b,c,d,k,s,t) \
77 | { \
78 | a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
79 | }
80 |
81 | A = ctx->state[0];
82 | B = ctx->state[1];
83 | C = ctx->state[2];
84 | D = ctx->state[3];
85 |
86 | #define F(x,y,z) (z ^ (x & (y ^ z)))
87 |
88 | P( A, B, C, D, 0, 7, 0xD76AA478 );
89 | P( D, A, B, C, 1, 12, 0xE8C7B756 );
90 | P( C, D, A, B, 2, 17, 0x242070DB );
91 | P( B, C, D, A, 3, 22, 0xC1BDCEEE );
92 | P( A, B, C, D, 4, 7, 0xF57C0FAF );
93 | P( D, A, B, C, 5, 12, 0x4787C62A );
94 | P( C, D, A, B, 6, 17, 0xA8304613 );
95 | P( B, C, D, A, 7, 22, 0xFD469501 );
96 | P( A, B, C, D, 8, 7, 0x698098D8 );
97 | P( D, A, B, C, 9, 12, 0x8B44F7AF );
98 | P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
99 | P( B, C, D, A, 11, 22, 0x895CD7BE );
100 | P( A, B, C, D, 12, 7, 0x6B901122 );
101 | P( D, A, B, C, 13, 12, 0xFD987193 );
102 | P( C, D, A, B, 14, 17, 0xA679438E );
103 | P( B, C, D, A, 15, 22, 0x49B40821 );
104 |
105 | #undef F
106 |
107 | #define F(x,y,z) (y ^ (z & (x ^ y)))
108 |
109 | P( A, B, C, D, 1, 5, 0xF61E2562 );
110 | P( D, A, B, C, 6, 9, 0xC040B340 );
111 | P( C, D, A, B, 11, 14, 0x265E5A51 );
112 | P( B, C, D, A, 0, 20, 0xE9B6C7AA );
113 | P( A, B, C, D, 5, 5, 0xD62F105D );
114 | P( D, A, B, C, 10, 9, 0x02441453 );
115 | P( C, D, A, B, 15, 14, 0xD8A1E681 );
116 | P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
117 | P( A, B, C, D, 9, 5, 0x21E1CDE6 );
118 | P( D, A, B, C, 14, 9, 0xC33707D6 );
119 | P( C, D, A, B, 3, 14, 0xF4D50D87 );
120 | P( B, C, D, A, 8, 20, 0x455A14ED );
121 | P( A, B, C, D, 13, 5, 0xA9E3E905 );
122 | P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
123 | P( C, D, A, B, 7, 14, 0x676F02D9 );
124 | P( B, C, D, A, 12, 20, 0x8D2A4C8A );
125 |
126 | #undef F
127 |
128 | #define F(x,y,z) (x ^ y ^ z)
129 |
130 | P( A, B, C, D, 5, 4, 0xFFFA3942 );
131 | P( D, A, B, C, 8, 11, 0x8771F681 );
132 | P( C, D, A, B, 11, 16, 0x6D9D6122 );
133 | P( B, C, D, A, 14, 23, 0xFDE5380C );
134 | P( A, B, C, D, 1, 4, 0xA4BEEA44 );
135 | P( D, A, B, C, 4, 11, 0x4BDECFA9 );
136 | P( C, D, A, B, 7, 16, 0xF6BB4B60 );
137 | P( B, C, D, A, 10, 23, 0xBEBFBC70 );
138 | P( A, B, C, D, 13, 4, 0x289B7EC6 );
139 | P( D, A, B, C, 0, 11, 0xEAA127FA );
140 | P( C, D, A, B, 3, 16, 0xD4EF3085 );
141 | P( B, C, D, A, 6, 23, 0x04881D05 );
142 | P( A, B, C, D, 9, 4, 0xD9D4D039 );
143 | P( D, A, B, C, 12, 11, 0xE6DB99E5 );
144 | P( C, D, A, B, 15, 16, 0x1FA27CF8 );
145 | P( B, C, D, A, 2, 23, 0xC4AC5665 );
146 |
147 | #undef F
148 |
149 | #define F(x,y,z) (y ^ (x | ~z))
150 |
151 | P( A, B, C, D, 0, 6, 0xF4292244 );
152 | P( D, A, B, C, 7, 10, 0x432AFF97 );
153 | P( C, D, A, B, 14, 15, 0xAB9423A7 );
154 | P( B, C, D, A, 5, 21, 0xFC93A039 );
155 | P( A, B, C, D, 12, 6, 0x655B59C3 );
156 | P( D, A, B, C, 3, 10, 0x8F0CCC92 );
157 | P( C, D, A, B, 10, 15, 0xFFEFF47D );
158 | P( B, C, D, A, 1, 21, 0x85845DD1 );
159 | P( A, B, C, D, 8, 6, 0x6FA87E4F );
160 | P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
161 | P( C, D, A, B, 6, 15, 0xA3014314 );
162 | P( B, C, D, A, 13, 21, 0x4E0811A1 );
163 | P( A, B, C, D, 4, 6, 0xF7537E82 );
164 | P( D, A, B, C, 11, 10, 0xBD3AF235 );
165 | P( C, D, A, B, 2, 15, 0x2AD7D2BB );
166 | P( B, C, D, A, 9, 21, 0xEB86D391 );
167 |
168 | #undef F
169 |
170 | ctx->state[0] += A;
171 | ctx->state[1] += B;
172 | ctx->state[2] += C;
173 | ctx->state[3] += D;
174 | }
175 | #endif /* !MBEDTLS_MD5_PROCESS_ALT */
176 |
177 | /*
178 | * MD5 process buffer
179 | */
180 | void mbedtls_md5_update( mbedtls_md5_context *ctx, const unsigned char *input, size_t ilen )
181 | {
182 | size_t fill;
183 | uint32_t left;
184 |
185 | if( ilen == 0 )
186 | return;
187 |
188 | left = ctx->total[0] & 0x3F;
189 | fill = 64 - left;
190 |
191 | ctx->total[0] += (uint32_t) ilen;
192 | ctx->total[0] &= 0xFFFFFFFF;
193 |
194 | if( ctx->total[0] < (uint32_t) ilen )
195 | ctx->total[1]++;
196 |
197 | if( left && ilen >= fill )
198 | {
199 | memcpy( (void *) (ctx->buffer + left), input, fill );
200 | mbedtls_md5_process( ctx, ctx->buffer );
201 | input += fill;
202 | ilen -= fill;
203 | left = 0;
204 | }
205 |
206 | while( ilen >= 64 )
207 | {
208 | mbedtls_md5_process( ctx, input );
209 | input += 64;
210 | ilen -= 64;
211 | }
212 |
213 | if( ilen > 0 )
214 | {
215 | memcpy( (void *) (ctx->buffer + left), input, ilen );
216 | }
217 | }
218 |
219 | static const unsigned char md5_padding[64] =
220 | {
221 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
222 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
223 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
224 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
225 | };
226 |
227 | /*
228 | * MD5 final digest
229 | */
230 | void mbedtls_md5_finish( mbedtls_md5_context *ctx, unsigned char output[16] )
231 | {
232 | uint32_t last, padn;
233 | uint32_t high, low;
234 | unsigned char msglen[8];
235 |
236 | high = ( ctx->total[0] >> 29 )
237 | | ( ctx->total[1] << 3 );
238 | low = ( ctx->total[0] << 3 );
239 |
240 | PUT_UINT32_LE( low, msglen, 0 );
241 | PUT_UINT32_LE( high, msglen, 4 );
242 |
243 | last = ctx->total[0] & 0x3F;
244 | padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
245 |
246 | mbedtls_md5_update( ctx, md5_padding, padn );
247 | mbedtls_md5_update( ctx, msglen, 8 );
248 |
249 | PUT_UINT32_LE( ctx->state[0], output, 0 );
250 | PUT_UINT32_LE( ctx->state[1], output, 4 );
251 | PUT_UINT32_LE( ctx->state[2], output, 8 );
252 | PUT_UINT32_LE( ctx->state[3], output, 12 );
253 | }
254 |
255 |
256 | /*
257 | * output = MD5( input buffer )
258 | */
259 | void mbedtls_md5( const unsigned char *input, size_t ilen, unsigned char output[16] )
260 | {
261 | mbedtls_md5_context ctx;
262 |
263 | mbedtls_md5_init( &ctx );
264 | mbedtls_md5_starts( &ctx );
265 | mbedtls_md5_update( &ctx, input, ilen );
266 | mbedtls_md5_finish( &ctx, output );
267 | }
268 |
--------------------------------------------------------------------------------
/src/md5.h:
--------------------------------------------------------------------------------
1 | #ifndef MD5_H_
2 | #define MD5_H_
3 |
4 | #include
5 | #include
6 |
7 | #ifdef __cplusplus
8 | extern "C" {
9 | #endif
10 |
11 | /**
12 | * \brief MD5 context structure
13 | */
14 | typedef struct
15 | {
16 | uint32_t total[2]; /*!< number of bytes processed */
17 | uint32_t state[4]; /*!< intermediate digest state */
18 | unsigned char buffer[64]; /*!< data block being processed */
19 | } mbedtls_md5_context;
20 |
21 | /**
22 | * \brief Initialize MD5 context
23 | *
24 | * \param ctx MD5 context to be initialized
25 | */
26 | void mbedtls_md5_init( mbedtls_md5_context *ctx );
27 |
28 |
29 | /**
30 | * \brief Clone (the state of) an MD5 context
31 | *
32 | * \param dst The destination context
33 | * \param src The context to be cloned
34 | */
35 | void mbedtls_md5_clone( mbedtls_md5_context *dst,
36 | const mbedtls_md5_context *src );
37 |
38 | /**
39 | * \brief MD5 context setup
40 | *
41 | * \param ctx context to be initialized
42 | */
43 | void mbedtls_md5_starts( mbedtls_md5_context *ctx );
44 |
45 | /**
46 | * \brief MD5 process buffer
47 | *
48 | * \param ctx MD5 context
49 | * \param input buffer holding the data
50 | * \param ilen length of the input data
51 | */
52 | void mbedtls_md5_update( mbedtls_md5_context *ctx, const unsigned char *input, size_t ilen );
53 |
54 | /**
55 | * \brief MD5 final digest
56 | *
57 | * \param ctx MD5 context
58 | * \param output MD5 checksum result
59 | */
60 | void mbedtls_md5_finish( mbedtls_md5_context *ctx, unsigned char output[16] );
61 |
62 | /* Internal use */
63 | void mbedtls_md5_process( mbedtls_md5_context *ctx, const unsigned char data[64] );
64 |
65 |
66 | /**
67 | * \brief Output = MD5( input buffer )
68 | *
69 | * \param input buffer holding the data
70 | * \param ilen length of the input data
71 | * \param output MD5 checksum result
72 | */
73 | void mbedtls_md5( const unsigned char *input, size_t ilen, unsigned char output[16] );
74 |
75 |
76 | #ifdef __cplusplus
77 | }
78 | #endif
79 |
80 |
81 | #endif /*MD5_H_*/
82 |
--------------------------------------------------------------------------------
/src/sds.c:
--------------------------------------------------------------------------------
1 | /* SDSLib, A C dynamic strings library
2 | *
3 | * Copyright (c) 2006-2012, Salvatore Sanfilippo
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * * Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * * Neither the name of Redis nor the names of its contributors may be used
15 | * to endorse or promote products derived from this software without
16 | * specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 | * POSSIBILITY OF SUCH DAMAGE.
29 | */
30 |
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include "sds.h"
37 |
38 | size_t sdslen(const sds s) {
39 | struct sdshdr *sh = (struct sdshdr *) (s - (sizeof(struct sdshdr)));
40 | return sh->len;
41 | }
42 |
43 | size_t sdsavail(const sds s) {
44 | struct sdshdr *sh = (struct sdshdr *) (s - (sizeof(struct sdshdr)));
45 | return sh->free;
46 | }
47 |
48 | /* Create a new sds string with the content specified by the 'init' pointer
49 | * and 'initlen'.
50 | * If NULL is used for 'init' the string is initialized with zero bytes.
51 | *
52 | * The string is always null-termined (all the sds strings are, always) so
53 | * even if you create an sds string with:
54 | *
55 | * mystring = sdsnewlen("abc",3);
56 | *
57 | * You can print the string with printf() as there is an implicit \0 at the
58 | * end of the string. However the string is binary safe and can contain
59 | * \0 characters in the middle, as the length is stored in the sds header. */
60 | sds sdsnewlen(const void *init, size_t initlen) {
61 | struct sdshdr *sh;
62 |
63 | if (init) {
64 | sh = malloc(sizeof(struct sdshdr) + initlen + 1);
65 | } else {
66 | sh = calloc(sizeof(struct sdshdr) + initlen + 1, 1);
67 | }
68 | if (sh == NULL) return NULL;
69 | sh->len = initlen;
70 | sh->free = 0;
71 | if (initlen && init)
72 | memcpy(sh->buf, init, initlen);
73 | sh->buf[initlen] = '\0';
74 | return (char *) sh->buf;
75 | }
76 |
77 |
78 | sds sdsnewEmpty(size_t preAlloclen) {
79 | struct sdshdr *sh;
80 |
81 | sh = malloc(sizeof(struct sdshdr) + preAlloclen + 1);
82 | if (sh == NULL) return NULL;
83 | sh->len = 0;
84 | sh->free = preAlloclen;
85 | sh->buf[0] = '\0';
86 | return (char *) sh->buf;
87 | }
88 |
89 |
90 | /* Create an empty (zero length) sds string. Even in this case the string
91 | * always has an implicit null term. */
92 | sds sdsempty(void) {
93 | return sdsnewlen("", 0);
94 | }
95 |
96 | /* Create a new sds string starting from a null terminated C string. */
97 | sds sdsnew(const char *init) {
98 | size_t initlen = (init == NULL) ? 0 : strlen(init);
99 | return sdsnewlen(init, initlen);
100 | }
101 |
102 | /* Duplicate an sds string. */
103 | sds sdsdup(const sds s) {
104 | if (s == NULL) return NULL;
105 | return sdsnewlen(s, sdslen(s));
106 | }
107 |
108 | /* Free an sds string. No operation is performed if 's' is NULL. */
109 | void sdsfree(sds s) {
110 | if (s == NULL) return;
111 | free(s - sizeof(struct sdshdr));
112 | }
113 |
114 | /* Set the sds string length to the length as obtained with strlen(), so
115 | * considering as content only up to the first null term character.
116 | *
117 | * This function is useful when the sds string is hacked manually in some
118 | * way, like in the following example:
119 | *
120 | * s = sdsnew("foobar");
121 | * s[2] = '\0';
122 | * sdsupdatelen(s);
123 | * printf("%d\n", sdslen(s));
124 | *
125 | * The output will be "2", but if we comment out the call to sdsupdatelen()
126 | * the output will be "6" as the string was modified but the logical length
127 | * remains 6 bytes. */
128 | void sdsupdatelen(sds s) {
129 | struct sdshdr *sh = (void *) (s - (sizeof(struct sdshdr)));
130 | int reallen = strlen(s);
131 | sh->free += (sh->len - reallen);
132 | sh->len = reallen;
133 | }
134 |
135 | /* Modify an sds string in-place to make it empty (zero length).
136 | * However all the existing buffer is not discarded but set as free space
137 | * so that next append operations will not require allocations up to the
138 | * number of bytes previously available. */
139 | void sdsclear(sds s) {
140 | struct sdshdr *sh = (void *) (s - (sizeof(struct sdshdr)));
141 | sh->free += sh->len;
142 | sh->len = 0;
143 | sh->buf[0] = '\0';
144 | }
145 |
146 | /* Enlarge the free space at the end of the sds string so that the caller
147 | * is sure that after calling this function can overwrite up to addlen
148 | * bytes after the end of the string, plus one more byte for nul term.
149 | *
150 | * Note: this does not change the *length* of the sds string as returned
151 | * by sdslen(), but only the free buffer space we have. */
152 | sds sdsMakeRoomFor(sds s, size_t addlen) {
153 | struct sdshdr *sh, *newsh;
154 | size_t free = sdsavail(s);
155 | size_t len, newlen;
156 |
157 | if (free >= addlen) return s;
158 | len = sdslen(s);
159 | sh = (void *) (s - (sizeof(struct sdshdr)));
160 | newlen = (len + addlen);
161 | if (newlen < SDS_MAX_PREALLOC)
162 | newlen *= 2;
163 | else
164 | newlen += SDS_MAX_PREALLOC;
165 | newsh = realloc(sh, sizeof(struct sdshdr) + newlen + 1);
166 | if (newsh == NULL) return NULL;
167 |
168 | newsh->free = newlen - len;
169 | return newsh->buf;
170 | }
171 |
172 | /* Reallocate the sds string so that it has no free space at the end. The
173 | * contained string remains not altered, but next concatenation operations
174 | * will require a reallocation.
175 | *
176 | * After the call, the passed sds string is no longer valid and all the
177 | * references must be substituted with the new pointer returned by the call. */
178 | sds sdsRemoveFreeSpace(sds s) {
179 | struct sdshdr *sh;
180 |
181 | sh = (void *) (s - (sizeof(struct sdshdr)));
182 | sh = realloc(sh, sizeof(struct sdshdr) + sh->len + 1);
183 | sh->free = 0;
184 | return sh->buf;
185 | }
186 |
187 | /* Return the total size of the allocation of the specifed sds string,
188 | * including:
189 | * 1) The sds header before the pointer.
190 | * 2) The string.
191 | * 3) The free buffer at the end if any.
192 | * 4) The implicit null term.
193 | */
194 | size_t sdsAllocSize(sds s) {
195 | struct sdshdr *sh = (void *) (s - (sizeof(struct sdshdr)));
196 |
197 | return sizeof(*sh) + sh->len + sh->free + 1;
198 | }
199 |
200 | /* Increment the sds length and decrements the left free space at the
201 | * end of the string according to 'incr'. Also set the null term
202 | * in the new end of the string.
203 | *
204 | * This function is used in order to fix the string length after the
205 | * user calls sdsMakeRoomFor(), writes something after the end of
206 | * the current string, and finally needs to set the new length.
207 | *
208 | * Note: it is possible to use a negative increment in order to
209 | * right-trim the string.
210 | *
211 | * Usage example:
212 | *
213 | * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the
214 | * following schema, to cat bytes coming from the kernel to the end of an
215 | * sds string without copying into an intermediate buffer:
216 | *
217 | * oldlen = sdslen(s);
218 | * s = sdsMakeRoomFor(s, BUFFER_SIZE);
219 | * nread = read(fd, s+oldlen, BUFFER_SIZE);
220 | * ... check for nread <= 0 and handle it ...
221 | * sdsIncrLen(s, nread);
222 | */
223 | void sdsIncrLen(sds s, int incr) {
224 | struct sdshdr *sh = (void *) (s - (sizeof(struct sdshdr)));
225 |
226 | if (incr >= 0)
227 | assert(sh->free >= (unsigned int) incr);
228 | else
229 | assert(sh->len >= (unsigned int) (-incr));
230 | sh->len += incr;
231 | sh->free -= incr;
232 | s[sh->len] = '\0';
233 | }
234 |
235 | /* Grow the sds to have the specified length. Bytes that were not part of
236 | * the original length of the sds will be set to zero.
237 | *
238 | * if the specified length is smaller than the current length, no operation
239 | * is performed. */
240 | sds sdsgrowzero(sds s, size_t len) {
241 | struct sdshdr *sh = (void *) (s - (sizeof(struct sdshdr)));
242 | size_t totlen, curlen = sh->len;
243 |
244 | if (len <= curlen) return s;
245 | s = sdsMakeRoomFor(s, len - curlen);
246 | if (s == NULL) return NULL;
247 |
248 | /* Make sure added region doesn't contain garbage */
249 | sh = (void *) (s - (sizeof(struct sdshdr)));
250 | memset(s + curlen, 0, (len - curlen + 1)); /* also set trailing \0 byte */
251 | totlen = sh->len + sh->free;
252 | sh->len = len;
253 | sh->free = totlen - sh->len;
254 | return s;
255 | }
256 |
257 | /* Append the specified binary-safe string pointed by 't' of 'len' bytes to the
258 | * end of the specified sds string 's'.
259 | *
260 | * After the call, the passed sds string is no longer valid and all the
261 | * references must be substituted with the new pointer returned by the call. */
262 | sds sdscatlen(sds s, const void *t, size_t len) {
263 | struct sdshdr *sh;
264 | size_t curlen = sdslen(s);
265 |
266 | s = sdsMakeRoomFor(s, len);
267 | if (s == NULL) return NULL;
268 | sh = (void *) (s - (sizeof(struct sdshdr)));
269 | memcpy(s + curlen, t, len);
270 | sh->len = curlen + len;
271 | sh->free = sh->free - len;
272 | s[curlen + len] = '\0';
273 | return s;
274 | }
275 |
276 |
277 | sds sdscatchar(sds s, char c) {
278 | struct sdshdr *sh;
279 | size_t curlen = sdslen(s);
280 |
281 | s = sdsMakeRoomFor(s, 1);
282 | if (s == NULL) return NULL;
283 | sh = (void *) (s - (sizeof(struct sdshdr)));
284 | s[curlen] = c;
285 | s[curlen + 1] = '\0';
286 | ++sh->len;
287 | --sh->free;
288 | return s;
289 | }
290 |
291 |
292 | /* Append the specified null termianted C string to the sds string 's'.
293 | *
294 | * After the call, the passed sds string is no longer valid and all the
295 | * references must be substituted with the new pointer returned by the call. */
296 | sds sdscat(sds s, const char *t) {
297 | if (s == NULL || t == NULL) {
298 | return s;
299 | }
300 | return sdscatlen(s, t, strlen(t));
301 | }
302 |
303 | /* Append the specified sds 't' to the existing sds 's'.
304 | *
305 | * After the call, the modified sds string is no longer valid and all the
306 | * references must be substituted with the new pointer returned by the call. */
307 | sds sdscatsds(sds s, const sds t) {
308 | return sdscatlen(s, t, sdslen(t));
309 | }
310 |
311 | /* Destructively modify the sds string 's' to hold the specified binary
312 | * safe string pointed by 't' of length 'len' bytes. */
313 | sds sdscpylen(sds s, const char *t, size_t len) {
314 | struct sdshdr *sh = (void *) (s - (sizeof(struct sdshdr)));
315 | size_t totlen = sh->free + sh->len;
316 |
317 | if (totlen < len) {
318 | s = sdsMakeRoomFor(s, len - sh->len);
319 | if (s == NULL) return NULL;
320 | sh = (void *) (s - (sizeof(struct sdshdr)));
321 | totlen = sh->free + sh->len;
322 | }
323 | memcpy(s, t, len);
324 | s[len] = '\0';
325 | sh->len = len;
326 | sh->free = totlen - len;
327 | return s;
328 | }
329 |
330 | /* Like sdscpylen() but 't' must be a null-termined string so that the length
331 | * of the string is obtained with strlen(). */
332 | sds sdscpy(sds s, const char *t) {
333 | return sdscpylen(s, t, strlen(t));
334 | }
335 |
336 |
337 |
338 | /* Like sdscatprintf() but gets va_list instead of being variadic. */
339 | sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
340 | va_list cpy;
341 | char staticbuf[1024], *buf = staticbuf, *t;
342 | size_t buflen = strlen(fmt) * 2;
343 |
344 | /* We try to start using a static buffer for speed.
345 | * If not possible we revert to heap allocation. */
346 | if (buflen > sizeof(staticbuf)) {
347 | buf = malloc(buflen);
348 | if (buf == NULL) return NULL;
349 | } else {
350 | buflen = sizeof(staticbuf);
351 | }
352 |
353 | /* Try with buffers two times bigger every time we fail to
354 | * fit the string in the current buffer size. */
355 | while (1) {
356 | buf[buflen - 2] = '\0';
357 | va_copy(cpy, ap);
358 | vsnprintf(buf, buflen, fmt, cpy);
359 | va_end(cpy);
360 | if (buf[buflen - 2] != '\0') {
361 | if (buf != staticbuf) free(buf);
362 | buflen *= 2;
363 | buf = malloc(buflen);
364 | if (buf == NULL) return NULL;
365 | continue;
366 | }
367 | break;
368 | }
369 |
370 | /* Finally concat the obtained string to the SDS string and return it. */
371 | t = sdscat(s, buf);
372 | if (buf != staticbuf) free(buf);
373 | return t;
374 | }
375 |
376 | /* Append to the sds string 's' a string obtained using printf-alike format
377 | * specifier.
378 | *
379 | * After the call, the modified sds string is no longer valid and all the
380 | * references must be substituted with the new pointer returned by the call.
381 | *
382 | * Example:
383 | *
384 | * s = sdsnew("Sum is: ");
385 | * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b).
386 | *
387 | * Often you need to create a string from scratch with the printf-alike
388 | * format. When this is the need, just use sdsempty() as the target string:
389 | *
390 | * s = sdscatprintf(sdsempty(), "... your format ...", args);
391 | */
392 | sds sdscatprintf(sds s, const char *fmt, ...) {
393 | va_list ap;
394 | char *t;
395 | va_start(ap, fmt);
396 | t = sdscatvprintf(s, fmt, ap);
397 | va_end(ap);
398 | return t;
399 | }
400 |
401 |
402 |
--------------------------------------------------------------------------------
/src/sds.h:
--------------------------------------------------------------------------------
1 | /* SDSLib, A C dynamic strings library
2 | *
3 | * Copyright (c) 2006-2010, Salvatore Sanfilippo
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * * Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * * Neither the name of Redis nor the names of its contributors may be used
15 | * to endorse or promote products derived from this software without
16 | * specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 | * POSSIBILITY OF SUCH DAMAGE.
29 | */
30 |
31 | #ifndef __SDS_H
32 | #define __SDS_H
33 |
34 | #define SDS_MAX_PREALLOC (1024*1024)
35 |
36 | #include
37 | #include
38 |
39 | #ifdef WIN32
40 | #define inline __inline
41 | #endif
42 |
43 | typedef char *sds;
44 |
45 | struct sdshdr {
46 | unsigned int len;
47 | unsigned int free;
48 | char buf[];
49 | };
50 |
51 | size_t sdslen(const sds s);
52 |
53 | size_t sdsavail(const sds s);
54 |
55 | sds sdsnewlen(const void *init, size_t initlen);
56 |
57 | sds sdsnewEmpty(size_t preAlloclen);
58 |
59 | sds sdsnew(const char *init);
60 |
61 | sds sdsempty(void);
62 |
63 | size_t sdslen(const sds s);
64 |
65 | sds sdsdup(const sds s);
66 |
67 | void sdsfree(sds s);
68 |
69 | size_t sdsavail(const sds s);
70 |
71 | sds sdsgrowzero(sds s, size_t len);
72 |
73 | sds sdscatlen(sds s, const void *t, size_t len);
74 |
75 | sds sdscat(sds s, const char *t);
76 |
77 | sds sdscatchar(sds s, char c);
78 |
79 | sds sdscatsds(sds s, const sds t);
80 |
81 | sds sdscpylen(sds s, const char *t, size_t len);
82 |
83 | sds sdscpy(sds s, const char *t);
84 |
85 | sds sdscatvprintf(sds s, const char *fmt, va_list ap);
86 |
87 | #ifdef __GNUC__
88 |
89 | sds sdscatprintf(sds s, const char *fmt, ...)
90 | __attribute__((format(printf, 2, 3)));
91 |
92 | #else
93 | sds sdscatprintf(sds s, const char *fmt, ...);
94 | #endif
95 |
96 |
97 | #endif
98 |
--------------------------------------------------------------------------------
/src/sha1.c:
--------------------------------------------------------------------------------
1 |
2 | #include /* memcpy & co */
3 | #include
4 | #include "sha1.h"
5 |
6 | #ifndef LITTLE_ENDIAN
7 | #define LITTLE_ENDIAN
8 | #endif
9 |
10 | /********************************************************************************************************/
11 |
12 | /**
13 | * \brief initialises given SHA-1 context
14 | *
15 | */
16 | void sha1_init(sha1_ctx_t *state){
17 | state->h[0] = 0x67452301;
18 | state->h[1] = 0xefcdab89;
19 | state->h[2] = 0x98badcfe;
20 | state->h[3] = 0x10325476;
21 | state->h[4] = 0xc3d2e1f0;
22 | state->length = 0;
23 | }
24 |
25 | /********************************************************************************************************/
26 | /* some helping functions */
27 | uint32_t rotl32(uint32_t n, uint8_t bits){
28 | return ((n<>(32-bits)));
29 | }
30 |
31 | uint32_t change_endian32(uint32_t x){
32 | return (((x)<<24) | ((x)>>24) | (((x)& 0x0000ff00)<<8) | (((x)& 0x00ff0000)>>8));
33 | }
34 |
35 |
36 | /* three SHA-1 inner functions */
37 | uint32_t ch(uint32_t x, uint32_t y, uint32_t z){
38 | return ((x&y)^((~x)&z));
39 | }
40 |
41 | uint32_t maj(uint32_t x, uint32_t y, uint32_t z){
42 | return ((x&y)^(x&z)^(y&z));
43 | }
44 |
45 | uint32_t parity(uint32_t x, uint32_t y, uint32_t z){
46 | return ((x^y)^z);
47 | }
48 |
49 | /********************************************************************************************************/
50 | /**
51 | * \brief "add" a block to the hash
52 | * This is the core function of the hash algorithm. To understand how it's working
53 | * and what thoese variables do, take a look at FIPS-182. This is an "alternativ" implementation
54 | */
55 |
56 | #define MASK 0x0000000f
57 |
58 | typedef uint32_t (*pf_t)(uint32_t x, uint32_t y, uint32_t z);
59 |
60 | void sha1_nextBlock (sha1_ctx_t *state, const void *block){
61 | uint32_t a[5];
62 | uint32_t w[16];
63 | uint32_t temp;
64 | uint8_t t,s,fi, fib;
65 | pf_t f[] = {ch,parity,maj,parity};
66 | uint32_t k[4]={ 0x5a827999,
67 | 0x6ed9eba1,
68 | 0x8f1bbcdc,
69 | 0xca62c1d6};
70 |
71 | /* load the w array (changing the endian and so) */
72 | for(t=0; t<16; ++t){
73 | w[t] = change_endian32(((uint32_t*)block)[t]);
74 | }
75 |
76 |
77 | /* load the state */
78 | memcpy(a, state->h, 5*sizeof(uint32_t));
79 |
80 |
81 | /* the fun stuff */
82 | for(fi=0,fib=0,t=0; t<=79; ++t){
83 | s = t & MASK;
84 | if(t>=16){
85 | w[s] = rotl32( w[(s+13)&MASK] ^ w[(s+8)&MASK] ^
86 | w[(s+ 2)&MASK] ^ w[s] ,1);
87 | }
88 |
89 | uint32_t dtemp;
90 | temp = rotl32(a[0],5) + (dtemp=f[fi](a[1],a[2],a[3])) + a[4] + k[fi] + w[s];
91 | memmove(&(a[1]), &(a[0]), 4*sizeof(uint32_t)); /* e=d; d=c; c=b; b=a; */
92 | a[0] = temp;
93 | a[2] = rotl32(a[2],30); /* we might also do rotr32(c,2) */
94 | fib++;
95 | if(fib==20){
96 | fib=0;
97 | fi = (fi+1)%4;
98 | }
99 | }
100 |
101 | /* update the state */
102 | for(t=0; t<5; ++t){
103 | state->h[t] += a[t];
104 | }
105 | state->length += 512;
106 | }
107 |
108 | /********************************************************************************************************/
109 |
110 | void sha1_lastBlock(sha1_ctx_t *state, const void *block, uint16_t length){
111 | uint8_t lb[SHA1_BLOCK_BYTES]; /* local block */
112 | while(length>=SHA1_BLOCK_BITS){
113 | sha1_nextBlock(state, block);
114 | length -= SHA1_BLOCK_BITS;
115 | block = (uint8_t*)block + SHA1_BLOCK_BYTES;
116 | }
117 | state->length += length;
118 | memset(lb, 0, SHA1_BLOCK_BYTES);
119 | memcpy (lb, block, (length+7)>>3);
120 |
121 | /* set the final one bit */
122 | lb[length>>3] |= 0x80>>(length & 0x07);
123 |
124 | if (length>512-64-1){ /* not enouth space for 64bit length value */
125 | sha1_nextBlock(state, lb);
126 | state->length -= 512;
127 | memset(lb, 0, SHA1_BLOCK_BYTES);
128 | }
129 | /* store the 64bit length value */
130 | #if defined LITTLE_ENDIAN
131 | /* this is now rolled up */
132 | uint8_t i;
133 | for (i=0; i<8; ++i){
134 | lb[56+i] = ((uint8_t*)&(state->length))[7-i];
135 | }
136 | #elif defined BIG_ENDIAN
137 | *((uint64_t)&(lb[56])) = state->length;
138 | #endif
139 | sha1_nextBlock(state, lb);
140 | }
141 |
142 | /********************************************************************************************************/
143 |
144 | void sha1_ctx2hash (void *dest, sha1_ctx_t *state){
145 | #if defined LITTLE_ENDIAN
146 | uint8_t i;
147 | for(i=0; i<5; ++i){
148 | ((uint32_t*)dest)[i] = change_endian32(state->h[i]);
149 | }
150 | #elif BIG_ENDIAN
151 | if (dest != state->h)
152 | memcpy(dest, state->h, SHA1_HASH_BITS/8);
153 | #else
154 | # error unsupported endian type!
155 | #endif
156 | }
157 |
158 | /********************************************************************************************************/
159 | /**
160 | *
161 | *
162 | */
163 | void sha1 (void *dest, const void *msg, uint32_t length){
164 | sha1_ctx_t s;
165 | sha1_init(&s);
166 | while(length & (~0x0001ff)){ /* length>=512 */
167 | sha1_nextBlock(&s, msg);
168 | msg = (uint8_t*)msg + SHA1_BLOCK_BITS/8; /* increment pointer to next block */
169 | length -= SHA1_BLOCK_BITS;
170 | }
171 | sha1_lastBlock(&s, msg, length);
172 | sha1_ctx2hash(dest, &s);
173 | }
174 |
--------------------------------------------------------------------------------
/src/sha1.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef SHA1_H_
3 | #define SHA1_H_
4 |
5 | #include
6 | /** \def SHA1_HASH_BITS
7 | * definees the size of a SHA-1 hash in bits
8 | */
9 |
10 | /** \def SHA1_HASH_BYTES
11 | * definees the size of a SHA-1 hash in bytes
12 | */
13 |
14 | /** \def SHA1_BLOCK_BITS
15 | * definees the size of a SHA-1 input block in bits
16 | */
17 |
18 | /** \def SHA1_BLOCK_BYTES
19 | * definees the size of a SHA-1 input block in bytes
20 | */
21 | #define SHA1_HASH_BITS 160
22 | #define SHA1_HASH_BYTES (SHA1_HASH_BITS/8)
23 | #define SHA1_BLOCK_BITS 512
24 | #define SHA1_BLOCK_BYTES (SHA1_BLOCK_BITS/8)
25 |
26 | /** \typedef sha1_ctx_t
27 | * \brief SHA-1 context type
28 | *
29 | * A vatiable of this type may hold the state of a SHA-1 hashing process
30 | */
31 | typedef struct {
32 | uint32_t h[5];
33 | uint64_t length;
34 | } sha1_ctx_t;
35 |
36 | /** \typedef sha1_hash_t
37 | * \brief hash value type
38 | * A variable of this type may hold a SHA-1 hash value
39 | */
40 | /*
41 | typedef uint8_t sha1_hash_t[SHA1_HASH_BITS/8];
42 | */
43 |
44 | /** \fn sha1_init(sha1_ctx_t *state)
45 | * \brief initializes a SHA-1 context
46 | * This function sets a ::sha1_ctx_t variable to the initialization vector
47 | * for SHA-1 hashing.
48 | * \param state pointer to the SHA-1 context variable
49 | */
50 | void sha1_init(sha1_ctx_t *state);
51 |
52 | /** \fn sha1_nextBlock(sha1_ctx_t *state, const void *block)
53 | * \brief process one input block
54 | * This function processes one input block and updates the hash context
55 | * accordingly
56 | * \param state pointer to the state variable to update
57 | * \param block pointer to the message block to process
58 | */
59 | void sha1_nextBlock (sha1_ctx_t *state, const void *block);
60 |
61 | /** \fn sha1_lastBlock(sha1_ctx_t *state, const void *block, uint16_t length_b)
62 | * \brief processes the given block and finalizes the context
63 | * This function processes the last block in a SHA-1 hashing process.
64 | * The block should have a maximum length of a single input block.
65 | * \param state pointer to the state variable to update and finalize
66 | * \param block pointer to themessage block to process
67 | * \param length_b length of the message block in bits
68 | */
69 | void sha1_lastBlock (sha1_ctx_t *state, const void *block, uint16_t length_b);
70 |
71 | /** \fn sha1_ctx2hash(sha1_hash_t *dest, sha1_ctx_t *state)
72 | * \brief convert a state variable into an actual hash value
73 | * Writes the hash value corresponding to the state to the memory pointed by dest.
74 | * \param dest pointer to the hash value destination
75 | * \param state pointer to the hash context
76 | */
77 | void sha1_ctx2hash (void *dest, sha1_ctx_t *state);
78 |
79 | /** \fn sha1(sha1_hash_t *dest, const void *msg, uint32_t length_b)
80 | * \brief hashing a message which in located entirely in RAM
81 | * This function automatically hashes a message which is entirely in RAM with
82 | * the SHA-1 hashing algorithm.
83 | * \param dest pointer to the hash value destination
84 | * \param msg pointer to the message which should be hashed
85 | * \param length_b length of the message in bits
86 | */
87 | void sha1(void *dest, const void *msg, uint32_t length_b);
88 |
89 |
90 |
91 | #endif /*SHA1_H_*/
92 |
--------------------------------------------------------------------------------
/src/sha256.c:
--------------------------------------------------------------------------------
1 | /*
2 | * FIPS-180-2 compliant SHA-256 implementation
3 | *
4 | * Copyright (C) 2001-2003 Christophe Devine
5 | *
6 | * This program is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation; either version 2 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program; if not, write to the Free Software
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 | */
20 |
21 | #include
22 |
23 | #include "sha256.h"
24 |
25 | #define GET_UINT32(n,b,i) \
26 | { \
27 | (n) = ( (uint32) (b)[(i) ] << 24 ) \
28 | | ( (uint32) (b)[(i) + 1] << 16 ) \
29 | | ( (uint32) (b)[(i) + 2] << 8 ) \
30 | | ( (uint32) (b)[(i) + 3] ); \
31 | }
32 |
33 | #define PUT_UINT32(n,b,i) \
34 | { \
35 | (b)[(i) ] = (uint8) ( (n) >> 24 ); \
36 | (b)[(i) + 1] = (uint8) ( (n) >> 16 ); \
37 | (b)[(i) + 2] = (uint8) ( (n) >> 8 ); \
38 | (b)[(i) + 3] = (uint8) ( (n) ); \
39 | }
40 |
41 | void sha256_starts( sha256_context *ctx )
42 | {
43 | ctx->total[0] = 0;
44 | ctx->total[1] = 0;
45 |
46 | ctx->state[0] = 0x6A09E667;
47 | ctx->state[1] = 0xBB67AE85;
48 | ctx->state[2] = 0x3C6EF372;
49 | ctx->state[3] = 0xA54FF53A;
50 | ctx->state[4] = 0x510E527F;
51 | ctx->state[5] = 0x9B05688C;
52 | ctx->state[6] = 0x1F83D9AB;
53 | ctx->state[7] = 0x5BE0CD19;
54 | }
55 |
56 | void sha256_process( sha256_context *ctx, uint8 data[64] )
57 | {
58 | uint32 temp1, temp2, W[64];
59 | uint32 A, B, C, D, E, F, G, H;
60 |
61 | GET_UINT32( W[0], data, 0 );
62 | GET_UINT32( W[1], data, 4 );
63 | GET_UINT32( W[2], data, 8 );
64 | GET_UINT32( W[3], data, 12 );
65 | GET_UINT32( W[4], data, 16 );
66 | GET_UINT32( W[5], data, 20 );
67 | GET_UINT32( W[6], data, 24 );
68 | GET_UINT32( W[7], data, 28 );
69 | GET_UINT32( W[8], data, 32 );
70 | GET_UINT32( W[9], data, 36 );
71 | GET_UINT32( W[10], data, 40 );
72 | GET_UINT32( W[11], data, 44 );
73 | GET_UINT32( W[12], data, 48 );
74 | GET_UINT32( W[13], data, 52 );
75 | GET_UINT32( W[14], data, 56 );
76 | GET_UINT32( W[15], data, 60 );
77 |
78 | #define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
79 | #define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
80 |
81 | #define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
82 | #define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
83 |
84 | #define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
85 | #define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
86 |
87 | #define F0(x,y,z) ((x & y) | (z & (x | y)))
88 | #define F1(x,y,z) (z ^ (x & (y ^ z)))
89 |
90 | #define R(t) \
91 | ( \
92 | W[t] = S1(W[t - 2]) + W[t - 7] + \
93 | S0(W[t - 15]) + W[t - 16] \
94 | )
95 |
96 | #define P(a,b,c,d,e,f,g,h,x,K) \
97 | { \
98 | temp1 = h + S3(e) + F1(e,f,g) + K + x; \
99 | temp2 = S2(a) + F0(a,b,c); \
100 | d += temp1; h = temp1 + temp2; \
101 | }
102 |
103 | A = ctx->state[0];
104 | B = ctx->state[1];
105 | C = ctx->state[2];
106 | D = ctx->state[3];
107 | E = ctx->state[4];
108 | F = ctx->state[5];
109 | G = ctx->state[6];
110 | H = ctx->state[7];
111 |
112 | P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 );
113 | P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 );
114 | P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF );
115 | P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 );
116 | P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B );
117 | P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 );
118 | P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 );
119 | P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 );
120 | P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 );
121 | P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 );
122 | P( G, H, A, B, C, D, E, F, W[10], 0x243185BE );
123 | P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 );
124 | P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 );
125 | P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE );
126 | P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 );
127 | P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 );
128 | P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 );
129 | P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 );
130 | P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 );
131 | P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC );
132 | P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F );
133 | P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA );
134 | P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC );
135 | P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA );
136 | P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 );
137 | P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D );
138 | P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 );
139 | P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 );
140 | P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 );
141 | P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 );
142 | P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 );
143 | P( B, C, D, E, F, G, H, A, R(31), 0x14292967 );
144 | P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 );
145 | P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 );
146 | P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC );
147 | P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 );
148 | P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 );
149 | P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB );
150 | P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E );
151 | P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 );
152 | P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 );
153 | P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B );
154 | P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 );
155 | P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 );
156 | P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 );
157 | P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 );
158 | P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 );
159 | P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 );
160 | P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 );
161 | P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 );
162 | P( G, H, A, B, C, D, E, F, R(50), 0x2748774C );
163 | P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 );
164 | P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 );
165 | P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A );
166 | P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F );
167 | P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 );
168 | P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE );
169 | P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F );
170 | P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 );
171 | P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 );
172 | P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA );
173 | P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB );
174 | P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 );
175 | P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 );
176 |
177 | ctx->state[0] += A;
178 | ctx->state[1] += B;
179 | ctx->state[2] += C;
180 | ctx->state[3] += D;
181 | ctx->state[4] += E;
182 | ctx->state[5] += F;
183 | ctx->state[6] += G;
184 | ctx->state[7] += H;
185 | }
186 |
187 | void sha256_update( sha256_context *ctx, uint8 *input, uint32 length )
188 | {
189 | uint32 left, fill;
190 |
191 | if( ! length ) return;
192 |
193 | left = ctx->total[0] & 0x3F;
194 | fill = 64 - left;
195 |
196 | ctx->total[0] += length;
197 | ctx->total[0] &= 0xFFFFFFFF;
198 |
199 | if( ctx->total[0] < length )
200 | ctx->total[1]++; /* #nocov */
201 |
202 | if( left && length >= fill )
203 | {
204 | memcpy( (void *) (ctx->buffer + left),
205 | (void *) input, fill );
206 | sha256_process( ctx, ctx->buffer );
207 | length -= fill;
208 | input += fill;
209 | left = 0;
210 | }
211 |
212 | while( length >= 64 )
213 | {
214 | sha256_process( ctx, input );
215 | length -= 64;
216 | input += 64;
217 | }
218 |
219 | if( length )
220 | {
221 | memcpy( (void *) (ctx->buffer + left),
222 | (void *) input, length );
223 | }
224 | }
225 |
226 | static uint8 sha256_padding[64] =
227 | {
228 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
229 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
230 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
231 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
232 | };
233 |
234 | void sha256_finish( sha256_context *ctx, uint8 digest[32] )
235 | {
236 | uint32 last, padn;
237 | uint32 high, low;
238 | uint8 msglen[8];
239 |
240 | high = ( ctx->total[0] >> 29 )
241 | | ( ctx->total[1] << 3 );
242 | low = ( ctx->total[0] << 3 );
243 |
244 | PUT_UINT32( high, msglen, 0 );
245 | PUT_UINT32( low, msglen, 4 );
246 |
247 | last = ctx->total[0] & 0x3F;
248 | padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
249 |
250 | sha256_update( ctx, sha256_padding, padn );
251 | sha256_update( ctx, msglen, 8 );
252 |
253 | PUT_UINT32( ctx->state[0], digest, 0 );
254 | PUT_UINT32( ctx->state[1], digest, 4 );
255 | PUT_UINT32( ctx->state[2], digest, 8 );
256 | PUT_UINT32( ctx->state[3], digest, 12 );
257 | PUT_UINT32( ctx->state[4], digest, 16 );
258 | PUT_UINT32( ctx->state[5], digest, 20 );
259 | PUT_UINT32( ctx->state[6], digest, 24 );
260 | PUT_UINT32( ctx->state[7], digest, 28 );
261 | }
--------------------------------------------------------------------------------
/src/sha256.h:
--------------------------------------------------------------------------------
1 | #ifndef _SHA256_H
2 | #define _SHA256_H
3 |
4 | #ifndef uint8
5 | #define uint8 unsigned char
6 | #endif
7 |
8 | #ifndef uint32
9 | #define uint32 unsigned long int
10 | #endif
11 |
12 | typedef struct
13 | {
14 | uint32 total[2];
15 | uint32 state[8];
16 | uint8 buffer[64];
17 | }
18 | sha256_context;
19 |
20 | void sha256_starts( sha256_context *ctx );
21 | void sha256_update( sha256_context *ctx, uint8 *input, uint32 length );
22 | void sha256_finish( sha256_context *ctx, uint8 digest[32] );
23 |
24 | #endif /* sha256.h */
--------------------------------------------------------------------------------