├── .gitignore
├── .travis.yml
├── BUILD.md
├── CMakeLists.txt
├── LICENSE-Apache
├── LatencyTests.md
├── PerfTest100M.md
├── README.md
├── TODO.md
├── examples
├── README.md
├── include
│ └── lightq_api.h
├── lib
│ └── liblightq.dylib
├── lightq-broker.c
├── lightq-consumer.c
├── lightq-producer.c
├── lightq-test.cpp
└── lightq-topic.c
├── include
├── admin_cmd.h
├── broker.h
├── broker_config.h
├── broker_manager.h
├── broker_storage.h
├── connection.h
├── connection_file.h
├── connection_socket.h
├── connection_zmq.h
├── consumer.h
├── file_details.h
├── lightq_api.h
├── log.h
├── monitor_zmq.h
├── producer.h
├── thirdparty
│ ├── atomicops.h
│ ├── concurrentqueue.h
│ ├── picojson.h
│ ├── readerwriterqueue.h
│ ├── spdlog
│ │ ├── async_logger.h
│ │ ├── common.h
│ │ ├── details
│ │ │ ├── async_log_helper.h
│ │ │ ├── async_logger_impl.h
│ │ │ ├── file_helper.h
│ │ │ ├── format.cc
│ │ │ ├── format.h
│ │ │ ├── line_logger.h
│ │ │ ├── log_msg.h
│ │ │ ├── logger_impl.h
│ │ │ ├── mpmc_bounded_q.h
│ │ │ ├── null_mutex.h
│ │ │ ├── os.h
│ │ │ ├── pattern_formatter_impl.h
│ │ │ ├── registry.h
│ │ │ └── spdlog_impl.h
│ │ ├── formatter.h
│ │ ├── logger.h
│ │ ├── sinks
│ │ │ ├── base_sink.h
│ │ │ ├── file_sinks.h
│ │ │ ├── null_sink.h
│ │ │ ├── ostream_sink.h
│ │ │ ├── sink.h
│ │ │ ├── stdout_sinks.h
│ │ │ └── syslog_sink.h
│ │ └── spdlog.h
│ ├── zhelpers.hpp
│ └── zmq.hpp
└── utils.h
└── src
└── lightq_api.cpp
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | build
3 | logs
4 | nbproject
5 | .idea
6 | .idea/dictionaries
7 | .idea/*
8 | examples/bin
9 | examples/logs
10 | examples/build
11 | examples/lib
12 | bin
13 | /examples/make.sh
14 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: cpp
2 |
3 | env:
4 | - release
5 | compiler:
6 | - gcc
7 |
8 | before_install:
9 | - echo $LANG
10 | - echo $LC_ALL
11 | - echo $TRAVIS_OS_NAME
12 | #LINUX
13 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y; fi
14 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq; fi
15 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install uuid-dev; fi
16 | - echo $CXX
17 | - echo `g++ --version`
18 | #- if [ "$CXX" = "clang++" ]; then sudo apt-get install -qq libstdc++-4.9-dev; fi
19 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq g++-4.9; fi
20 | - if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi
21 | #OSX
22 | #- if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install gcc49; fi
23 | - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install cmake; fi
24 | - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install libsodium; fi
25 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then git clone --depth 1 git://github.com/jedisct1/libsodium.git -b 0.4.5 libsodium; fi
26 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then cd libsodium; fi
27 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then ./autogen.sh; fi
28 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then ./configure; fi
29 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then make; sudo make install; cd ..; fi
30 | - git clone https://github.com/zeromq/zeromq4-1 zeromq4-1
31 | - cd zeromq4-1
32 | - ./autogen.sh
33 | - ./configure
34 | - make
35 | - sudo make install
36 | #- sudo /sbin/ldconfig
37 | - cd ..
38 |
39 | before_script:
40 | - mkdir build
41 | - cd build
42 | - cmake -DCMAKE_BUILD_TYPE=Release ..
43 |
44 |
45 | script:
46 | - make install
47 |
48 | branches:
49 | only:
50 | - master
51 |
52 |
53 | notifications:
54 | email: false
55 | irc:
56 | channels:
57 | - "chat.freenode.net#lightq"
58 | template:
59 | - "%{repository}/%{branch} (%{commit} - %{author}): %{build_url}: %{message}"
60 | webhooks:
61 | on_success: change
62 | on_failure: always
63 | on_start: always
64 |
65 |
66 |
67 | os:
68 | - linux
69 | - osx
70 |
71 |
--------------------------------------------------------------------------------
/BUILD.md:
--------------------------------------------------------------------------------
1 | LightQ project dependens on zeromq so make sure it is in the path.
2 |
3 | 1. Create a build directory and cd to build
4 |
5 | mkdir build
6 |
7 | cd build
8 |
9 | 2. Run cmake command
10 |
11 | cmake ..
12 |
13 | 3. Run make install command. It will install programs under bin directory
14 |
15 | make install
16 |
17 | cd ../bin
18 |
19 | mkdir logs #logs directory is required where you start program
20 |
21 | 4. Start a broker. Pass -h for optional command line options.
22 |
23 | ./lightq-broker
24 |
25 | 5. Create a topic (test). Pass -h for optional command line options.
26 |
27 | ./lightq-topic
28 |
29 | 6. Start a consumer (Read 10M messages). Pass -h for optional command line options.
30 |
31 | ./lightq-consumer -m 100000000
32 |
33 | 7. Start a producer (Send 10M messages). Pass -h for optional command line options.
34 |
35 | ./lightq-producer -m 10000000
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 |
2 | cmake_minimum_required(VERSION 2.8)
3 |
4 | project(lightq_project)
5 | SET( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -m64 -DDEBUG -std=c++11 -DPICOJSON_USE_INT64 -O0 -g " )
6 | SET( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -m64 -DNDEBUG -std=c++11 -Wall -Wextra -Wfloat-equal -Wundef -Wcast-align -Wwrite-strings -Wlogical-op -Wmissing-declarations -Wredundant-decls -Wshadow -Woverloaded-virtual -Wformat=2 -DPICOJSON_USE_INT64 -O3 -g " )
7 |
8 | include_directories(/usr/local/include include include/thirdparty /opt/zeromq/include)
9 | link_directories( /opt/zeromq/lib /usr/local/opt/zlib/lib)
10 |
11 |
12 | add_library(lightq SHARED src/lightq_api.cpp)
13 | TARGET_LINK_LIBRARIES(lightq zmq)
14 | install(TARGETS lightq DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/examples/lib)
15 | install(TARGETS lightq DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
16 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/lightq_api.h DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/examples/include)
17 |
18 | add_executable(lightq-test examples/lightq-test.cpp)
19 | target_link_libraries(lightq-test zmq z)
20 | install(TARGETS lightq-test DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
21 |
22 | SET( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -m64 -DDEBUG -std=c11 -O0 -g " )
23 | SET( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -m64 -DNDEBUG -std=c11 -Wall -Wextra -Wfloat-equal -Wundef -Wcast-align -Wwrite-strings -Wlogical-op -Wmissing-declarations -Wredundant-decls -Wshadow -Wformat=2 -O3 -g " )
24 | find_package (Threads)
25 | link_directories( ${PROJECT_BINARY_DIR}/lib )
26 |
27 | add_executable(lightq-broker examples/lightq-broker.c)
28 | target_link_libraries(lightq-broker lightq zmq pthread )
29 | install(TARGETS lightq-broker DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
30 |
31 | add_executable(lightq-consumer examples/lightq-consumer.c)
32 | target_link_libraries(lightq-consumer lightq zmq pthread)
33 | install(TARGETS lightq-consumer DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
34 |
35 | add_executable(lightq-producer examples/lightq-producer.c)
36 | target_link_libraries(lightq-producer lightq zmq pthread)
37 | install(TARGETS lightq-producer DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
38 |
39 | add_executable(lightq-topic examples/lightq-topic.c)
40 | target_link_libraries(lightq-topic lightq zmq pthread)
41 | install(TARGETS lightq-topic DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/PerfTest100M.md:
--------------------------------------------------------------------------------
1 | #Performance:
2 |
3 | Laptop hardware:
4 |
5 | MacBook Pro (Retina, 15-inch, Late 2013)
6 | Processor 2.3 GHz Intel Core i7
7 | Memory 16 GB 1600 MHz DDR3
8 |
9 | Broker Type: Transient
10 |
11 | Broker, Consumer and Producer is running on a same machine (Sharing memory/CPU)
12 |
13 | ##100 bytes, 100M messages
14 |
15 | Producer:
16 |
17 | ./dist/Release/GNU-MacOSX/lightq producer 100000000 100 event
18 | Total Messages:100000000, Time Taken:91.847 seconds.
19 | Start Time: 1427672217256, End Time:1427672309103
20 | 1088766 messages per seconds.
21 | 10000000000 bytes sent
22 | 103.8329 MB per second.
23 |
24 | Consumer:
25 |
26 | ./dist/Release/GNU-MacOSX/lightq consumer queue zmq pull event
27 | Total Messages:100000001, Time Taken:91.8728 seconds.
28 | Start Time: 1427672217260, End Time:1427672309133
29 | 1088462 messages per seconds.
30 | 10000000004 bytes received
31 | 103.8038 MB per second.
32 |
33 | ##256 bytes 100M Messages
34 |
35 | Producer:
36 |
37 | ./dist/Release/GNU-MacOSX/lightq producer 100000000 256 event
38 | Total Messages:100000000, Time Taken:99.4206 seconds.
39 | Start Time: 1427672381712, End Time:1427672481133
40 | 1005827 messages per seconds.
41 | 25600000000 bytes sent
42 | 245.5634 MB per second.
43 |
44 | Consumer:
45 |
46 | ./dist/Release/GNU-MacOSX/lightq consumer queue zmq pull event
47 | Total Messages:100000001, Time Taken:99.4544 seconds.
48 | Start Time: 1427672381723, End Time:1427672481178
49 | 1005486 messages per seconds.
50 | 25600000004 bytes received
51 | 245.4800 MB per second.
52 |
53 | ## 512 bytes 100M Messages
54 |
55 | Producer:
56 |
57 | ./dist/Release/GNU-MacOSX/lightq producer 100000000 512 event
58 | Total Messages:100000000, Time Taken:103.17 seconds.
59 | Start Time: 1427672549030, End Time:1427672652200
60 | 969269 messages per seconds.
61 | 51200000000 bytes sent
62 | 473.2762 MB per second.
63 |
64 | Consumer:
65 |
66 | ./dist/Release/GNU-MacOSX/lightq consumer queue zmq pull event
67 | Total Messages:100000001, Time Taken:103.184 seconds.
68 | Start Time: 1427672549040, End Time:1427672652224
69 | 969144 messages per seconds.
70 | 51200000004 bytes received
71 | 473.2149 MB per second.
72 |
73 |
74 | ## 1024 bytes 100M Messages
75 |
76 | Producer:
77 |
78 | ./dist/Release/GNU-MacOSX/lightq producer 100000000 1024 event
79 | Total Messages:100000000, Time Taken:219.452 seconds.
80 | Start Time: 1427672739376, End Time:1427672958828
81 | 455680 messages per seconds.
82 | 102400000000 bytes sent
83 | 445.0001 MB per second.
84 |
85 | Consumer:
86 |
87 | ./dist/Release/GNU-MacOSX/lightq consumer queue zmq pull event
88 | Total Messages:100000001, Time Taken:219.451 seconds.
89 | Start Time: 1427672739386, End Time:1427672958837
90 | 455682 messages per seconds.
91 | 102400000004 bytes received
92 | 445.0020 MB per second.
93 |
94 | #Performance: (Durable broker: file)
95 | ##100 bytes, 100M messages
96 |
97 | Producer:
98 |
99 | ./dist/Release/GNU-MacOSX/lightq producer 100000000 100 event
100 | Total Messages:100000000, Time Taken:291.86 seconds.
101 | Start Time: 1427891740258, End Time:1427892032117
102 | 342630 messages per seconds.
103 | 10000000000 bytes sent
104 | 32.6758 MB per second.
105 |
106 | Consumer:
107 |
108 | ./dist/Release/GNU-MacOSX/lightq consumer file socket pull event
109 | Total Messages:100000001, Time Taken:291.896 seconds.
110 | Start Time: 1427891740271, End Time:1427892032167
111 | 342587 messages per seconds.
112 | 10000000004 bytes received
113 | 32.6717 MB per second.
114 |
115 | ##256 bytes 100M Messages
116 |
117 | Producer:
118 |
119 | ./dist/Release/GNU-MacOSX/lightq producer 100000000 256 event
120 | Total Messages:100000000, Time Taken:284.6 seconds.
121 | Start Time: 1427892109361, End Time:1427892393961
122 | 351370 messages per seconds.
123 | 25600000000 bytes sent
124 | 85.7837 MB per second.
125 |
126 | Consumer:
127 |
128 | ./dist/Release/GNU-MacOSX/lightq consumer file socket pull event
129 | Total Messages:100000001, Time Taken:284.619 seconds.
130 | Start Time: 1427892109372, End Time:1427892393991
131 | 351347 messages per seconds.
132 | 25600000004 bytes received
133 | 85.7781 MB per second.
134 |
135 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LightQ
2 | A high performance, brokered messaging queue
3 |
4 | [](https://travis-ci.org/LightIO/LightQ)
5 |
6 | It is a high performance, brokered messaging queue which supports transient (1M msg/sec with microseconds latency) and durable (~300K msg/sec with milliseconds latency) queues. Durable queues are similar to Kafka where data are written to the file and consumers consume from the file.
7 |
8 | ###Features:
9 | 1. [High Performance - 1M+ msg/sec](https://github.com/LightIO/LightQ/blob/master/README.md#performance)
10 | 2. [Low Latency - in microseconds](https://github.com/LightIO/LightQ/blob/master/LatencyTests.md)
11 | 3. Transient and durable queue (similar to Kafka where producer writes to the file, consumer reads from the file)
12 | 4. Authentication per topic (userid/password validation)
13 | 5. Header only project (embed within your project)
14 | 6. Consumer in load balancing mode(pipeline): One of the consumer gets a message mostly in round robin)
15 | 7. Consumer as Subscribers (Each consumer gets a copy of a message)
16 | 8. Both subscriber and pipelining mode are supported for a single topic
17 | 9. Multi Producers/Consumers for a single topic
18 | 10. Unlimited* topics per broker
19 | 11. JSON protocol to create topic and join topic (at runtime)
20 | 12. C++11 support/require
21 | 13. Logging support
22 | 14. Dynamic port allocation for topic and consumer/producer bind uri
23 | 15. Apache License
24 | 16. Cluster support (todo)
25 | 17. Client API (todo): C, Go, Java, Rust, Lua, Ruby
26 |
27 |
28 | It is mostly header only project with main.cpp as an example for broker, producer and consumer.
29 |
30 | NOTE: This is an initial version and may not be ready for production use.
31 |
32 |
33 |
34 | ##Protocol:
35 |
36 | ### Create a Topic:
37 |
38 | (Admin userid and password must be passed to create a topic. Also we need to define userid/password per topic which consumer/produder need to pass for authentication)
39 |
40 |
41 | Send a request to the broker
42 | {
43 | "admin_password": "T0p$3cr31",
44 | "admin_user_id": "lightq_admin",
45 | "broker_type": "queue",
46 | "cmd": "create_topic",
47 | "password": "T0p$3cr31",
48 | "topic": "test",
49 | "user_id": "test_admin"
50 | }
51 |
52 |
53 | Response:
54 | {
55 | "cmd": "create_topic",
56 | "description": "topic created successfully",
57 | "status": "ok"
58 | }
59 |
60 |
61 | ###Join Topic (Consumer):
62 | (Need to pass userid/password for topic 'test')
63 |
64 | Request:
65 | {
66 | "cmd": "join",
67 | "connection_type": "zmq",
68 | "password": "T0p$3cr31",
69 | "topic": "test",
70 | "type": "pull",
71 | "user_id": "test_admin"
72 | }
73 | Response:
74 | {
75 | "bind_uri": "tcp://127.0.0.1:5002",
76 | "cmd": "join",
77 | "status": "ok",
78 | "topic": "test"
79 | }
80 |
81 | ### Join Topic (Producer):
82 | (Need to pass userid/password for topic 'test')
83 |
84 | Request:
85 | {
86 | "cmd": "join",
87 | "connection_type": "zmq",
88 | "password": "T0p$3cr31",
89 | "topic": "test",
90 | "type": "pub",
91 | "user_id": "test_admin"
92 | }
93 | Response:
94 | {
95 | "bind_uri": "tcp://127.0.0.1:5003",
96 | "cmd": "join",
97 | "status": "ok",
98 | "topic": "test"
99 | }
100 | ### Get the statistics about the topic
101 |
102 | Request:
103 | {
104 | "cmd": "stats",
105 | "password": "T0p$3cr31",
106 | "topic": "test",
107 | "user_id": "test_admin"
108 | }
109 | Response:
110 | {
111 | "cmd": "stats",
112 | "messages_received": 9499570,
113 | "messages_sent": 9491554,
114 | "publishers_count": 1,
115 | "queue_size": 8016,
116 | "status": "ok",
117 | "subscribers_count": 1,
118 | "total_bytes_read": 0,
119 | "total_bytes_written": 0
120 | }
121 |
122 | #Performance:
123 |
124 | Laptop hardware:
125 |
126 | MacBook Pro (Retina, 15-inch, Late 2013)
127 | Processor 2.3 GHz Intel Core i7
128 | Memory 16 GB 1600 MHz DDR3
129 |
130 | Broker Type: Transient
131 | ##100 bytes, 10M messages
132 |
133 | Producer:
134 |
135 | ./dist/Release/GNU-MacOSX/lightq producer 10000000 100 event
136 | Total Messages:10000000, Time Taken:8.46577 seconds.
137 | Start Time: 1427658489112, End Time:1427658497577
138 | 1181227 messages per seconds.
139 | 1000000000 bytes sent
140 | 112.6507 MB per second
141 |
142 | Consumer:
143 |
144 | ./dist/Release/GNU-MacOSX/lightq consumer queue zmq pull event
145 | Total Messages:10000001, Time Taken:8.47781 seconds.
146 | Start Time: 1427658489122, End Time:1427658497600
147 | 1179550 messages per seconds.
148 | 1000000004 bytes received
149 | 112.4907 MB per second.
150 |
151 |
152 |
153 | ##256 bytes 10M Messages
154 |
155 | Producer:
156 |
157 | ./dist/Release/GNU-MacOSX/lightq producer 10000000 256 event
158 | Total Messages:10000000, Time Taken:9.2752 seconds.
159 | Start Time: 1427658738559, End Time:1427658747834
160 | 1078143 messages per seconds.
161 | 2560000000 bytes sent
162 | 263.2186 MB per second.
163 |
164 | Consumer:
165 |
166 | ./dist/Release/GNU-MacOSX/lightq consumer queue zmq pull event
167 | Total Messages:10000001, Time Taken:9.30292 seconds.
168 | Start Time: 1427658738562, End Time:1427658747865
169 | 1074931 messages per seconds.
170 | 2560000004 bytes received
171 | 262.4345 MB per second.
172 |
173 |
174 | ## 512 bytes 10M Messages
175 |
176 | Producer:
177 |
178 | ./dist/Release/GNU-MacOSX/lightq producer 10000000 512 event
179 | Total Messages:10000000, Time Taken:10.5182 seconds.
180 | Start Time: 1427658940094, End Time:1427658950612
181 | 950734 messages per seconds.
182 | 5120000000 bytes sent
183 | 464.2258 MB per second.
184 |
185 | Consumer:
186 |
187 | ./dist/Release/GNU-MacOSX/lightq consumer queue zmq pull event
188 | Total Messages:10000001, Time Taken:10.5296 seconds.
189 | Start Time: 1427658940097, End Time:1427658950627
190 | 949706 messages per seconds.
191 | 5120000004 bytes received
192 | 463.7239 MB per second.
193 |
194 |
195 |
196 | ## 1024 bytes 10M Messages
197 |
198 | Producer:
199 |
200 | ./dist/Release/GNU-MacOSX/lightq producer 10000000 1024 event
201 | Total Messages:10000000, Time Taken:19.8285 seconds.
202 | Start Time: 1427659063592, End Time:1427659083420
203 | 504324 messages per seconds.
204 | 10240000000 bytes sent
205 | 492.5049 MB per second.
206 |
207 | Consumer:
208 |
209 | ./dist/Release/GNU-MacOSX/lightq consumer queue zmq pull event
210 | Total Messages:10000001, Time Taken:19.8222 seconds.
211 | Start Time: 1427659063603, End Time:1427659083425
212 | 504485 messages per seconds.
213 | 10240000004 bytes received
214 | 492.6617 MB per second.
215 |
216 |
217 |
218 | #Performance: (Durable broker: file)
219 | ##100 bytes, 10M messages
220 |
221 | Producer:
222 |
223 | ./dist/Release/GNU-MacOSX/lightq producer 10000000 100 event
224 | Total Messages:10000000, Time Taken:25.0786 seconds.
225 | Start Time: 1427659575158, End Time:1427659600236
226 | 398746 messages per seconds.
227 | 1000000000 bytes sent
228 | 38.0275 MB per second.
229 |
230 | Consumer:
231 |
232 | ./dist/Release/GNU-MacOSX/lightq consumer file socket pull event
233 | Total Messages:10000001, Time Taken:25.0945 seconds.
234 | Start Time: 1427659575170, End Time:1427659600264
235 | 398493 messages per seconds.
236 | 1000000004 bytes received
237 | 38.0033 MB per second.
238 |
239 | ##256 bytes 10M Messages
240 |
241 | Producer:
242 |
243 | ./dist/Release/GNU-MacOSX/lightq producer 10000000 256 event
244 | Total Messages:10000000, Time Taken:28.3802 seconds.
245 | Start Time: 1427659339399, End Time:1427659367779
246 | 352358 messages per seconds.
247 | 2560000000 bytes sent
248 | 86.0250 MB per second.
249 |
250 | Consumer:
251 |
252 | ./dist/Release/GNU-MacOSX/lightq consumer file socket pull event
253 | Total Messages:10000001, Time Taken:28.3939 seconds.
254 | Start Time: 1427659339410, End Time:1427659367804
255 | 352188 messages per seconds.
256 | 2560000004 bytes received
257 | 85.9834 MB per second.
258 |
259 | ## 512 bytes 10M Messages
260 |
261 | Producer:
262 |
263 | ./dist/Release/GNU-MacOSX/lightq producer 10000000 512 event
264 | Total Messages:10000000, Time Taken:31.0832 seconds.
265 | Start Time: 1427890737326, End Time:1427890768409
266 | 321716 messages per seconds.
267 | 5120000000 bytes sent
268 | 157.0884 MB per second.
269 |
270 | Consumer:
271 |
272 | ./dist/Release/GNU-MacOSX/lightq consumer file socket pull event
273 | Total Messages:10000001, Time Taken:31.0935 seconds.
274 | Start Time: 1427890737329, End Time:1427890768423
275 | 321610 messages per seconds.
276 | 5120000004 bytes received
277 | 157.0363 MB per second.
278 |
279 | ## 1024 bytes 10M Messages
280 |
281 | Producer:
282 |
283 | ./dist/Release/GNU-MacOSX/lightq producer 10000000 1024 event
284 | Total Messages:10000000, Time Taken:37.4027 seconds.
285 | Start Time: 1427890878446, End Time:1427890915848
286 | 267360 messages per seconds.
287 | 10240000000 bytes sent
288 | 261.0942 MB per second.
289 |
290 | Consumer:
291 |
292 | ./dist/Release/GNU-MacOSX/lightq consumer file socket pull event
293 | Total Messages:10000001, Time Taken:37.4166 seconds.
294 | Start Time: 1427890878455, End Time:1427890915871
295 | 267260 messages per seconds.
296 | 10240000004 bytes received
297 | 260.9970 MB per second.
298 |
299 | Performance Test with 100M messages: https://github.com/rohitjoshi/LightQ/blob/master/PerfTest100M.md
300 | ###Example: (transient broker)
301 |
302 | Start Broker: (broker type: queue, logging level: event)
303 |
304 | ./dist/Release/GNU-MacOSX/lightq queue event
305 |
306 | Start Consumer: (client: consumer, broker type: queue, client socket: zmq, logging level: event)
307 |
308 | ./dist/Release/GNU-MacOSX/lightq consumer queue zmq pull event
309 |
310 | Start Producer: (client: producer, number of messages 10M, payload size: 100 bytes, logging level: event)
311 |
312 | ./dist/Release/GNU-MacOSX/lightq producer 10000000 100 event
313 |
314 |
315 | ##License : [](LICENSE-Apache)
316 |
317 |
318 | Dependecies:
319 | ZeroMQ LGPL: [](http://zeromq.org/area:licensing)
320 |
321 |
322 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 |
2 | # TODO: not in priority order
3 | - [X] Travis build support
4 | - [ ] Replace ZMQ based admin interface with TCP Socket
5 | - [X] Replace Netbeans build with CMake
6 | - [X] C API for producer, consumer and broker
7 | - [X] Linux Support
8 | - [ ] Fetch for durable queues (similar to Kafka)
9 | - [ ] Kafka client support
10 | - [ ] HTTP/2 protocol support for producer/consumer
11 | - [ ] Cluster Support
12 | - [ ] SSL/TLS support
13 | - [ ] Configurable max message size
14 | - [ ] Add ability to reload config on signal
15 | - [ ] Mac Brew support
16 | -
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | ##Compile Examples.
2 | It will create broker, consumer and producer under ./bin directory.
3 | Run each program with -h option to see optional commandline parameters.
4 |
5 | mkdir build
6 | cd build
7 | cmake ..
8 | make install
9 | cd ../bin
10 |
11 | ## Run examples
12 |
13 | ### Start Broker : Run in a separate terminal
14 | ./bin/lightq-broker
15 | process_name[./lightq-broker], [-u admin_userid[lightq_admin]] [-p admin_password[T0p$3cr31]] [-i bind_ip[*]] [-b bind_port[5500]] [-t transport[tcp]] [-l loglevel[event]]
16 |
17 | ### Create a topic
18 | ./bin/lightq-topic
19 | topic[test] admin_userid[lightq_admin] admin_password[T0p$3cr31] bind_uri[tcp://127.0.0.1:5500] userid[test_admin] password[T0p$3cr31] storage[queue] num_partitions[1] loglevel[event]
20 | initiaze logging
21 | creating topic test_1
22 | topic test created successfully
23 |
24 | ### Start Consumer (Receive 10M messages)
25 | ./bin/lightq-consumer -m 10000000
26 | [./lightq-consumer] [-t topic[test]] [-u userid[test_admin]] [-p password[T0p$3cr31]] [-b broker_uri[tcp://127.0.0.1:5500]] [-c consumer_type[zmq]] [-m messages_to_receive[10000000]] [-n num_partitions[1]] [-l loglevel[event]]
27 | Log initialized successfully for process[./lightq-consumer]
28 | Consumer last message received consumer endtime[44741594]
29 | topic[test_1], Total message received [10000000] in [7.00]sec
30 | topic[test_1],Average messages received per second [1428571.38]
31 | topic[test_1],Average bandwidth received per second [136.2392]MB
32 | First message producer start time[44733954]
33 | Consumer first message start time[44733957]
34 | Consumer first message latency[3]ms
35 | topic[test_1], consumer end to producer start time[7640]
36 | topic[test_1], Average latency[764.00]nano sec
37 |
38 | ### Start Producer (Send 10M messages, size 100)
39 | ./bin/lightq-producer -m 10000000 -s 100
40 | [./lightq-producer] [-t topic[test]] [-u userid[test_admin]] [-p password[T0p$3cr31]] [-b broker_uri[tcp://127.0.0.1:5500]] [-s message_size[100]] [-m messages_to_send[10000000]] [-n num_partitions[1]] [-l loglevel[event]]
41 | Sending message [N2qmWqBlQ9wQj99nsQzldVI5ZuGXbEWRK5RhRXdCdG5nG5azdNMK66MuCV6GXi5xr84P2R391UXaLHbavJvFZGfO47XWS2qVOw5l]
42 | First message start time[44733954l]
43 | Topic[test_1], Total message sent [10000000] in [7.00]sec
44 | Topic[test_1], Average messages sent per second [1428571.38]
45 | Topic[test_1], Average bandwidth sent per second [136.2392]MB
46 |
47 |
--------------------------------------------------------------------------------
/examples/include/lightq_api.h:
--------------------------------------------------------------------------------
1 | /*
2 | * File: lightq_api.h
3 | * Author: Rohit Joshi
4 | *
5 | * Created on April 2, 2015, 8:16 PM
6 | */
7 |
8 | #ifndef LIGHTQ_API_H
9 | #define LIGHTQ_API_H
10 |
11 | #include
12 |
13 | #ifdef __cplusplus
14 | extern "C" {
15 | #endif
16 |
17 | #ifdef __cplusplus
18 | /* in case the compiler is a C++ compiler */
19 | #define DEFAULT_VALUE(value) = value
20 | #else
21 | /* otherwise, C compiler, do nothing */
22 | #define DEFAULT_VALUE(value)
23 | #define true 1
24 | #define false 0
25 | typedef int bool;
26 | #endif
27 | /**
28 | Log Level
29 | */
30 | typedef enum {
31 |
32 | LOG_TRACE = 0,
33 | LOG_DEBUG = 1,
34 | LOG_INFO = 2,
35 | LOG_EVENT = 3,
36 | LOG_WARNING = 4,
37 | LOG_ERROR = 5,
38 | LOG_CRITICAL = 6,
39 | LOG_ALERT = 7,
40 | LOG_EMERG = 8,
41 | LOG_OFF = 9
42 | }lightq_loglevel;
43 |
44 | typedef enum {
45 | queue_type,
46 | file_type,
47 | direct_type,
48 | queue_file_type
49 | }broker_storage_type;
50 |
51 | /**
52 | * Topic statistics
53 | */
54 | typedef struct {
55 | char status[128];
56 | char topic[256];
57 | char topic_type[256];
58 | uint64_t queue_size;
59 | uint64_t messages_sent;
60 | uint64_t messages_received;
61 | uint64_t publishers_count;
62 | uint64_t subscribers_count;
63 | uint64_t total_bytes_written;
64 | uint64_t total_bytes_read;
65 | }topic_stats;
66 |
67 |
68 | /**
69 | * LightQ connection handle
70 | */
71 | typedef struct {
72 | void *client_conn;
73 | void *admin_conn;
74 | char topic[256];
75 | char userid[128];
76 | char password[128];
77 | char broker_uri[256];
78 | uint64_t message_counter;
79 | uint64_t payload_size_counter;
80 |
81 | }lightq_conn;
82 |
83 | typedef struct {
84 | lightq_conn *conn;
85 | uint64_t last_queue_size; //only used for determining if queue depth increasing
86 | char topic_type[256];
87 | bool delay_pub_on_slow_consumer;
88 |
89 | void (*pubDelayAlgorithm)(void *);
90 | }lightq_producer_conn;
91 |
92 | /**
93 | * consumer_socket_type
94 | */
95 | typedef enum {
96 | zmq_consumer,
97 | socket_consumer
98 | }consumer_socket_type;
99 |
100 | //consumer connection
101 | typedef struct {
102 | lightq_conn *p_lightq_conn;
103 | consumer_socket_type socket_type;
104 | }lightq_consumer_conn;
105 |
106 |
107 | /**
108 | * Broker manager
109 | */
110 | typedef struct {
111 | void *broker;
112 | char broker_uri[256];
113 | }lightq_broker_mgr;
114 |
115 |
116 | /**
117 | * initialize log
118 | * @param level
119 | * @return
120 | */
121 | bool init_log(const char *process_name, lightq_loglevel level DEFAULT_VALUE(lightq_loglevel::LOG_EVENT));
122 |
123 | /**
124 | * set log level
125 | * @param level
126 | */
127 | bool set_loglevel(lightq_loglevel level);
128 |
129 | lightq_producer_conn *init_producer(
130 | const char *userid, const char *password, const char *topic,
131 | const char *broker_uri);
132 |
133 | /**
134 | * Free producer connection
135 | * @param producer_conn
136 | */
137 | void free_producer_conn(lightq_producer_conn *producer_conn);
138 | /**
139 | * Initialize producer
140 | * @param topic
141 | * @param broker_uri
142 | * @param pubdelay_on_slow_consumer
143 | * @return
144 | */
145 | int publish_message(lightq_producer_conn *conn, const char *message, uint32_t message_length);
146 |
147 | /**
148 | * Initialize consumer
149 | * @param topic
150 | * @param broker_uri
151 | * @return
152 | */
153 | lightq_consumer_conn *init_consumer(
154 | const char *userid, const char *password, const char *topic, const char *broker_uri,
155 | consumer_socket_type type DEFAULT_VALUE(consumer_socket_type::zmq_consumer));
156 |
157 | /**
158 | * free consumer connection
159 | * @param consumer_conn
160 | */
161 | void free_consumer_conn(lightq_consumer_conn *consumer_conn);
162 | /**
163 | * Receive message - consumer
164 | * @param conn
165 | * @param buffer
166 | * @param buffer_length
167 | * @return
168 | */
169 | int receive_message(lightq_consumer_conn *p_consumer_conn, char *buffer, uint32_t buffer_length);
170 | /**
171 | * Get stats
172 | * @param conn
173 | * @return
174 | */
175 | bool get_stats(lightq_conn *conn, topic_stats *stats);
176 |
177 | /**
178 | * publish delay algorithm function: default implementation
179 | * @param
180 | */
181 | void publish_delay_algorithm(void *);
182 |
183 |
184 | /**
185 | * init_broker
186 | * @param admin_userid
187 | * @param admin_password
188 | * @param transport
189 | * @param bind_ip
190 | * @param bind_port
191 | * @return
192 | */
193 | lightq_broker_mgr *init_broker(
194 | const char *admin_userid, const char *admin_password, const char *transport,
195 | const char *bind_ip, unsigned bind_port);
196 |
197 | /**
198 | * Free broker manager
199 | * @param broker_mgr
200 | */
201 | void free_broker_mgr(lightq_broker_mgr *broker_mgr);
202 | /**
203 | * Run broker. This is a blocking call if block is enabled
204 | * @param broker
205 | * @param block using it's own thread
206 | * @return
207 | */
208 | bool run_broker(lightq_broker_mgr *broker, bool block DEFAULT_VALUE(true));
209 |
210 | /**
211 | * create a topic
212 | * @param broker_uri
213 | * @param topic
214 | * @param admin_userid
215 | * @param admin_password
216 | * @param userid
217 | * @param password
218 | * @param storage_type
219 | * @return
220 | */
221 | bool create_topic(
222 | const char *broker_uri, const char *topic, const char *admin_userid, const char *admin_password,
223 | const char *userid, const char *password, broker_storage_type storage_type);
224 |
225 |
226 | /**
227 | * str to log level
228 | * @param log_level
229 | * @return
230 | */
231 | lightq_loglevel str_to_loglevel(const char *log_level);
232 |
233 |
234 | /**
235 | * get current time in mill second
236 | * @return
237 | */
238 | unsigned long get_current_time_millsec();
239 |
240 | /**
241 | * generate random string for a given size. make sure you pass preallocated buffer size+1 (for null termination)
242 | * @param buffer
243 | * @param size
244 | */
245 | void generate_random_string(char *buffer, unsigned size);
246 |
247 |
248 | /**
249 | * sleep in mill second
250 | * @param
251 | */
252 | void sleep_ms(unsigned);
253 |
254 |
255 | #ifdef __cplusplus
256 | }
257 | #endif
258 |
259 | #endif /* LIGHTQ_API_H */
260 |
261 |
--------------------------------------------------------------------------------
/examples/lib/liblightq.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LightIO/LightQ/2b6cb7b6b57937ea7c98aa6f75a58927accd6597/examples/lib/liblightq.dylib
--------------------------------------------------------------------------------
/examples/lightq-broker.c:
--------------------------------------------------------------------------------
1 | /*
2 | * File: main.c
3 | * Author: Rohit Joshi
4 | *
5 | * Created on April 2, 2015, 9:46 PM
6 | */
7 |
8 | #include
9 | #include
10 | #include
11 | #ifndef __APPLE__
12 | #include
13 | #endif
14 | #include
15 | #include
16 | #include "lightq_api.h"
17 |
18 | /*
19 | * start broker
20 | */
21 | int main(int argc, char **argv) {
22 |
23 | int c;
24 | const char *admin_userid = "lightq_admin";
25 | const char *admin_password = "T0p$3cr31";
26 | const char *bind_ip = "*";
27 | unsigned bind_port = 5500;
28 | const char *transport = "tcp";
29 | const char *loglevel = "event";
30 |
31 |
32 | while ((c = getopt(argc, argv, "hu:p:i:b:t:l:")) != -1) {
33 | switch (c) {
34 | case 'h':
35 | printf(
36 | "Usage: [%s] [-u admin_userid[%s]] [-p admin_password[%s]] [-i bind_ip[%s]] [-b bind_port[%d]] [-t transport[%s]] [-l loglevel[event]]\n",
37 | argv[0], admin_userid, admin_password, bind_ip, bind_port, transport);
38 | return 1;
39 | case 'u':
40 | admin_userid = optarg;
41 | break;
42 | case 'p':
43 | admin_password = optarg;
44 | break;
45 | case 'i':
46 | bind_ip = optarg;
47 | break;
48 |
49 | case 'b':
50 | bind_port = atoi(optarg);
51 | if (bind_port == 0) {
52 | printf("Invalid bindport 0\n");
53 | return -1;
54 | }
55 | break;
56 |
57 | case 'l':
58 | loglevel = optarg;
59 | break;
60 |
61 | case 't':
62 | transport = optarg;
63 | if ((strcmp("tcp", transport) != 0) && (strcmp("ipc", transport) != 0) &&
64 | (strcmp("inproc", transport) != 0)) {
65 | printf("Invalid transport %s. Must be one of 'tcp', 'ipc', 'inproc\n", transport);
66 | return -1;
67 | }
68 | break;
69 | case '?':
70 | if (isprint(optopt))
71 | fprintf(stderr, "Unknown option `-%c'.\n", optopt);
72 | else
73 | fprintf(
74 | stderr,
75 | "Unknown option character `\\x%x'.\n",
76 | optopt);
77 | return 1;
78 | default:
79 | break;
80 | }
81 | }
82 |
83 | printf(
84 | "process_name[%s], [-u admin_userid[%s]] [-p admin_password[%s]] [-i bind_ip[%s]] [-b bind_port[%d]] [-t transport[%s]] [-l loglevel[%s]]\n",
85 | argv[0], admin_userid, admin_password, bind_ip, bind_port, transport, loglevel);
86 |
87 | lightq_loglevel level = str_to_loglevel(loglevel);
88 | init_log("logs", argv[0], level);
89 |
90 | lightq_broker_mgr *p_broker = init_broker(admin_userid, admin_password, transport, bind_ip, bind_port);
91 |
92 | if (p_broker) {
93 | run_broker(p_broker, true);
94 | } else {
95 | printf("Failed to initialize broker\n");
96 | }
97 | free_broker_mgr(p_broker);
98 |
99 | return (EXIT_SUCCESS);
100 |
101 | }
102 |
103 |
--------------------------------------------------------------------------------
/examples/lightq-consumer.c:
--------------------------------------------------------------------------------
1 | /*
2 | * File: main.c
3 | * Author: Rohit Joshi
4 | *
5 | * Created on April 2, 2015, 9:46 PM
6 | */
7 |
8 | #include
9 | #include
10 | #include
11 | #ifndef __APPLE__
12 | #include
13 | #endif
14 | #include
15 | #include
16 | #include
17 | #include "lightq_api.h"
18 |
19 | typedef struct {
20 | char userid[256];
21 | char password[256];
22 | char topic[256];
23 | char broker_uri[256];
24 | consumer_socket_type type;
25 | uint64_t messages_to_receive;
26 | lightq_consumer_conn *p_consumer;
27 | }consumer_info;
28 |
29 | /**
30 | * execute consumer in a thread
31 | * @param p_con_info
32 | */
33 | static void execute_consumer(void *p_con_info) {
34 |
35 | unsigned buffer_size = 1024 * 1024;
36 | char buffer[buffer_size];
37 | consumer_info *p_info = (consumer_info *) p_con_info;
38 |
39 |
40 | if (p_info->p_consumer) {
41 |
42 | uint64_t total_bytes_received = 0;
43 | unsigned long start_time = 0;
44 | unsigned long end_time = 0;
45 | unsigned long producer_start_time = 0;
46 |
47 | for (uint64_t i = 0; i < p_info->messages_to_receive; ++i) {
48 | strcpy(buffer, "");
49 | int bytes_received = receive_message(p_info->p_consumer, buffer, buffer_size);
50 | if (bytes_received > 0) {
51 | total_bytes_received += bytes_received;
52 | } else {
53 | printf("Failed to received message. index [%llu]\n", i);
54 | }
55 | if (i == 0) {
56 | start_time = get_current_time_millsec();
57 | buffer[bytes_received] = '\0';
58 | producer_start_time = strtoul(buffer, NULL, 10);
59 | printf(
60 | "Topic[%s], First message: producer start time [%lu], consumer start time [%lu] \n",
61 | p_info->topic, producer_start_time, start_time);
62 |
63 |
64 | }
65 | }
66 |
67 | end_time = get_current_time_millsec();
68 |
69 | unsigned total_time_ms = end_time - start_time;
70 | float total_time_sec = total_time_ms / 1000;
71 | printf(
72 | "Topic[%s], Total message received [%llu] in [%.2f]sec\n", p_info->topic, p_info->messages_to_receive,
73 | total_time_sec);
74 | printf(
75 | "Topic[%s], Average messages received per second [%.2f]\n", p_info->topic,
76 | p_info->messages_to_receive / total_time_sec);
77 | printf(
78 | "Topic[%s], Total bytes received [%llu], average bandwidth received per second [%.4f]MB\n",
79 | p_info->topic, total_bytes_received, total_bytes_received / (1024 * 1024 * total_time_sec));
80 | printf("Topic[%s], Last Message: consumer endtime [%lu]\n", p_info->topic, end_time);
81 | printf("Topic[%s], Consumer first message latency [%lu] ms\n", p_info->topic, start_time - producer_start_time);
82 | unsigned long consumer_end_to_producer_start_time = end_time - producer_start_time;
83 | printf(
84 | "Topic[%s], Consumer last message received - producer first message sent timestamp [%lu]\n",
85 | p_info->topic, consumer_end_to_producer_start_time);
86 | printf(
87 | "Topic[%s], Average latency [%.2f] nano sec\n", p_info->topic,
88 | (double) ((consumer_end_to_producer_start_time * 1000000 / p_info->messages_to_receive)));
89 |
90 | } else {
91 | printf("Failed to initialize consumer\n");
92 | }
93 |
94 | }
95 |
96 | /*
97 | * start producer
98 | */
99 | int main(int argc, char **argv) {
100 |
101 | int c;
102 | const char *userid = "test_admin";
103 | const char *password = "T0p$3cr31";
104 | const char *broker_uri = "tcp://127.0.0.1:5500";
105 | const char *loglevel = "event";
106 | const char *topic = "test";
107 | const char *consumer_type = "zmq";
108 | uint64_t messages_to_receive = 1000000;
109 | unsigned num_partitions = 1;
110 |
111 | while ((c = getopt(argc, argv, "ht:u:p:b:c:m:n:l:")) != -1) {
112 |
113 | switch (c) {
114 | case 'h':
115 | printf(
116 | "Usage: [%s] [-t topic[%s]] [-u userid[%s]] [-p password[%s]] [-b broker_uri[%s]] [-c consumer_type[%s]] [-m messages_to_receive[%llu]] [-n num_partitions[%u]] [-l loglevel[event]]\n",
117 | argv[0], topic, userid, password, broker_uri, consumer_type, messages_to_receive,
118 | num_partitions);
119 | return 0;
120 | case 't':
121 | topic = optarg;
122 | printf("%c %s\n", c, topic);
123 | break;
124 | case 'u':
125 | userid = optarg;
126 | break;
127 | case 'p':
128 | password = optarg;
129 | break;
130 | case 'b':
131 | broker_uri = optarg;
132 | break;
133 | case 'c':
134 | consumer_type = optarg;
135 | break;
136 | case 'm':
137 | messages_to_receive = strtoull(optarg, NULL, 10);
138 | break;
139 | case 'n':
140 | num_partitions = atoi(optarg);
141 | break;
142 | case 'l':
143 | loglevel = optarg;
144 | break;
145 | case '?':
146 | if (isprint(optopt))
147 | fprintf(stderr, "Unknown option `-%c'.\n", optopt);
148 | else
149 | fprintf(
150 | stderr,
151 | "Unknown option character `\\x%x'.\n",
152 | optopt);
153 | return 1;
154 | default:
155 | break;
156 | }
157 | }
158 |
159 |
160 | printf(
161 | " [%s] [-t topic[%s]] [-u userid[%s]] [-p password[%s]] [-b broker_uri[%s]] "
162 | "[-c consumer_type[%s]] [-m messages_to_receive[%llu]] [-n num_partitions[%u]] [-l loglevel[%s]]\n",
163 | argv[0], topic, userid, password, broker_uri,
164 | consumer_type, messages_to_receive, num_partitions, loglevel);
165 |
166 | lightq_loglevel level = str_to_loglevel(loglevel);
167 | if (!init_log("logs", argv[0], level)) {
168 | printf("Failed to initialize logging\n");
169 | return -1;
170 | } else {
171 | printf("Log initialized successfully for process[%s]\n", argv[0]);
172 | }
173 |
174 | consumer_socket_type type = zmq_consumer;
175 | if (!strcmp(consumer_type, "socket")) {
176 | type = socket_consumer;
177 | printf("Using consumer socket as tcp socket\n");
178 | }//
179 |
180 |
181 | pthread_t tid[10];
182 | consumer_info coninfo[10];
183 | char topic_buffer[256];
184 | for (unsigned i = 0; i < num_partitions; ++i) {
185 | strcpy(topic_buffer, "");
186 | sprintf(topic_buffer, "%s_%u", topic, i + 1);
187 | strcpy(coninfo[i].userid, userid);
188 | strcpy(coninfo[i].password, password);
189 | strcpy(coninfo[i].topic, topic_buffer);
190 | strcpy(coninfo[i].broker_uri, broker_uri);
191 | coninfo[i].type = type;
192 | coninfo[i].messages_to_receive = messages_to_receive;
193 | coninfo[i].p_consumer = init_consumer(userid, password, topic_buffer, broker_uri, type);
194 |
195 | }
196 |
197 |
198 | for (unsigned i = 0; i < num_partitions; ++i) {
199 | // execute_consumer(coninfo[i]);
200 | int err = pthread_create(&(tid[i]), NULL, (void *) &execute_consumer, (void *) &coninfo[i]);
201 | if (err != 0)
202 | printf("\ncan't create thread :[%s]", strerror(err));
203 | //else
204 | // printf("\n Thread created successfully\n");
205 | }
206 |
207 | for (unsigned i = 0; i < num_partitions; ++i) {
208 | // printf("Waiting for joininh thread\n");
209 | pthread_join(tid[i], NULL);
210 | }
211 | for (unsigned i = 0; i < num_partitions; ++i) {
212 | free_consumer_conn(coninfo[i].p_consumer);
213 | }
214 |
215 |
216 | return (EXIT_SUCCESS);
217 | }
218 |
219 |
--------------------------------------------------------------------------------
/examples/lightq-producer.c:
--------------------------------------------------------------------------------
1 | /*
2 | * File: main.c
3 | * Author: Rohit Joshi
4 | *
5 | * Created on April 2, 2015, 9:46 PM
6 | */
7 |
8 | #include
9 | #include
10 | #include
11 | #ifndef __APPLE__
12 | #include
13 | #endif
14 | #include
15 | #include
16 | #include
17 | #include "lightq_api.h"
18 |
19 | typedef struct {
20 | char userid[256];
21 | char password[256];
22 | char topic[256];
23 | char broker_uri[256];
24 | unsigned message_size;
25 | uint64_t messages_to_send;
26 | lightq_producer_conn *p_producer;
27 | }publisher_info;
28 |
29 | static void execute_publisher(void *p_pub) {
30 | publisher_info *pub = (publisher_info *) p_pub;
31 |
32 |
33 | char buffer[pub->message_size + 1];
34 |
35 | if (pub->p_producer) {
36 | uint64_t total_bytes_sent = 0;
37 | unsigned long start_time = 0;
38 | unsigned long end_time = 0;
39 | int bytes_sent = 0;
40 |
41 | generate_random_string(buffer, pub->message_size);
42 | printf("Sending message [%s]\n", buffer);
43 | start_time = get_current_time_millsec();
44 | for (uint64_t i = 0; i < pub->messages_to_send; ++i) {
45 | if (i == 0) {
46 | sprintf(buffer, "%lu", start_time);
47 | bytes_sent = publish_message(pub->p_producer, buffer, strlen(buffer));
48 | printf("Topic[%s], Producer: first message sent timestamp [%lu]\n", pub->topic, start_time);
49 | } else {
50 | bytes_sent = publish_message(pub->p_producer, buffer, pub->message_size);
51 | }
52 |
53 | if (bytes_sent > 0) {
54 | total_bytes_sent += bytes_sent;
55 | } else {
56 | printf("Failed to send message. index [%llu]\n", i);
57 | }
58 | }
59 |
60 | end_time = get_current_time_millsec();
61 | printf("Topic[%s], Producer: last message sent timestamp [%lu]\n", pub->topic, end_time);
62 | unsigned total_time_ms = end_time - start_time;
63 | float total_time_sec = total_time_ms / 1000;
64 |
65 | printf(
66 | "Topic[%s], Total message sent [%llu] in [%.2f] sec\n", pub->topic, pub->messages_to_send,
67 | total_time_sec);
68 | printf(
69 | "Topic[%s], Average messages sent per second [%.2f]\n", pub->topic,
70 | pub->messages_to_send / total_time_sec);
71 | printf(
72 | "Topic[%s], Average bandwidth sent per second [%.4f] MB\n", pub->topic,
73 | total_bytes_sent / (1024 * 1024 * total_time_sec));
74 |
75 | }
76 | }
77 |
78 | /*
79 | * start producer
80 | */
81 | int main(int argc, char **argv) {
82 |
83 | int c;
84 | const char *userid = "test_admin";
85 | const char *password = "T0p$3cr31";
86 | const char *broker_uri = "tcp://127.0.0.1:5500";
87 | const char *loglevel = "event";
88 | const char *topic = "test";
89 | uint32_t message_size = 100;
90 | uint64_t messages_to_send = 1000000;
91 | unsigned num_partitions = 1;
92 |
93 | while ((c = getopt(argc, argv, "ht:u:p:b:m:s:n:l:")) != -1)
94 |
95 | switch (c) {
96 | case 'h':
97 | printf(
98 | "Usage: [%s] [-t topic[%s]] [-u userid[%s]] [-p password[%s]] [-b broker_uri[%s]] [-s message_size[%u]] [-m messages_to_send[%llu]] [-n num_partitions[%u]] [-l loglevel[event]]\n",
99 | argv[0], topic, userid, password, broker_uri, message_size, messages_to_send, num_partitions);
100 | return 0;
101 | case 't':
102 | topic = optarg;
103 | printf("%c %s\n", c, topic);
104 | break;
105 | case 'u':
106 | userid = optarg;
107 | break;
108 | case 'p':
109 | password = optarg;
110 | break;
111 | case 'b':
112 | broker_uri = optarg;
113 | break;
114 | case 'm':
115 | messages_to_send = strtoull(optarg, NULL, 10);
116 | break;
117 | case 's':
118 | message_size = atoi(optarg);
119 | break;
120 | case 'n':
121 | num_partitions = atoi(optarg);
122 | break;
123 | case 'l':
124 | loglevel = optarg;
125 | break;
126 | case '?':
127 | if (isprint(optopt))
128 | fprintf(stderr, "Unknown option `-%c'.\n", optopt);
129 | else
130 | fprintf(
131 | stderr,
132 | "Unknown option character `\\x%x'.\n",
133 | optopt);
134 | return 1;
135 | default:
136 | break;
137 | }
138 |
139 |
140 | if (topic == NULL) {
141 | printf(
142 | "Usage: [%s] -t topic [-u userid[%s]] [-p password[%s]] [-b broker_uri[%s]] [-m message_size[%u]] [-s messages_to_send[%llu]] [-n num_partitions[%u]] [-l loglevel[event]]\n",
143 | argv[0], userid, password, broker_uri, message_size, messages_to_send, num_partitions);
144 | return 0;
145 | }
146 |
147 | printf(
148 | " [%s] [-t topic[%s]] [-u userid[%s]] [-p password[%s]] [-b broker_uri[%s]] [-s message_size[%u]] [-m messages_to_send[%llu]] [-n num_partitions[%u]] [-l loglevel[%s]]\n",
149 | argv[0], topic, userid, password, broker_uri, message_size, messages_to_send, num_partitions, loglevel);
150 |
151 |
152 | lightq_loglevel level = str_to_loglevel(loglevel);
153 | if (!init_log("logs", argv[0], level)) {
154 | printf("Failed to initialize logging");
155 | return -1;
156 | }
157 |
158 | pthread_t tid[10];
159 | publisher_info pubs[10];
160 | for (unsigned i = 0; i < num_partitions; ++i) {
161 | char topic_buffer[256];
162 | topic_buffer[0] = '\0';
163 | sprintf(topic_buffer, "%s_%u", topic, i + 1);
164 | strcpy(pubs[i].userid, userid);
165 | strcpy(pubs[i].password, password);
166 | strcpy(pubs[i].topic, topic_buffer);
167 | strcpy(pubs[i].broker_uri, broker_uri);
168 | pubs[i].message_size = message_size;
169 | pubs[i].messages_to_send = messages_to_send;
170 | pubs[i].p_producer = init_producer(userid, password, topic_buffer, broker_uri);
171 |
172 | }
173 | sleep(3);
174 | for (unsigned i = 0; i < num_partitions; ++i) {
175 | int err = pthread_create(&(tid[i]), NULL, (void *) &execute_publisher, (void *) &pubs[i]);
176 | if (err != 0)
177 | printf("\ncan't create thread :[%s]", strerror(err));
178 | // else
179 | // printf("\n Thread created successfully\n");
180 | }
181 | for (unsigned i = 0; i < num_partitions; ++i) {
182 | pthread_join(tid[i], NULL);
183 | }
184 | sleep(5);
185 | for (unsigned i = 0; i < num_partitions; ++i) {
186 | free_producer_conn(pubs[i].p_producer);
187 | }
188 |
189 | return (EXIT_SUCCESS);
190 | }
191 |
192 |
--------------------------------------------------------------------------------
/examples/lightq-topic.c:
--------------------------------------------------------------------------------
1 | /*
2 | * File: main.c
3 | * Author: Rohit Joshi
4 | *
5 | * Created on April 4, 2015, 9:07 PM
6 | */
7 | #include
8 | #include
9 | #include
10 | #ifndef __APPLE__
11 | #include
12 | #endif
13 | #include
14 | #include
15 | #include "lightq_api.h"
16 |
17 | /*
18 | *
19 | */
20 | int main(int argc, char **argv) {
21 |
22 | int c;
23 | const char *admin_userid = "lightq_admin";
24 | const char *admin_password = "T0p$3cr31";
25 | const char *userid = "test_admin";
26 | const char *password = "T0p$3cr31";
27 | const char *bind_uri = "tcp://127.0.0.1:5500";
28 | const char *topic = "test";
29 | const char *storage = "queue";
30 |
31 | const char *loglevel = "event";
32 | unsigned num_partitions = 1;
33 |
34 |
35 | while ((c = getopt(argc, argv, "ht:a:d:b:u:p:s:l:n:")) != -1) {
36 | switch (c) {
37 | case 'h':
38 | printf(
39 | "Usage: [%s] [-t topic[%s]] [-a admin_userid[%s]] [-d admin_password[%s]] [-b bind_uri[%s]] [-u userid[%s]] [-p password[%s]] [-s storage[%s]] [-n num_partitions[%u]] [-l loglevel[event]]\n",
40 | argv[0], topic, admin_userid, admin_password, bind_uri, userid, password, storage,
41 | num_partitions);
42 | return 1;
43 |
44 | case 't':
45 | topic = optarg;
46 | break;
47 | case 'a':
48 | admin_userid = optarg;
49 | break;
50 | case 'd':
51 | admin_password = optarg;
52 | break;
53 | case 'b':
54 | bind_uri = optarg;
55 | break;
56 | case 'u':
57 | userid = optarg;
58 | break;
59 | case 'p':
60 | password = optarg;
61 | break;
62 |
63 | case 's':
64 | storage = optarg;
65 | break;
66 |
67 | case 'l':
68 | loglevel = optarg;
69 | break;
70 | case 'n':
71 | num_partitions = atoi(optarg);
72 | break;
73 | case '?':
74 | if (isprint(optopt))
75 | fprintf(stderr, "Unknown option `-%c'.\n", optopt);
76 | else
77 | fprintf(
78 | stderr,
79 | "Unknown option character `\\x%x'.\n",
80 | optopt);
81 | return 1;
82 | default:
83 | break;
84 | }
85 | }
86 |
87 | printf(
88 | "topic[%s] admin_userid[%s] admin_password[%s] bind_uri[%s] userid[%s] password[%s] storage[%s] num_partitions[%u] loglevel[%s]\n",
89 | topic, admin_userid, admin_password, bind_uri, userid, password, storage, num_partitions, loglevel);
90 |
91 | lightq_loglevel level = str_to_loglevel(loglevel);
92 | printf("initiaze logging\n");
93 | init_log("logs", argv[0], level);
94 | broker_storage_type type = queue_type;
95 | if (!strcmp(storage, "file")) {
96 | type = file_type;
97 | }
98 | char topic_buffer[256];
99 | strcpy(topic_buffer, "");
100 |
101 | for (unsigned i = 0; i < num_partitions; ++i) {
102 | sprintf(topic_buffer, "%s_%u", topic, i + 1);
103 | printf("creating topic %s\n", topic_buffer);
104 | if (create_topic(bind_uri, topic_buffer, admin_userid, admin_password, userid, password, type)) {
105 | printf("topic %s created successfully\n", topic);
106 | } else {
107 | printf("Failed to create topic %s\n", topic);
108 | }
109 | }
110 | return (EXIT_SUCCESS);
111 | }
112 |
113 |
--------------------------------------------------------------------------------
/include/broker.h:
--------------------------------------------------------------------------------
1 | /*
2 | * File: broker.h
3 | * Author: Rohit Joshi
4 | *
5 | * Created on February 26, 2015, 8:40 AM
6 | */
7 |
8 | #ifndef BROKER_H
9 | #define BROKER_H
10 |
11 | #include "thirdparty/readerwriterqueue.h"
12 | #include "connection.h"
13 | #include "connection_zmq.h"
14 | #include "connection_file.h"
15 | #include "utils.h"
16 | #include "broker_config.h"
17 | #include "producer.h"
18 | #include "consumer.h"
19 |
20 |
21 | namespace lightq {
22 |
23 | //broker
24 | class broker {
25 | public:
26 |
27 |
28 | /**
29 | * constructor
30 | * @param config
31 | */
32 | broker(broker_config &config) : config_(config), storage_(config) {
33 |
34 | LOG_IN("broker_config: %s", config.to_string().c_str());
35 | stop_ = false;
36 | p_producer_ = NULL;
37 | p_consumer_ = NULL;
38 | LOG_OUT("");
39 | }
40 |
41 | /**
42 | * destructor
43 | */
44 | ~broker() {
45 | LOG_IN("");
46 | delete p_producer_;
47 | delete p_consumer_;
48 | LOG_OUT("");
49 | }
50 |
51 | bool init() {
52 | LOG_IN("");
53 | storage_.init(config_);
54 | LOG_RET_TRUE("success");
55 | }
56 |
57 | bool init_consumer(consumer_config &consumer_config) {
58 | LOG_IN("");
59 | //initialize consumer
60 | p_consumer_ = new consumer(&storage_, consumer_config);
61 | if (!p_consumer_->init()) {
62 | LOG_RET_FALSE("Failed to initialize consumer");
63 | } else {
64 | LOG_DEBUG("Consumer initialized successfully");
65 | }
66 | storage_.set_consumer_socket(p_consumer_->get_consumer_socket());
67 | if (p_consumer_->run()) {
68 | LOG_RET_TRUE("success");
69 | } else {
70 | LOG_RET_FALSE("Failed to run consumer");
71 | }
72 | }
73 |
74 | bool init_producer(producer_config &prod_config) {
75 | LOG_IN("");
76 |
77 | //initialize producer
78 | p_producer_ = new producer(&storage_, prod_config);
79 | if (!p_producer_->init()) {
80 | LOG_RET_FALSE("Failed to initialize producer");
81 | } else {
82 | LOG_DEBUG("Producer initialized successfully");
83 | }
84 | if (p_producer_->run()) {
85 | LOG_RET_TRUE("success");
86 | } else {
87 | LOG_RET_FALSE("Failed to run producer");
88 | }
89 | }
90 |
91 |
92 | /**
93 | * Stop the broker
94 | * @return
95 | */
96 | bool stop() {
97 | LOG_IN("");
98 | stop_ = true;
99 | LOG_RET_TRUE("stopped");
100 |
101 | }
102 |
103 | inline uint32_t get_total_msg_sent() {
104 | return storage_.get_total_dequeued_messages();
105 | }
106 |
107 | inline uint32_t get_total_msg_received() {
108 | return storage_.get_total_enqueued_messages();
109 | }
110 |
111 | inline uint64_t get_queue_size() {
112 | return storage_.get_queue_size();
113 | }
114 |
115 | producer *get_producer() {
116 | return p_producer_;
117 | }
118 |
119 | consumer *get_consumer() {
120 | return p_consumer_;
121 | }
122 |
123 | broker_config &get_config() {
124 | return config_;
125 | }
126 |
127 | broker_storage &get_storage() {
128 | return storage_;
129 | }
130 |
131 | private:
132 | broker_config config_;
133 | bool stop_;
134 | broker_storage storage_;
135 | producer *p_producer_;
136 | consumer *p_consumer_;
137 |
138 | };
139 | }
140 |
141 | #endif /* BROKER_H */
142 |
143 |
--------------------------------------------------------------------------------
/include/broker_config.h:
--------------------------------------------------------------------------------
1 | /*
2 | * File: broker_config.h
3 | * Author: Rohit Joshi
4 | *
5 | * Created on February 28, 2015, 10:19 AM
6 | */
7 |
8 | #ifndef BROKER_CONFIG_H
9 | #define BROKER_CONFIG_H
10 |
11 | #include "utils.h"
12 | #include "connection.h"
13 | //#include "broker.h"
14 |
15 |
16 | namespace lightq {
17 |
18 | class connection;
19 |
20 | //class broker_config
21 | struct broker_config {
22 | //broker type
23 | enum broker_type {
24 | broker_queue,
25 | broker_file,
26 | broker_direct,
27 | broker_queue_file
28 | };
29 |
30 | std::string id_;
31 | broker_type broker_type_;
32 | std::string user_id_;
33 | std::string password_;
34 | // producer_config producer_config_;
35 | // consumer_config consumer_config_;
36 | uint32_t default_queue_size_ = 1024 * 1024 * 5;
37 | uint32_t max_message_size = 128 * 1048; // make it configurable
38 | std::string output_directory_ = "/tmp";
39 | std::string bind_interface = "tcp://*";
40 |
41 |
42 | /**
43 | * to string
44 | * @return
45 | */
46 | std::string to_string() {
47 | /*
48 | std::string str = utils::format_str( "id: %s, broker_type: %d, producer_bind_uri: %s, "
49 | "producer_stream_type: %d, consumer_bind_uri: %s, consumer_stream_type: %d, "
50 | "default_queue_size_: %u, max_message_size: %u, output_directory: %s",
51 | id_.c_str(), broker_type_, producer_config_.producer_bind_uri_.c_str(), producer_config_.producer_stream_type_,
52 | consumer_config_.push_bind_uri_.c_str(), consumer_config_.stream_type_ , default_queue_size_, max_message_size,
53 | output_directory_.c_str());
54 |
55 | // std::string str (buffer, strlen(buffer));
56 | LOG_DEBUG("config.to_string(): %s", str.c_str());
57 | return std::move(str);*/
58 | return std::string("uncommment");
59 |
60 | }
61 |
62 | std::string get_broker_type_to_str() {
63 | switch (broker_type_) {
64 | case broker_type::broker_direct :
65 | return "direct";
66 | case broker_type::broker_file :
67 | return "file";
68 | case broker_type::broker_queue_file :
69 | return "queue_file";
70 | default:
71 | case broker_type::broker_queue :
72 | return "queue";
73 | }
74 | return "queue";
75 | }
76 |
77 | /**
78 | * get next port
79 | * @param initial_port
80 | * @return
81 | */
82 | inline static unsigned get_next_port(unsigned initial_port = 5000) {
83 | static unsigned port = initial_port;
84 | return port++;
85 | }
86 | };
87 | }
88 |
89 | #endif /* BROKER_CONFIG_H */
90 |
91 |
--------------------------------------------------------------------------------
/include/connection.h:
--------------------------------------------------------------------------------
1 | /*
2 | * File: connection.h
3 | * Author: Rohit Joshi
4 | *
5 | * Created on February 25, 2015, 8:39 AM
6 | */
7 |
8 | #ifndef CONNECTION_H
9 | #define CONNECTION_H
10 |
11 | #include "log.h"
12 | //#include "connection.h"
13 |
14 | namespace lightq {
15 |
16 | //connection
17 | class connection {
18 | public:
19 |
20 | //stream typr
21 | enum stream_type {
22 | stream_zmq,
23 | stream_nanomsg,
24 | stream_file,
25 | stream_socket
26 | };
27 | //endpoint type
28 | enum endpoint_type {
29 | conn_consumer,
30 | conn_publisher,
31 | conn_broker
32 | };
33 | //socket connect type
34 | enum socket_connect_type {
35 | bind_socket,
36 | connect_socket,
37 | create_file
38 | };
39 |
40 | /**
41 | * destructor
42 | */
43 | virtual ~connection() { }
44 |
45 | protected:
46 | /**
47 | * connection
48 | * @param topic
49 | * @param uri
50 | * @param stype
51 | * @param ep_type
52 | * @param connect_type
53 | */
54 | connection(
55 | const std::string &topic, const std::string &uri, stream_type stype,
56 | endpoint_type ep_type, socket_connect_type connect_type, bool non_blocking = true) {
57 |
58 | LOG_IN("topic[%s], uri[%s], stream_type[%d], endpoint_type[%d], socket_connect_type[%d]",
59 | topic.c_str(), uri.c_str(), stype, ep_type, connect_type);
60 |
61 | topic_ = topic;
62 | resource_uri_ = uri;
63 | stream_type_ = stype;
64 | endpoint_type_ = ep_type;
65 | socket_connect_type_ = connect_type;
66 | non_blocking_ = non_blocking;
67 | }
68 |
69 |
70 | public:
71 | /**
72 | * init
73 | * @return
74 | */
75 | virtual bool init() = 0;
76 |
77 | /**
78 | * run
79 | * @return
80 | */
81 | virtual bool run() = 0;
82 |
83 | /**
84 | * write message
85 | * @param message
86 | * @return
87 | */
88 | virtual ssize_t write_msg(const std::string &message) = 0;
89 |
90 | /**
91 | * write message
92 | * @param message
93 | * @param length
94 | * @return
95 | */
96 | virtual ssize_t write_msg(const char *message, unsigned length) = 0;
97 |
98 |
99 | /**
100 | * read message
101 | * @param message
102 | * @return
103 | */
104 | virtual ssize_t read_msg(std::string &message) = 0;
105 |
106 |
107 | /**
108 | * read message
109 | * @param message
110 | * @return
111 | */
112 |
113 |
114 | virtual ssize_t read_msg(char *buffer, uint32_t buffer_length, bool ntohl = false) = 0;
115 |
116 |
117 | /**
118 | * get stream type
119 | * @return
120 | */
121 | inline stream_type get_stream_type() {
122 | return stream_type_;
123 | }
124 |
125 | /**
126 | * get endpoint type
127 | * @return
128 | */
129 | inline endpoint_type get_endpoint_type() {
130 | return endpoint_type_;
131 | }
132 |
133 | /**
134 | * get topic
135 | * @return
136 | */
137 | inline const std::string &get_topic() const {
138 | return topic_;
139 | }
140 |
141 | inline std::string get_resource_uri_() {
142 | return resource_uri_;
143 | }
144 |
145 | protected:
146 | std::string resource_uri_;
147 | std::string topic_;
148 | stream_type stream_type_;
149 | endpoint_type endpoint_type_;
150 | socket_connect_type socket_connect_type_;
151 | bool non_blocking_;
152 |
153 | };
154 |
155 | }
156 | #endif /* CONNECTION_H */
157 |
158 |
--------------------------------------------------------------------------------
/include/lightq_api.h:
--------------------------------------------------------------------------------
1 | /*
2 | * File: lightq_api.h
3 | * Author: Rohit Joshi
4 | *
5 | * Created on April 2, 2015, 8:16 PM
6 | */
7 |
8 | #ifndef LIGHTQ_API_H
9 | #define LIGHTQ_API_H
10 |
11 | #include
12 |
13 | #ifdef __cplusplus
14 | extern "C" {
15 | #endif
16 |
17 | #ifdef __cplusplus
18 | /* in case the compiler is a C++ compiler */
19 | #define DEFAULT_VALUE(value) = value
20 | #else
21 | /* otherwise, C compiler, do nothing */
22 | #define DEFAULT_VALUE(value)
23 | #define true 1
24 | #define false 0
25 | typedef int bool;
26 | #endif
27 | /**
28 | Log Level
29 | */
30 | typedef enum {
31 |
32 | LOG_TRACE = 0,
33 | LOG_DEBUG = 1,
34 | LOG_INFO = 2,
35 | LOG_EVENT = 3,
36 | LOG_WARNING = 4,
37 | LOG_ERROR = 5,
38 | LOG_CRITICAL = 6,
39 | LOG_ALERT = 7,
40 | LOG_EMERG = 8,
41 | LOG_OFF = 9
42 | }lightq_loglevel;
43 |
44 | typedef enum {
45 | queue_type,
46 | file_type,
47 | direct_type,
48 | queue_file_type
49 | }broker_storage_type;
50 |
51 | /**
52 | * Topic statistics
53 | */
54 | typedef struct {
55 | char status[128];
56 | char topic[256];
57 | char topic_type[256];
58 | uint64_t queue_size;
59 | uint64_t messages_sent;
60 | uint64_t messages_received;
61 | uint64_t publishers_count;
62 | uint64_t subscribers_count;
63 | uint64_t total_bytes_written;
64 | uint64_t total_bytes_read;
65 | }topic_stats;
66 |
67 |
68 | /**
69 | * LightQ connection handle
70 | */
71 | typedef struct {
72 | void *client_conn;
73 | void *admin_conn;
74 | char topic[256];
75 | char userid[128];
76 | char password[128];
77 | char broker_uri[256];
78 | uint64_t message_counter;
79 | uint64_t payload_size_counter;
80 |
81 | }lightq_conn;
82 |
83 | typedef struct {
84 | lightq_conn *conn;
85 | uint64_t last_queue_size; //only used for determining if queue depth increasing
86 | char topic_type[256];
87 | bool delay_pub_on_slow_consumer;
88 |
89 | void (*pubDelayAlgorithm)(void *);
90 | }lightq_producer_conn;
91 |
92 | /**
93 | * consumer_socket_type
94 | */
95 | typedef enum {
96 | zmq_consumer,
97 | socket_consumer
98 | }consumer_socket_type;
99 |
100 | //consumer connection
101 | typedef struct {
102 | lightq_conn *p_lightq_conn;
103 | consumer_socket_type socket_type;
104 | }lightq_consumer_conn;
105 |
106 |
107 | /**
108 | * Broker manager
109 | */
110 | typedef struct {
111 | void *broker;
112 | char broker_uri[256];
113 | }lightq_broker_mgr;
114 |
115 |
116 | /**
117 | * initialize log
118 | * @param level
119 | * @return
120 | */
121 | bool init_log(
122 | const char *logdir, const char *process_name, lightq_loglevel level DEFAULT_VALUE(lightq_loglevel::LOG_EVENT));
123 |
124 | /**
125 | * set log level
126 | * @param level
127 | */
128 | bool set_loglevel(lightq_loglevel level);
129 |
130 | lightq_producer_conn *init_producer(
131 | const char *userid, const char *password, const char *topic,
132 | const char *broker_uri);
133 |
134 | /**
135 | * Free producer connection
136 | * @param producer_conn
137 | */
138 | void free_producer_conn(lightq_producer_conn *producer_conn);
139 | /**
140 | * Initialize producer
141 | * @param topic
142 | * @param broker_uri
143 | * @param pubdelay_on_slow_consumer
144 | * @return
145 | */
146 | int publish_message(lightq_producer_conn *conn, const char *message, uint32_t message_length);
147 |
148 | /**
149 | * Initialize consumer
150 | * @param topic
151 | * @param broker_uri
152 | * @return
153 | */
154 | lightq_consumer_conn *init_consumer(
155 | const char *userid, const char *password, const char *topic, const char *broker_uri,
156 | consumer_socket_type type DEFAULT_VALUE(consumer_socket_type::zmq_consumer));
157 |
158 | /**
159 | * free consumer connection
160 | * @param consumer_conn
161 | */
162 | void free_consumer_conn(lightq_consumer_conn *consumer_conn);
163 | /**
164 | * Receive message - consumer
165 | * @param conn
166 | * @param buffer
167 | * @param buffer_length
168 | * @return
169 | */
170 | int receive_message(lightq_consumer_conn *p_consumer_conn, char *buffer, uint32_t buffer_length);
171 | /**
172 | * Get stats
173 | * @param conn
174 | * @return
175 | */
176 | bool get_stats(lightq_conn *conn, topic_stats *stats);
177 |
178 | /**
179 | * publish delay algorithm function: default implementation
180 | * @param
181 | */
182 | void publish_delay_algorithm(void *);
183 |
184 |
185 | /**
186 | * init_broker
187 | * @param admin_userid
188 | * @param admin_password
189 | * @param transport
190 | * @param bind_ip
191 | * @param bind_port
192 | * @return
193 | */
194 | lightq_broker_mgr *init_broker(
195 | const char *admin_userid, const char *admin_password, const char *transport,
196 | const char *bind_ip, unsigned bind_port);
197 |
198 | /**
199 | * Free broker manager
200 | * @param broker_mgr
201 | */
202 | void free_broker_mgr(lightq_broker_mgr *broker_mgr);
203 | /**
204 | * Run broker. This is a blocking call if block is enabled
205 | * @param broker
206 | * @param block using it's own thread
207 | * @return
208 | */
209 | bool run_broker(lightq_broker_mgr *broker, bool block DEFAULT_VALUE(true));
210 |
211 | /**
212 | * create a topic
213 | * @param broker_uri
214 | * @param topic
215 | * @param admin_userid
216 | * @param admin_password
217 | * @param userid
218 | * @param password
219 | * @param storage_type
220 | * @return
221 | */
222 | bool create_topic(
223 | const char *broker_uri, const char *topic, const char *admin_userid, const char *admin_password,
224 | const char *userid, const char *password, broker_storage_type storage_type);
225 |
226 |
227 | /**
228 | * str to log level
229 | * @param log_level
230 | * @return
231 | */
232 | lightq_loglevel str_to_loglevel(const char *log_level);
233 |
234 |
235 | /**
236 | * get current time in mill second
237 | * @return
238 | */
239 | unsigned long get_current_time_millsec();
240 |
241 | /**
242 | * generate random string for a given size. make sure you pass preallocated buffer size+1 (for null termination)
243 | * @param buffer
244 | * @param size
245 | */
246 | void generate_random_string(char *buffer, unsigned size);
247 |
248 |
249 | /**
250 | * sleep in mill second
251 | * @param
252 | */
253 | void sleep_ms(unsigned);
254 |
255 |
256 | #ifdef __cplusplus
257 | }
258 | #endif
259 |
260 | #endif /* LIGHTQ_API_H */
261 |
262 |
--------------------------------------------------------------------------------
/include/monitor_zmq.h:
--------------------------------------------------------------------------------
1 | /*
2 | * File: monitor_zmq.h
3 | * Author: Rohit Joshi
4 | *
5 | * Created on February 26, 2015, 12:27 PM
6 | */
7 |
8 | #ifndef MONITOR_ZMQ_H
9 | #define MONITOR_ZMQ_H
10 |
11 | #include
12 | #include "thirdparty/readerwriterqueue.h"
13 | #include "thirdparty/zmq.hpp"
14 | #include "log.h"
15 |
16 | namespace lightq {
17 | //monitor event
18 | //monitor event
19 |
20 | class monitor_event {
21 | public:
22 |
23 | /**
24 | * constructor
25 | * @param zmq_event
26 | * @param address
27 | */
28 | explicit monitor_event(const zmq_event_t &zmq_event, const std::string &address) {
29 | event_info_ = zmq_event;
30 | address_ = address;
31 |
32 | }
33 |
34 |
35 | /**
36 | * to string
37 | * @return
38 | */
39 | std::string to_string() {
40 | std::ostringstream ss;
41 | ss << "address: " << address_;
42 | ss << ", event: " << event_info_.event << ", value: " << event_info_.value;
43 | return ss.str();
44 | }
45 |
46 | private:
47 | zmq_event_t event_info_;
48 | std::string address_;
49 |
50 |
51 | };
52 |
53 | //monitor_zmq
54 |
55 | class monitor_zmq : public zmq::monitor_t {
56 | friend class connection_zmq;
57 |
58 | private:
59 |
60 | monitor_zmq() : zmq::monitor_t(), num_clients_(0) {
61 |
62 | }
63 |
64 | virtual ~monitor_zmq() {
65 | LOG_IN("");
66 | LOG_OUT("");
67 | }
68 |
69 | virtual void on_monitor_started() {
70 | LOG_IN("");
71 | LOG_EVENT("event_monitor_started")
72 | LOG_OUT("");
73 | }
74 |
75 | virtual void on_event_connected(const zmq_event_t &event, const char *addr) {
76 | LOG_IN("event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
77 | LOG_EVENT("event_connected: event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
78 | ++num_clients_;
79 | //monitor_event me(event, addr);
80 |
81 | // events_.enqueue(me);
82 | LOG_OUT("");
83 | }
84 |
85 | virtual void on_event_connect_delayed(const zmq_event_t &event, const char *addr) {
86 | LOG_IN("event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
87 |
88 | LOG_EVENT("connect_delayed: event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
89 | //monitor_event me(event, addr);
90 | //events_.enqueue(me);
91 | LOG_OUT("");
92 | }
93 |
94 | virtual void on_event_connect_retried(const zmq_event_t &event, const char *addr) {
95 | LOG_IN("event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
96 | LOG_EVENT("connect_retried: event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
97 | //monitor_event me(event, addr);
98 | // events_.enqueue(me);
99 | LOG_OUT("");
100 | }
101 |
102 | virtual void on_event_listening(const zmq_event_t &event, const char *addr) {
103 | LOG_IN("event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
104 | LOG_EVENT("event_listening: event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
105 | //monitor_event me(event, addr);
106 | //events_.enqueue(me);
107 | LOG_OUT("");
108 | }
109 |
110 | virtual void on_event_bind_failed(const zmq_event_t &event, const char *addr) {
111 | LOG_IN("event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
112 | LOG_EVENT("event_bind_failed: event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
113 | //monitor_event me(event, addr);
114 | //events_.enqueue(me);
115 | LOG_OUT("");
116 | }
117 |
118 | virtual void on_event_accepted(const zmq_event_t &event, const char *addr) {
119 | LOG_IN("event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
120 | LOG_EVENT("event_accepted: event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
121 | // monitor_event me(event, addr);
122 | // events_.enqueue(me);
123 | ++num_clients_;
124 | LOG_TRACE("Total number of clients connected: %d", num_clients_);
125 | LOG_OUT("");
126 | }
127 |
128 | virtual void on_event_accept_failed(const zmq_event_t &event, const char *addr) {
129 | LOG_IN("event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
130 | LOG_EVENT("event_accept_failed: event.event[%u],event.value[%u], addr[%s] ", event.event, event.value,
131 | addr);
132 | //monitor_event me(event, addr);
133 | //events_.enqueue(me);
134 | LOG_OUT("");
135 | }
136 |
137 | virtual void on_event_closed(const zmq_event_t &event, const char *addr) {
138 | LOG_IN("event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
139 | LOG_EVENT("event_closed: event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
140 | // monitor_event me(event, addr);
141 | //events_.enqueue(me);
142 | LOG_OUT("");
143 | }
144 |
145 | virtual void on_event_close_failed(const zmq_event_t &event, const char *addr) {
146 | LOG_IN("event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
147 | LOG_EVENT("event_close_failed: event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
148 | //monitor_event me(event, addr);
149 | //events_.enqueue(me);
150 | LOG_OUT("");
151 | }
152 |
153 | virtual void on_event_disconnected(const zmq_event_t &event, const char *addr) {
154 | LOG_IN("event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
155 | --num_clients_;
156 | LOG_EVENT("event_disconnected: event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
157 | //monitor_event me(event, addr);
158 | //events_.enqueue(me);
159 | LOG_TRACE("Total number of clients connected: %d", num_clients_);
160 | LOG_OUT("");
161 | }
162 |
163 | virtual void on_event_unknown(const zmq_event_t &event, const char *addr) {
164 | LOG_IN("event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
165 | LOG_EVENT("event_unknown: event.event[%u],event.value[%u], addr[%s] ", event.event, event.value, addr);
166 | //monitor_event me(event, addr);
167 | //events_.enqueue(me);
168 | LOG_OUT("");
169 | }
170 |
171 | // moodycamel::ReaderWriterQueue events_;
172 | int32_t num_clients_;
173 | };
174 |
175 | }
176 |
177 |
178 | #endif /* MONITOR_ZMQ_H */
179 |
180 |
--------------------------------------------------------------------------------
/include/producer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * File: producer.h
3 | * Author: Rohit Joshi
4 | *
5 | * Created on February 27, 2015, 10:27 PM
6 | */
7 |
8 | #ifndef PRODUCER_H
9 | #define PRODUCER_H
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include "log.h"
18 | #include "connection.h"
19 | #include "broker_config.h"
20 | //#include "broker.h"
21 | #include "broker_storage.h"
22 | #include "connection_zmq.h"
23 | #include "connection_socket.h"
24 |
25 | namespace lightq {
26 | //class producer
27 | struct producer_config {
28 | std::string id_;
29 | std::string producer_bind_uri_;
30 | connection::stream_type producer_stream_type_;
31 | connection::socket_connect_type producer_socket_connect_type_;
32 | };
33 |
34 | class producer {
35 | public:
36 |
37 | /**
38 | * constructor
39 | */
40 | producer(broker_storage *pstorage, producer_config &config) : p_storage_(pstorage), config_(config),
41 | producer_endpoint_type_(
42 | connection::endpoint_type::conn_publisher) {
43 | LOG_IN("broker_storage: %p, config: %s, pconnection::endpoint_type::conn_publisher",
44 | p_storage_, config.producer_bind_uri_.c_str());
45 | stop_ = false;
46 | p_producer_socket = NULL;
47 | LOG_OUT("");
48 | }
49 |
50 | /**
51 | * Destructor
52 | */
53 | ~producer() {
54 | LOG_IN("");
55 | if (producer_tid_.joinable())
56 | producer_tid_.join();
57 |
58 | delete p_producer_socket;
59 |
60 |
61 | LOG_OUT("");
62 | }
63 |
64 | /**
65 | * init
66 | * @return
67 | */
68 | bool init() {
69 | LOG_IN("");
70 | if (config_.producer_stream_type_ == connection::stream_type::stream_zmq) {
71 | p_producer_socket = new connection_zmq(
72 | config_.id_,
73 | config_.producer_bind_uri_,
74 | connection::endpoint_type::conn_publisher,
75 | connection_zmq::zmq_pull,
76 | config_.producer_socket_connect_type_,
77 | true, true);
78 | // connection_zmq* p_zmq_producer = (connection_zmq*)p_producer_socket;
79 | if (!p_producer_socket->init()) {
80 |
81 | LOG_RET_FALSE(utils::format_str(
82 | "Failed to initialize broker: %s, producer_bind_uri: %s",
83 | config_.id_.c_str(), config_.producer_bind_uri_.c_str()).c_str());
84 | }
85 | } else if (config_.producer_stream_type_ == connection::stream_socket) {
86 |
87 | p_producer_socket = new connection_socket(
88 | config_.id_,
89 | config_.producer_bind_uri_,
90 | connection::endpoint_type::conn_publisher,
91 | connection::bind_socket,
92 | true);
93 |
94 | connection_socket *psocket = (connection_socket *) p_producer_socket;
95 |
96 | if (!psocket->init(p_storage_)) {
97 |
98 | LOG_RET_FALSE(utils::format_str(
99 | "Failed to initialize broker: %s, consumer_bind_uri: %s",
100 | config_.id_.c_str(), config_.producer_bind_uri_.c_str()).c_str());
101 |
102 | } else {
103 |
104 | if (!p_producer_socket->run()) {
105 | LOG_RET_FALSE(utils::format_str(
106 | "Failed to run consumer broker: %s, consumer_bind_uri: %s",
107 | config_.id_.c_str(),
108 | config_.producer_bind_uri_.c_str()).c_str());
109 | }
110 | }
111 | } else {
112 | throw std::runtime_error("producer::init():Not implemented");
113 | }
114 | LOG_RET_TRUE("");
115 | }
116 |
117 |
118 |
119 |
120 | /**
121 | *
122 | * @return
123 | */
124 | bool run() {
125 | LOG_IN("");
126 | producer_tid_ = std::thread(
127 | [&]() {
128 | process_producers();
129 | });
130 | LOG_RET_TRUE("");
131 | }
132 | /*
133 | ssize_t process_socket_producers() {
134 | connection_socket* psocket = (connection_socket*)p_producer_socket;
135 | int fdset_size = 0;
136 | char buffer[utils::max_msg_size];
137 | while(!stop_) { //FIXME: If no producer connected, this will be in loop
138 | std::vector active_fds = psocket->get_active_fds();
139 | if(!active_fds.size()) {
140 | utils::sleep_ms(utils::queue_poll_wait);
141 | continue;
142 | }
143 | fd_set read_fd_set;
144 | FD_ZERO(&read_fd_set);
145 | for(unsigned i= 0; i < active_fds.size(); ++i) {
146 | FD_SET(active_fds[i], &read_fd_set);
147 | if(active_fds[i] > fdset_size) {
148 | fdset_size = active_fds[i];
149 | }
150 | }
151 | if (select(fdset_size, &read_fd_set, NULL, NULL, NULL) < 0) {
152 | LOG_ERROR("Failed to select on read fd");
153 | continue;
154 | }
155 | for (int i = 0; i < FD_SETSIZE; ++i) {
156 | int fd = active_fds[i];
157 | if (FD_ISSET(fd, &read_fd_set)) {
158 | buffer[0] = '\0';
159 | ssize_t bytes_read = utils::read_size(fd, true);
160 | if(bytes_read < 0) {
161 | psocket->remove_fd(i);
162 | continue;
163 | }else if(bytes_read == 0) {
164 | continue;
165 | }
166 | bytes_read = utils::read_buffer(buffer, utils::max_msg_size,bytes_read);
167 | if(bytes_read < 0) {
168 | psocket->remove_fd(i);
169 | continue;
170 | }
171 | if (!p_storage_->add_to_storage(buffer, bytes_read, true)) {
172 | LOG_RET_FALSE("failure");
173 | }
174 |
175 | }
176 | }
177 |
178 |
179 | }
180 |
181 |
182 | LOG_RET_TRUE("loop exit");
183 | }*/
184 |
185 |
186 |
187 | /**
188 | * process producers
189 | * @return
190 | */
191 | bool process_producers() {
192 | LOG_IN("");
193 | std::string message;
194 | message.reserve(utils::max_msg_size);
195 | while (!stop_) {
196 | message.clear();
197 | ssize_t bytes_read = p_producer_socket->read_msg(message);
198 | if (bytes_read < 0) {
199 | LOG_ERROR("Failed to read from producer connection id: %s, producer_bind_uri: %s",
200 | config_.id_.c_str(), config_.producer_bind_uri_.c_str());
201 | LOG_RET_FALSE("failure");
202 | }
203 | LOG_DEBUG("Read message with size: %d", bytes_read);
204 | //if bytes read zero, continue
205 | if (bytes_read == 0) continue;
206 | bool write_message_size = true;
207 | //if producer is socket, we expect producer to have message size included in the payload
208 | if (p_producer_socket->get_stream_type() == connection::stream_socket) {
209 | write_message_size = true;
210 | }
211 | if (!p_storage_->add_to_storage(message, write_message_size)) {
212 | LOG_RET_FALSE("failure");
213 | }
214 |
215 |
216 | }
217 | LOG_RET_TRUE("done");
218 | }
219 |
220 | std::string get_bind_uri() {
221 | return config_.producer_bind_uri_;
222 | }
223 |
224 | unsigned get_num_clients() {
225 | if (p_producer_socket) {
226 | connection_zmq *psocket = (connection_zmq *) p_producer_socket;
227 | return psocket->get_num_connected_clients();
228 | } else {
229 | return 0;
230 | }
231 | }
232 |
233 | connection::endpoint_type get_endpoint_type () {
234 | return producer_endpoint_type_;
235 | }
236 |
237 | private:
238 | broker_storage *p_storage_;
239 | producer_config config_;
240 | connection::endpoint_type producer_endpoint_type_;
241 | connection *p_producer_socket;
242 | bool stop_;
243 | std::thread producer_tid_;
244 |
245 |
246 | };
247 | }
248 |
249 |
250 | #endif /* PRODUCER_H */
251 |
252 |
--------------------------------------------------------------------------------
/include/thirdparty/atomicops.h:
--------------------------------------------------------------------------------
1 | // ©2013 Cameron Desrochers.
2 | // Distributed under the simplified BSD license (see the license file that
3 | // should have come with this header).
4 |
5 | #pragma once
6 |
7 | // Provides portable (VC++2010+, Intel ICC 13, GCC 4.7+, and anything C++11 compliant) implementation
8 | // of low-level memory barriers, plus a few semi-portable utility macros (for inlining and alignment).
9 | // Also has a basic atomic type (limited to hardware-supported atomics with no memory ordering guarantees).
10 | // Uses the AE_* prefix for macros (historical reasons), and the "moodycamel" namespace for symbols.
11 |
12 | #include
13 |
14 |
15 | // Platform detection
16 | #if defined(__INTEL_COMPILER)
17 | #define AE_ICC
18 | #elif defined(_MSC_VER)
19 | #define AE_VCPP
20 | #elif defined(__GNUC__)
21 | #define AE_GCC
22 | #endif
23 |
24 | #if defined(_M_IA64) || defined(__ia64__)
25 | #define AE_ARCH_IA64
26 | #elif defined(_WIN64) || defined(__amd64__) || defined(_M_X64) || defined(__x86_64__)
27 | #define AE_ARCH_X64
28 | #elif defined(_M_IX86) || defined(__i386__)
29 | #define AE_ARCH_X86
30 | #elif defined(_M_PPC) || defined(__powerpc__)
31 | #define AE_ARCH_PPC
32 | #else
33 | #define AE_ARCH_UNKNOWN
34 | #endif
35 |
36 |
37 | // AE_UNUSED
38 | #define AE_UNUSED(x) ((void)x)
39 |
40 |
41 | // AE_FORCEINLINE
42 | #if defined(AE_VCPP) || defined(AE_ICC)
43 | #define AE_FORCEINLINE __forceinline
44 | #elif defined(AE_GCC)
45 | //#define AE_FORCEINLINE __attribute__((always_inline))
46 | #define AE_FORCEINLINE inline
47 | #else
48 | #define AE_FORCEINLINE inline
49 | #endif
50 |
51 |
52 | // AE_ALIGN
53 | #if defined(AE_VCPP) || defined(AE_ICC)
54 | #define AE_ALIGN(x) __declspec(align(x))
55 | #elif defined(AE_GCC)
56 | #define AE_ALIGN(x) __attribute__((aligned(x)))
57 | #else
58 | // Assume GCC compliant syntax...
59 | #define AE_ALIGN(x) __attribute__((aligned(x)))
60 | #endif
61 |
62 |
63 | // Portable atomic fences implemented below:
64 |
65 | namespace moodycamel {
66 |
67 | enum memory_order {
68 | memory_order_relaxed,
69 | memory_order_acquire,
70 | memory_order_release,
71 | memory_order_acq_rel,
72 | memory_order_seq_cst,
73 |
74 | // memory_order_sync: Forces a full sync:
75 | // #LoadLoad, #LoadStore, #StoreStore, and most significantly, #StoreLoad
76 | memory_order_sync = memory_order_seq_cst
77 | };
78 |
79 | } // end namespace moodycamel
80 |
81 | #if defined(AE_VCPP) || defined(AE_ICC)
82 | // VS2010 and ICC13 don't support std::atomic_*_fence, implement our own fences
83 |
84 | #include
85 |
86 | #if defined(AE_ARCH_X64) || defined(AE_ARCH_X86)
87 | #define AeFullSync _mm_mfence
88 | #define AeLiteSync _mm_mfence
89 | #elif defined(AE_ARCH_IA64)
90 | #define AeFullSync __mf
91 | #define AeLiteSync __mf
92 | #elif defined(AE_ARCH_PPC)
93 | #include
94 | #define AeFullSync __sync
95 | #define AeLiteSync __lwsync
96 | #endif
97 |
98 |
99 | #ifdef AE_VCPP
100 | #pragma warning(push)
101 | #pragma warning(disable: 4365) // Disable erroneous 'conversion from long to unsigned int, signed/unsigned mismatch' error when using `assert`
102 | #endif
103 |
104 | namespace moodycamel {
105 |
106 | AE_FORCEINLINE void compiler_fence(memory_order order)
107 | {
108 | switch (order) {
109 | case memory_order_relaxed: break;
110 | case memory_order_acquire: _ReadBarrier(); break;
111 | case memory_order_release: _WriteBarrier(); break;
112 | case memory_order_acq_rel: _ReadWriteBarrier(); break;
113 | case memory_order_seq_cst: _ReadWriteBarrier(); break;
114 | default: assert(false);
115 | }
116 | }
117 |
118 | // x86/x64 have a strong memory model -- all loads and stores have
119 | // acquire and release semantics automatically (so only need compiler
120 | // barriers for those).
121 | #if defined(AE_ARCH_X86) || defined(AE_ARCH_X64)
122 | AE_FORCEINLINE void fence(memory_order order)
123 | {
124 | switch (order) {
125 | case memory_order_relaxed: break;
126 | case memory_order_acquire: _ReadBarrier(); break;
127 | case memory_order_release: _WriteBarrier(); break;
128 | case memory_order_acq_rel: _ReadWriteBarrier(); break;
129 | case memory_order_seq_cst:
130 | _ReadWriteBarrier();
131 | AeFullSync();
132 | _ReadWriteBarrier();
133 | break;
134 | default: assert(false);
135 | }
136 | }
137 | #else
138 | AE_FORCEINLINE void fence(memory_order order)
139 | {
140 | // Non-specialized arch, use heavier memory barriers everywhere just in case :-(
141 | switch (order) {
142 | case memory_order_relaxed:
143 | break;
144 | case memory_order_acquire:
145 | _ReadBarrier();
146 | AeLiteSync();
147 | _ReadBarrier();
148 | break;
149 | case memory_order_release:
150 | _WriteBarrier();
151 | AeLiteSync();
152 | _WriteBarrier();
153 | break;
154 | case memory_order_acq_rel:
155 | _ReadWriteBarrier();
156 | AeLiteSync();
157 | _ReadWriteBarrier();
158 | break;
159 | case memory_order_seq_cst:
160 | _ReadWriteBarrier();
161 | AeFullSync();
162 | _ReadWriteBarrier();
163 | break;
164 | default: assert(false);
165 | }
166 | }
167 | #endif
168 | } // end namespace moodycamel
169 | #else
170 | // Use standard library of atomics
171 | #include
172 |
173 | namespace moodycamel {
174 |
175 | AE_FORCEINLINE void compiler_fence(memory_order order)
176 | {
177 | switch (order) {
178 | case memory_order_relaxed: break;
179 | case memory_order_acquire: std::atomic_signal_fence(std::memory_order_acquire); break;
180 | case memory_order_release: std::atomic_signal_fence(std::memory_order_release); break;
181 | case memory_order_acq_rel: std::atomic_signal_fence(std::memory_order_acq_rel); break;
182 | case memory_order_seq_cst: std::atomic_signal_fence(std::memory_order_seq_cst); break;
183 | default: assert(false);
184 | }
185 | }
186 |
187 | AE_FORCEINLINE void fence(memory_order order)
188 | {
189 | switch (order) {
190 | case memory_order_relaxed: break;
191 | case memory_order_acquire: std::atomic_thread_fence(std::memory_order_acquire); break;
192 | case memory_order_release: std::atomic_thread_fence(std::memory_order_release); break;
193 | case memory_order_acq_rel: std::atomic_thread_fence(std::memory_order_acq_rel); break;
194 | case memory_order_seq_cst: std::atomic_thread_fence(std::memory_order_seq_cst); break;
195 | default: assert(false);
196 | }
197 | }
198 |
199 | } // end namespace moodycamel
200 |
201 | #endif
202 |
203 |
204 |
205 |
206 | #if !defined(AE_VCPP) || _MSC_VER >= 1700
207 | #define AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
208 | #endif
209 |
210 | #ifdef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
211 | #include
212 | #endif
213 | #include
214 |
215 | // WARNING: *NOT* A REPLACEMENT FOR std::atomic. READ CAREFULLY:
216 | // Provides basic support for atomic variables -- no memory ordering guarantees are provided.
217 | // The guarantee of atomicity is only made for types that already have atomic load and store guarantees
218 | // at the hardware level -- on most platforms this generally means aligned pointers and integers (only).
219 | namespace moodycamel {
220 | template
221 | class weak_atomic
222 | {
223 | public:
224 | weak_atomic() { }
225 | #ifdef AE_VCPP
226 | #pragma warning(disable: 4100) // Get rid of (erroneous) 'unreferenced formal parameter' warning
227 | #endif
228 | template weak_atomic(U&& x) : value(std::forward(x)) { }
229 | weak_atomic(weak_atomic const& other) : value(other.value) { }
230 | weak_atomic(weak_atomic&& other) : value(std::move(other.value)) { }
231 | #ifdef AE_VCPP
232 | #pragma warning(default: 4100)
233 | #endif
234 |
235 | AE_FORCEINLINE operator T() const { return load(); }
236 |
237 |
238 | #ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
239 | template AE_FORCEINLINE weak_atomic const& operator=(U&& x) { value = std::forward(x); return *this; }
240 | AE_FORCEINLINE weak_atomic const& operator=(weak_atomic const& other) { value = other.value; return *this; }
241 |
242 | AE_FORCEINLINE T load() const { return value; }
243 | #else
244 | template
245 | AE_FORCEINLINE weak_atomic const& operator=(U&& x)
246 | {
247 | value.store(std::forward(x), std::memory_order_relaxed);
248 | return *this;
249 | }
250 |
251 | AE_FORCEINLINE weak_atomic const& operator=(weak_atomic const& other)
252 | {
253 | value.store(other.value.load(std::memory_order_relaxed), std::memory_order_relaxed);
254 | return *this;
255 | }
256 |
257 | AE_FORCEINLINE T load() const { return value.load(std::memory_order_relaxed); }
258 | #endif
259 |
260 |
261 | private:
262 | #ifndef AE_USE_STD_ATOMIC_FOR_WEAK_ATOMIC
263 | // No std::atomic support, but still need to circumvent compiler optimizations.
264 | // `volatile` will make memory access slow, but is guaranteed to be reliable.
265 | volatile T value;
266 | #else
267 | std::atomic value;
268 | #endif
269 | };
270 |
271 | } // end namespace moodycamel
272 |
273 |
274 | #ifdef AE_VCPP
275 | #pragma warning(pop)
276 | #endif
277 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/async_logger.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 |
27 | // Very fast asynchronous logger (millions of logs per second on an average desktop)
28 | // Uses pre allocated lockfree queue for maximum throughput even under large number of threads.
29 | // Creates a single back thread to pop messages from the queue and log them.
30 | //
31 | // Upon each log write the logger:
32 | // 1. Checks if its log level is enough to log the message
33 | // 2. Push a new copy of the message to a queue (or block the caller until space is available in the queue)
34 | // 3. will throw spdlog_ex upon log exceptions
35 | // Upong destruction, logs all remaining messages in the queue before destructing..
36 |
37 | #include
38 | #include
39 | #include "common.h"
40 | #include "logger.h"
41 | #include "spdlog.h"
42 |
43 |
44 | namespace spdlog
45 | {
46 |
47 | namespace details
48 | {
49 | class async_log_helper;
50 | }
51 |
52 | class async_logger :public logger
53 | {
54 | public:
55 | template
56 | async_logger(const std::string& name,
57 | const It& begin,
58 | const It& end,
59 | size_t queue_size,
60 | const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
61 | const std::function& worker_warmup_cb = nullptr);
62 |
63 | async_logger(const std::string& logger_name,
64 | sinks_init_list sinks,
65 | size_t queue_size,
66 | const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
67 | const std::function& worker_warmup_cb = nullptr);
68 |
69 | async_logger(const std::string& logger_name,
70 | sink_ptr single_sink,
71 | size_t queue_size,
72 | const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
73 | const std::function& worker_warmup_cb = nullptr);
74 |
75 |
76 | protected:
77 | void _log_msg(details::log_msg& msg) override;
78 | void _set_formatter(spdlog::formatter_ptr msg_formatter) override;
79 | void _set_pattern(const std::string& pattern) override;
80 |
81 | private:
82 | std::unique_ptr _async_log_helper;
83 | };
84 | }
85 |
86 |
87 | #include "./details/async_logger_impl.h"
88 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/common.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 |
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | //visual studio does not support noexcept yet
33 | #ifndef _MSC_VER
34 | #define SPDLOG_NOEXCEPT noexcept
35 | #else
36 | #define SPDLOG_NOEXCEPT throw()
37 | #endif
38 |
39 | // under linux, you can use the much faster CLOCK_REALTIME_COARSE clock.
40 | // this clock is less accurate - can be off by few millis - depending on the kernel HZ
41 | // uncomment to use it instead of the regular (and slower) clock
42 |
43 | //#ifdef __linux__
44 | //#define SPDLOG_CLOCK_COARSE
45 | //#endif
46 |
47 | namespace spdlog
48 | {
49 |
50 | class formatter;
51 |
52 | namespace sinks
53 | {
54 | class sink;
55 | }
56 |
57 | // Common types across the lib
58 | using log_clock = std::chrono::system_clock;
59 | using sink_ptr = std::shared_ptr < sinks::sink > ;
60 | using sinks_init_list = std::initializer_list < sink_ptr > ;
61 | using formatter_ptr = std::shared_ptr;
62 |
63 | //Log level enum
64 | namespace level
65 | {
66 | typedef enum
67 | {
68 | trace = 0,
69 | debug = 1,
70 | info = 2,
71 | notice = 3,
72 | warn = 4,
73 | err = 5,
74 | critical = 6,
75 | alert = 7,
76 | emerg = 8,
77 | off = 9
78 | } level_enum;
79 |
80 | static const char* level_names[] { "trace", "debug", "info", "notice", "warning", "error", "critical", "alert", "emerg", "off"};
81 |
82 | static const char* short_level_names[] { "T", "D", "I", "N", "W", "E", "C", "A", "M", "O"};
83 |
84 | inline const char* to_str(spdlog::level::level_enum l)
85 | {
86 | return level_names[l];
87 | }
88 |
89 | inline const char* to_short_str(spdlog::level::level_enum l)
90 | {
91 | return short_level_names[l];
92 | }
93 | } //level
94 |
95 |
96 | //
97 | // Async overflow policy - block by default.
98 | //
99 | enum class async_overflow_policy
100 | {
101 | block_retry, // Block / yield / sleep until message can be enqueued
102 | discard_log_msg // Discard the message it enqueue fails
103 | };
104 |
105 |
106 | //
107 | // Log exception
108 | //
109 | class spdlog_ex : public std::exception
110 | {
111 | public:
112 | spdlog_ex(const std::string& msg) :_msg(msg) {}
113 | const char* what() const SPDLOG_NOEXCEPT override
114 | {
115 | return _msg.c_str();
116 | }
117 | private:
118 | std::string _msg;
119 |
120 | };
121 |
122 | } //spdlog
123 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/details/async_log_helper.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | // async log helper :
26 | // Process logs asynchronously using a back thread.
27 | //
28 | // If the internal queue of log messages reaches its max size,
29 | // then the client call will block until there is more room.
30 | //
31 | // If the back thread throws during logging, a spdlog::spdlog_ex exception
32 | // will be thrown in client's thread when tries to log the next message
33 |
34 | #pragma once
35 |
36 | #include
37 | #include
38 | #include
39 | #include
40 |
41 | #include "../common.h"
42 | #include "../sinks/sink.h"
43 | #include "./mpmc_bounded_q.h"
44 | #include "./log_msg.h"
45 | #include "./format.h"
46 |
47 |
48 | namespace spdlog
49 | {
50 | namespace details
51 | {
52 |
53 | class async_log_helper
54 | {
55 | // Async msg to move to/from the queue
56 | // Movable only. should never be copied
57 | struct async_msg
58 | {
59 | std::string logger_name;
60 | level::level_enum level;
61 | log_clock::time_point time;
62 | std::string txt;
63 |
64 | async_msg() = default;
65 | ~async_msg() = default;
66 |
67 | async_msg(async_msg&& other) SPDLOG_NOEXCEPT:
68 | logger_name(std::move(other.logger_name)),
69 | level(std::move(other.level)),
70 | time(std::move(other.time)),
71 | txt(std::move(other.txt))
72 | {}
73 |
74 | async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT
75 | {
76 | logger_name = std::move(other.logger_name);
77 | level = other.level;
78 | time = std::move(other.time);
79 | txt = std::move(other.txt);
80 | return *this;
81 | }
82 | // never copy or assign. should only be moved..
83 | async_msg(const async_msg&) = delete;
84 | async_msg& operator=(async_msg& other) = delete;
85 |
86 | // construct from log_msg
87 | async_msg(const details::log_msg& m) :
88 | logger_name(m.logger_name),
89 | level(m.level),
90 | time(m.time),
91 | txt(m.raw.data(), m.raw.size())
92 | {}
93 |
94 |
95 | // copy into log_msg
96 | void fill_log_msg(log_msg &msg)
97 | {
98 | msg.clear();
99 | msg.logger_name = logger_name;
100 | msg.level = level;
101 | msg.time = time;
102 | msg.raw << txt;
103 | }
104 | };
105 |
106 | public:
107 |
108 | using item_type = async_msg;
109 | using q_type = details::mpmc_bounded_queue;
110 |
111 | using clock = std::chrono::steady_clock;
112 |
113 |
114 | async_log_helper(formatter_ptr formatter,
115 | const std::vector& sinks,
116 | size_t queue_size,
117 | const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,
118 | const std::function& worker_warmup_cb = nullptr);
119 |
120 | void log(const details::log_msg& msg);
121 |
122 | // stop logging and join the back thread
123 | ~async_log_helper();
124 |
125 | void set_formatter(formatter_ptr);
126 |
127 |
128 | private:
129 | formatter_ptr _formatter;
130 | std::vector> _sinks;
131 |
132 | // queue of messages to log
133 | q_type _q;
134 |
135 | // last exception thrown from the worker thread
136 | std::shared_ptr _last_workerthread_ex;
137 |
138 | // overflow policy
139 | const async_overflow_policy _overflow_policy;
140 |
141 | // worker thread warmup callback - one can set thread priority, affinity, etc
142 | const std::function _worker_warmup_cb;
143 |
144 | // worker thread
145 | std::thread _worker_thread;
146 |
147 | // throw last worker thread exception or if worker thread is not active
148 | void throw_if_bad_worker();
149 |
150 | // worker thread main loop
151 | void worker_loop();
152 |
153 | // pop next message from the queue and process it
154 | // return true if a message was available (queue was not empty), will set the last_pop to the pop time
155 | bool process_next_msg(clock::time_point& last_pop);
156 |
157 | // sleep,yield or return immediatly using the time passed since last message as a hint
158 | static void sleep_or_yield(const clock::time_point& last_op_time);
159 |
160 | };
161 | }
162 | }
163 |
164 | ///////////////////////////////////////////////////////////////////////////////
165 | // async_sink class implementation
166 | ///////////////////////////////////////////////////////////////////////////////
167 | inline spdlog::details::async_log_helper::async_log_helper(formatter_ptr formatter, const std::vector& sinks, size_t queue_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb):
168 | _formatter(formatter),
169 | _sinks(sinks),
170 | _q(queue_size),
171 | _overflow_policy(overflow_policy),
172 | _worker_warmup_cb(worker_warmup_cb),
173 | _worker_thread(&async_log_helper::worker_loop, this)
174 | {}
175 |
176 | // Send to the worker thread termination message(level=off)
177 | // and wait for it to finish gracefully
178 | inline spdlog::details::async_log_helper::~async_log_helper()
179 | {
180 |
181 | try
182 | {
183 | log(log_msg(level::off));
184 | _worker_thread.join();
185 | }
186 | catch (...) //Dont crash if thread not joinable
187 | {}
188 | }
189 |
190 |
191 | //Try to push and block until succeeded
192 | inline void spdlog::details::async_log_helper::log(const details::log_msg& msg)
193 | {
194 | throw_if_bad_worker();
195 | async_msg new_msg(msg);
196 | if (!_q.enqueue(std::move(new_msg)) && _overflow_policy != async_overflow_policy::discard_log_msg)
197 | {
198 | auto last_op_time = clock::now();
199 | do
200 | {
201 | sleep_or_yield(last_op_time);
202 | }
203 | while (!_q.enqueue(std::move(new_msg)));
204 | }
205 |
206 | }
207 |
208 | inline void spdlog::details::async_log_helper::worker_loop()
209 | {
210 | try
211 | {
212 | if (_worker_warmup_cb) _worker_warmup_cb();
213 | clock::time_point last_pop = clock::now();
214 | while(process_next_msg(last_pop));
215 | }
216 | catch (const std::exception& ex)
217 | {
218 | _last_workerthread_ex = std::make_shared(std::string("async_logger worker thread exception: ") + ex.what());
219 | }
220 | catch (...)
221 | {
222 | _last_workerthread_ex = std::make_shared("async_logger worker thread exception");
223 | }
224 | }
225 |
226 | // process next message in the queue
227 | // return true if this thread should still be active (no msg with level::off was received)
228 | inline bool spdlog::details::async_log_helper::process_next_msg(clock::time_point& last_pop)
229 | {
230 |
231 | async_msg incoming_async_msg;
232 | log_msg incoming_log_msg;
233 |
234 | if (_q.dequeue(incoming_async_msg))
235 | {
236 | last_pop = clock::now();
237 |
238 | if(incoming_async_msg.level == level::off)
239 | return false;
240 |
241 | incoming_async_msg.fill_log_msg(incoming_log_msg);
242 | _formatter->format(incoming_log_msg);
243 | for (auto &s : _sinks)
244 | s->log(incoming_log_msg);
245 | }
246 | else //empty queue
247 | {
248 | sleep_or_yield(last_pop);
249 | }
250 | return true;
251 | }
252 |
253 | inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter)
254 | {
255 | _formatter = msg_formatter;
256 | }
257 |
258 |
259 | // sleep,yield or return immediatly using the time passed since last message as a hint
260 | inline void spdlog::details::async_log_helper::sleep_or_yield(const clock::time_point& last_op_time)
261 | {
262 | using std::chrono::milliseconds;
263 | using namespace std::this_thread;
264 |
265 | auto time_since_op = clock::now() - last_op_time;
266 |
267 | // spin upto 1 ms
268 | if (time_since_op <= milliseconds(1))
269 | return;
270 |
271 | // yield upto 10ms
272 | if (time_since_op <= milliseconds(10))
273 | return yield();
274 |
275 |
276 | // sleep for half of duration since last op
277 | if (time_since_op <= milliseconds(100))
278 | return sleep_for(time_since_op / 2);
279 |
280 | return sleep_for(milliseconds(100));
281 | }
282 |
283 | // throw if the worker thread threw an exception or not active
284 | inline void spdlog::details::async_log_helper::throw_if_bad_worker()
285 | {
286 | if (_last_workerthread_ex)
287 | {
288 | auto ex = std::move(_last_workerthread_ex);
289 | throw *ex;
290 | }
291 | }
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/details/async_logger_impl.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 |
27 |
28 | #include "./async_log_helper.h"
29 |
30 | //
31 | // Async Logger implementation
32 | // Use single async_sink (queue) to perform the logging in a worker thread
33 | //
34 |
35 |
36 | template
37 | inline spdlog::async_logger::async_logger(const std::string& logger_name,
38 | const It& begin,
39 | const It& end,
40 | size_t queue_size,
41 | const async_overflow_policy overflow_policy,
42 | const std::function& worker_warmup_cb) :
43 | logger(logger_name, begin, end),
44 | _async_log_helper(new details::async_log_helper(_formatter, _sinks, queue_size, overflow_policy, worker_warmup_cb))
45 | {
46 | }
47 |
48 | inline spdlog::async_logger::async_logger(const std::string& logger_name,
49 | sinks_init_list sinks,
50 | size_t queue_size,
51 | const async_overflow_policy overflow_policy,
52 | const std::function& worker_warmup_cb) :
53 | async_logger(logger_name, sinks.begin(), sinks.end(), queue_size, overflow_policy, worker_warmup_cb) {}
54 |
55 | inline spdlog::async_logger::async_logger(const std::string& logger_name,
56 | sink_ptr single_sink,
57 | size_t queue_size,
58 | const async_overflow_policy overflow_policy,
59 | const std::function& worker_warmup_cb) :
60 | async_logger(logger_name, { single_sink }, queue_size, overflow_policy, worker_warmup_cb) {}
61 |
62 |
63 | inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter)
64 | {
65 | _formatter = msg_formatter;
66 | _async_log_helper->set_formatter(_formatter);
67 | }
68 |
69 | inline void spdlog::async_logger::_set_pattern(const std::string& pattern)
70 | {
71 | _formatter = std::make_shared(pattern);
72 | _async_log_helper->set_formatter(_formatter);
73 | }
74 |
75 |
76 | inline void spdlog::async_logger::_log_msg(details::log_msg& msg)
77 | {
78 | _async_log_helper->log(msg);
79 | }
80 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/details/file_helper.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 |
27 | // Helper class for file sink
28 | // When failing to open a file, retry several times(5) with small delay between the tries(10 ms)
29 | // Can be set to auto flush on every line
30 | // Throw spdlog_ex exception on errors
31 |
32 | #include
33 | #include
34 | #include
35 | #include "os.h"
36 |
37 |
38 |
39 |
40 | namespace spdlog
41 | {
42 | namespace details
43 | {
44 |
45 | class file_helper
46 | {
47 | public:
48 | const int open_tries = 5;
49 | const int open_interval = 10;
50 |
51 | explicit file_helper(bool force_flush):
52 | _fd(nullptr),
53 | _force_flush(force_flush)
54 | {}
55 |
56 | file_helper(const file_helper&) = delete;
57 | file_helper& operator=(const file_helper&) = delete;
58 |
59 | ~file_helper()
60 | {
61 | close();
62 | }
63 |
64 |
65 | void open(const std::string& fname, bool truncate=false)
66 | {
67 |
68 | close();
69 | const char* mode = truncate ? "wb" : "ab";
70 | _filename = fname;
71 | for (int tries = 0; tries < open_tries; ++tries)
72 | {
73 | if(!os::fopen_s(&_fd, fname, mode))
74 | return;
75 |
76 | std::this_thread::sleep_for(std::chrono::milliseconds(open_interval));
77 | }
78 |
79 | throw spdlog_ex("Failed opening file " + fname + " for writing");
80 | }
81 |
82 | void reopen(bool truncate)
83 | {
84 | if(_filename.empty())
85 | throw spdlog_ex("Failed re opening file - was not opened before");
86 | open(_filename, truncate);
87 |
88 | }
89 |
90 | void close()
91 | {
92 | if (_fd)
93 | {
94 | std::fclose(_fd);
95 | _fd = nullptr;
96 | }
97 | }
98 |
99 | void write(const log_msg& msg)
100 | {
101 |
102 | size_t size = msg.formatted.size();
103 | auto data = msg.formatted.data();
104 | if(std::fwrite(data, 1, size, _fd) != size)
105 | throw spdlog_ex("Failed writing to file " + _filename);
106 |
107 | if(_force_flush)
108 | std::fflush(_fd);
109 |
110 | }
111 |
112 | const std::string& filename() const
113 | {
114 | return _filename;
115 | }
116 |
117 | static bool file_exists(const std::string& name)
118 | {
119 | FILE* file;
120 | if (!os::fopen_s(&file, name.c_str(), "r"))
121 | {
122 | fclose(file);
123 | return true;
124 | }
125 | else
126 | {
127 | return false;
128 | }
129 | }
130 |
131 | private:
132 | FILE* _fd;
133 | std::string _filename;
134 | bool _force_flush;
135 |
136 |
137 | };
138 | }
139 | }
140 |
141 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/details/line_logger.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 | #include
27 | #include "../common.h"
28 | #include "../logger.h"
29 |
30 |
31 | // Line logger class - aggregates operator<< calls to fast ostream
32 | // and logs upon destruction
33 |
34 | namespace spdlog
35 | {
36 | namespace details
37 | {
38 | class line_logger
39 | {
40 | public:
41 | line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled):
42 | _callback_logger(callback_logger),
43 | _log_msg(msg_level),
44 | _enabled(enabled)
45 | {}
46 |
47 | // No copy intended. Only move
48 | line_logger(const line_logger& other) = delete;
49 | line_logger& operator=(const line_logger&) = delete;
50 | line_logger& operator=(line_logger&&) = delete;
51 |
52 |
53 | line_logger(line_logger&& other) :
54 | _callback_logger(other._callback_logger),
55 | _log_msg(std::move(other._log_msg)),
56 | _enabled(other._enabled)
57 | {
58 | other.disable();
59 | }
60 |
61 | //Log the log message using the callback logger
62 | ~line_logger()
63 | {
64 | if (_enabled)
65 | {
66 | _log_msg.logger_name = _callback_logger->name();
67 | _log_msg.time = os::now();
68 | _callback_logger->_log_msg(_log_msg);
69 | }
70 | }
71 |
72 | //
73 | // Support for format string with variadic args
74 | //
75 |
76 |
77 | void write(const char* what)
78 | {
79 | if (_enabled)
80 | _log_msg.raw << what;
81 | }
82 |
83 | template
84 | void write(const char* fmt, const Args&... args)
85 | {
86 | if (!_enabled)
87 | return;
88 | try
89 | {
90 | _log_msg.raw.write(fmt, args...);
91 | }
92 | catch (const fmt::FormatError& e)
93 | {
94 | throw spdlog_ex(fmt::format("formatting error while processing format string '{}': {}", fmt, e.what()));
95 | }
96 | }
97 |
98 |
99 | //
100 | // Support for operator<<
101 | //
102 | line_logger& operator<<(const char* what)
103 | {
104 | if (_enabled)
105 | _log_msg.raw << what;
106 | return *this;
107 | }
108 |
109 | line_logger& operator<<(const std::string& what)
110 | {
111 | if (_enabled)
112 | _log_msg.raw << what;
113 | return *this;
114 | }
115 |
116 | line_logger& operator<<(int what)
117 | {
118 | if (_enabled)
119 | _log_msg.raw << what;
120 | return *this;
121 | }
122 |
123 | line_logger& operator<<(unsigned int what)
124 | {
125 | if (_enabled)
126 | _log_msg.raw << what;
127 | return *this;
128 | }
129 |
130 |
131 | line_logger& operator<<(long what)
132 | {
133 | if (_enabled)
134 | _log_msg.raw << what;
135 | return *this;
136 | }
137 |
138 | line_logger& operator<<(unsigned long what)
139 | {
140 | if (_enabled)
141 | _log_msg.raw << what;
142 | return *this;
143 | }
144 |
145 | line_logger& operator<<(long long what)
146 | {
147 | if (_enabled)
148 | _log_msg.raw << what;
149 | return *this;
150 | }
151 |
152 | line_logger& operator<<(unsigned long long what)
153 | {
154 | if (_enabled)
155 | _log_msg.raw << what;
156 | return *this;
157 | }
158 |
159 | line_logger& operator<<(double what)
160 | {
161 | if (_enabled)
162 | _log_msg.raw << what;
163 | return *this;
164 | }
165 |
166 | line_logger& operator<<(long double what)
167 | {
168 | if (_enabled)
169 | _log_msg.raw << what;
170 | return *this;
171 | }
172 |
173 | line_logger& operator<<(float what)
174 | {
175 | if (_enabled)
176 | _log_msg.raw << what;
177 | return *this;
178 | }
179 |
180 | line_logger& operator<<(char what)
181 | {
182 | if (_enabled)
183 | _log_msg.raw << what;
184 | return *this;
185 | }
186 |
187 | //Support user types which implements operator<<
188 | template
189 | line_logger& operator<<(const T& what)
190 | {
191 | if (_enabled)
192 | _log_msg.raw.write("{}", what);
193 | return *this;
194 | }
195 |
196 |
197 | void disable()
198 | {
199 | _enabled = false;
200 | }
201 |
202 |
203 | private:
204 | logger* _callback_logger;
205 | log_msg _log_msg;
206 | bool _enabled;
207 | };
208 | } //Namespace details
209 | } // Namespace spdlog
210 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/details/log_msg.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 |
27 | #include "../common.h"
28 | #include "./format.h"
29 |
30 | namespace spdlog
31 | {
32 | namespace details
33 | {
34 | struct log_msg
35 | {
36 | log_msg() = default;
37 | log_msg(level::level_enum l):
38 | logger_name(),
39 | level(l),
40 | time(),
41 | raw(),
42 | formatted() {}
43 |
44 |
45 | log_msg(const log_msg& other) :
46 | logger_name(other.logger_name),
47 | level(other.level),
48 | time(other.time)
49 | {
50 | if (other.raw.size())
51 | raw << fmt::BasicStringRef(other.raw.data(), other.raw.size());
52 | if (other.formatted.size())
53 | formatted << fmt::BasicStringRef(other.formatted.data(), other.formatted.size());
54 | }
55 |
56 | log_msg(log_msg&& other) :
57 | logger_name(std::move(other.logger_name)),
58 | level(other.level),
59 | time(std::move(other.time)),
60 | raw(std::move(other.raw)),
61 | formatted(std::move(other.formatted))
62 | {
63 | other.clear();
64 | }
65 |
66 | log_msg& operator=(log_msg&& other)
67 | {
68 | if (this == &other)
69 | return *this;
70 |
71 | logger_name = std::move(other.logger_name);
72 | level = other.level;
73 | time = std::move(other.time);
74 | raw = std::move(other.raw);
75 | formatted = std::move(other.formatted);
76 | other.clear();
77 | return *this;
78 | }
79 |
80 | void clear()
81 | {
82 | level = level::off;
83 | raw.clear();
84 | formatted.clear();
85 | }
86 |
87 | std::string logger_name;
88 | level::level_enum level;
89 | log_clock::time_point time;
90 | fmt::MemoryWriter raw;
91 | fmt::MemoryWriter formatted;
92 | };
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/details/logger_impl.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 | //
27 | // Logger implementation
28 | //
29 |
30 | #include "./line_logger.h"
31 |
32 |
33 | // create logger with given name, sinks and the default pattern formatter
34 | // all other ctors will call this one
35 | template
36 | inline spdlog::logger::logger(const std::string& logger_name, const It& begin, const It& end) :
37 | _name(logger_name),
38 | _sinks(begin, end),
39 | _formatter(std::make_shared("%+"))
40 | {
41 |
42 | // no support under vs2013 for member initialization for std::atomic
43 | _level = level::info;
44 | }
45 |
46 | // ctor with sinks as init list
47 | inline spdlog::logger::logger(const std::string& logger_name, sinks_init_list sinks_list) :
48 | logger(logger_name, sinks_list.begin(), sinks_list.end()) {}
49 |
50 |
51 | // ctor with single sink
52 | inline spdlog::logger::logger(const std::string& logger_name, spdlog::sink_ptr single_sink) :
53 | logger(logger_name, { single_sink }) {}
54 |
55 |
56 | inline spdlog::logger::~logger() = default;
57 |
58 |
59 | inline void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter)
60 | {
61 | _set_formatter(msg_formatter);
62 | }
63 |
64 | inline void spdlog::logger::set_pattern(const std::string& pattern)
65 | {
66 | _set_pattern(pattern);
67 | }
68 |
69 | //
70 | // log only if given level>=logger's log level
71 | //
72 |
73 |
74 | template
75 | inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args)
76 | {
77 | bool msg_enabled = should_log(lvl);
78 | details::line_logger l(this, lvl, msg_enabled);
79 | l.write(fmt, args...);
80 | return l;
81 | }
82 |
83 | inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl)
84 | {
85 | return details::line_logger(this, lvl, should_log(lvl));
86 | }
87 |
88 | template
89 | inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const T& msg)
90 | {
91 | bool msg_enabled = should_log(lvl);
92 | details::line_logger l(this, lvl, msg_enabled);
93 | l << msg;
94 | return l;
95 | }
96 |
97 | //
98 | // logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
99 | //
100 | template
101 | inline spdlog::details::line_logger spdlog::logger::trace(const char* fmt, const Args&... args)
102 | {
103 | return _log_if_enabled(level::trace, fmt, args...);
104 | }
105 |
106 | template
107 | inline spdlog::details::line_logger spdlog::logger::debug(const char* fmt, const Args&... args)
108 | {
109 | return _log_if_enabled(level::debug, fmt, args...);
110 | }
111 |
112 | template
113 | inline spdlog::details::line_logger spdlog::logger::info(const char* fmt, const Args&... args)
114 | {
115 | return _log_if_enabled(level::info, fmt, args...);
116 | }
117 |
118 | template
119 | inline spdlog::details::line_logger spdlog::logger::notice(const char* fmt, const Args&... args)
120 | {
121 | return _log_if_enabled(level::notice, fmt, args...);
122 | }
123 |
124 | template
125 | inline spdlog::details::line_logger spdlog::logger::warn(const char* fmt, const Args&... args)
126 | {
127 | return _log_if_enabled(level::warn, fmt, args...);
128 | }
129 |
130 | template
131 | inline spdlog::details::line_logger spdlog::logger::error(const char* fmt, const Args&... args)
132 | {
133 | return _log_if_enabled(level::err, fmt, args...);
134 | }
135 |
136 | template
137 | inline spdlog::details::line_logger spdlog::logger::critical(const char* fmt, const Args&... args)
138 | {
139 | return _log_if_enabled(level::critical, fmt, args...);
140 | }
141 |
142 | template
143 | inline spdlog::details::line_logger spdlog::logger::alert(const char* fmt, const Args&... args)
144 | {
145 | return _log_if_enabled(level::alert, fmt, args...);
146 | }
147 |
148 | template
149 | inline spdlog::details::line_logger spdlog::logger::emerg(const char* fmt, const Args&... args)
150 | {
151 | return _log_if_enabled(level::emerg, fmt, args...);
152 | }
153 |
154 | //
155 | // logger.info(msg) << ".." call style
156 | //
157 | template
158 | inline spdlog::details::line_logger spdlog::logger::trace(const T& msg)
159 | {
160 | return _log_if_enabled(level::trace, msg);
161 | }
162 |
163 | template
164 | inline spdlog::details::line_logger spdlog::logger::debug(const T& msg)
165 | {
166 | return _log_if_enabled(level::debug, msg);
167 | }
168 |
169 |
170 | template
171 | inline spdlog::details::line_logger spdlog::logger::info(const T& msg)
172 | {
173 | return _log_if_enabled(level::info, msg);
174 | }
175 |
176 | template
177 | inline spdlog::details::line_logger spdlog::logger::notice(const T& msg)
178 | {
179 | return _log_if_enabled(level::notice, msg);
180 | }
181 |
182 | template
183 | inline spdlog::details::line_logger spdlog::logger::warn(const T& msg)
184 | {
185 | return _log_if_enabled(level::warn, msg);
186 | }
187 |
188 | template
189 | inline spdlog::details::line_logger spdlog::logger::error(const T& msg)
190 | {
191 | return _log_if_enabled(level::err, msg);
192 | }
193 |
194 | template
195 | inline spdlog::details::line_logger spdlog::logger::critical(const T& msg)
196 | {
197 | return _log_if_enabled(level::critical, msg);
198 | }
199 |
200 | template
201 | inline spdlog::details::line_logger spdlog::logger::alert(const T& msg)
202 | {
203 | return _log_if_enabled(level::alert, msg);
204 | }
205 |
206 | template
207 | inline spdlog::details::line_logger spdlog::logger::emerg(const T& msg)
208 | {
209 | return _log_if_enabled(level::emerg, msg);
210 | }
211 |
212 |
213 |
214 |
215 | //
216 | // logger.info() << ".." call style
217 | //
218 | inline spdlog::details::line_logger spdlog::logger::trace()
219 | {
220 | return _log_if_enabled(level::trace);
221 | }
222 |
223 | inline spdlog::details::line_logger spdlog::logger::debug()
224 | {
225 | return _log_if_enabled(level::debug);
226 | }
227 |
228 | inline spdlog::details::line_logger spdlog::logger::info()
229 | {
230 | return _log_if_enabled(level::info);
231 | }
232 |
233 | inline spdlog::details::line_logger spdlog::logger::notice()
234 | {
235 | return _log_if_enabled(level::notice);
236 | }
237 |
238 | inline spdlog::details::line_logger spdlog::logger::warn()
239 | {
240 | return _log_if_enabled(level::warn);
241 | }
242 |
243 | inline spdlog::details::line_logger spdlog::logger::error()
244 | {
245 | return _log_if_enabled(level::err);
246 | }
247 |
248 | inline spdlog::details::line_logger spdlog::logger::critical()
249 | {
250 | return _log_if_enabled(level::critical);
251 | }
252 |
253 | inline spdlog::details::line_logger spdlog::logger::alert()
254 | {
255 | return _log_if_enabled(level::alert);
256 | }
257 |
258 | inline spdlog::details::line_logger spdlog::logger::emerg()
259 | {
260 | return _log_if_enabled(level::emerg);
261 | }
262 |
263 |
264 | // always log, no matter what is the actual logger's log level
265 | template
266 | inline spdlog::details::line_logger spdlog::logger::force_log(level::level_enum lvl, const char* fmt, const Args&... args)
267 | {
268 | details::line_logger l(this, lvl, true);
269 | l.write(fmt, args...);
270 | return l;
271 | }
272 |
273 | //
274 | // name and level
275 | //
276 | inline const std::string& spdlog::logger::name() const
277 | {
278 | return _name;
279 | }
280 |
281 | inline void spdlog::logger::set_level(spdlog::level::level_enum log_level)
282 | {
283 | _level.store(log_level);
284 | }
285 |
286 | inline spdlog::level::level_enum spdlog::logger::level() const
287 | {
288 | return static_cast(_level.load(std::memory_order_relaxed));
289 | }
290 |
291 | inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const
292 | {
293 | return msg_level >= _level.load(std::memory_order_relaxed);
294 | }
295 |
296 | //
297 | // protected virtual called at end of each user log call (if enabled) by the line_logger
298 | //
299 | inline void spdlog::logger::_log_msg(details::log_msg& msg)
300 | {
301 | _formatter->format(msg);
302 | for (auto &sink : _sinks)
303 | sink->log(msg);
304 | }
305 |
306 | inline void spdlog::logger::_set_pattern(const std::string& pattern)
307 | {
308 | _formatter = std::make_shared(pattern);
309 | }
310 | inline void spdlog::logger::_set_formatter(formatter_ptr msg_formatter)
311 | {
312 | _formatter = msg_formatter;
313 | }
314 |
315 |
316 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/details/mpmc_bounded_q.h:
--------------------------------------------------------------------------------
1 | /*
2 | A modified version of Bounded MPMC queue by Dmitry Vyukov.
3 |
4 | Original code from:
5 | http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
6 |
7 | licensed by Dmitry Vyukov under the terms below:
8 |
9 | Simplified BSD license
10 |
11 | Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
12 | Redistribution and use in source and binary forms, with or without modification,
13 | are permitted provided that the following conditions are met:
14 | 1. Redistributions of source code must retain the above copyright notice, this list of
15 | conditions and the following disclaimer.
16 |
17 | 2. Redistributions in binary form must reproduce the above copyright notice, this list
18 | of conditions and the following disclaimer in the documentation and/or other materials
19 | provided with the distribution.
20 |
21 | THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
22 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24 | SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
27 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
32 | The views and conclusions contained in the software and documentation are those of the authors and
33 | should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov.
34 | */
35 |
36 | /*
37 | The code in its current form adds the license below:
38 |
39 | spdlog - an extremely fast and easy to use c++11 logging library.
40 | Copyright (c) 2014 Gabi Melman.
41 |
42 | Permission is hereby granted, free of charge, to any person obtaining
43 | a copy of this software and associated documentation files (the
44 | "Software"), to deal in the Software without restriction, including
45 | without limitation the rights to use, copy, modify, merge, publish,
46 | distribute, sublicense, and/or sell copies of the Software, and to
47 | permit persons to whom the Software is furnished to do so, subject to
48 | the following conditions:
49 |
50 | The above copyright notice and this permission notice shall be
51 | included in all copies or substantial portions of the Software.
52 |
53 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
54 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
55 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
56 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
57 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
58 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
59 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
60 | */
61 |
62 | #pragma once
63 |
64 | #include
65 | #include "../common.h"
66 |
67 | namespace spdlog
68 | {
69 | namespace details
70 | {
71 |
72 | template
73 | class mpmc_bounded_queue
74 | {
75 | public:
76 |
77 | using item_type = T;
78 | mpmc_bounded_queue(size_t buffer_size)
79 | : buffer_(new cell_t [buffer_size]),
80 | buffer_mask_(buffer_size - 1)
81 | {
82 | //queue size must be power of two
83 | if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0)))
84 | throw spdlog_ex("async logger queue size must be power of two");
85 |
86 | for (size_t i = 0; i != buffer_size; i += 1)
87 | buffer_[i].sequence_.store(i, std::memory_order_relaxed);
88 | enqueue_pos_.store(0, std::memory_order_relaxed);
89 | dequeue_pos_.store(0, std::memory_order_relaxed);
90 | }
91 |
92 | ~mpmc_bounded_queue()
93 | {
94 | delete [] buffer_;
95 | }
96 |
97 |
98 | bool enqueue(T&& data)
99 | {
100 | cell_t* cell;
101 | size_t pos = enqueue_pos_.load(std::memory_order_relaxed);
102 | for (;;)
103 | {
104 | cell = &buffer_[pos & buffer_mask_];
105 | size_t seq = cell->sequence_.load(std::memory_order_acquire);
106 | intptr_t dif = (intptr_t)seq - (intptr_t)pos;
107 | if (dif == 0)
108 | {
109 | if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
110 | break;
111 | }
112 | else if (dif < 0)
113 | {
114 | return false;
115 | }
116 | else
117 | {
118 | pos = enqueue_pos_.load(std::memory_order_relaxed);
119 | }
120 | }
121 | cell->data_ = std::move(data);
122 | cell->sequence_.store(pos + 1, std::memory_order_release);
123 | return true;
124 | }
125 |
126 | bool dequeue(T& data)
127 | {
128 | cell_t* cell;
129 | size_t pos = dequeue_pos_.load(std::memory_order_relaxed);
130 | for (;;)
131 | {
132 | cell = &buffer_[pos & buffer_mask_];
133 | size_t seq =
134 | cell->sequence_.load(std::memory_order_acquire);
135 | intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1);
136 | if (dif == 0)
137 | {
138 | if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed))
139 | break;
140 | }
141 | else if (dif < 0)
142 | return false;
143 | else
144 | pos = dequeue_pos_.load(std::memory_order_relaxed);
145 | }
146 | data = std::move(cell->data_);
147 | cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release);
148 | return true;
149 | }
150 |
151 | private:
152 | struct cell_t
153 | {
154 | std::atomic sequence_;
155 | T data_;
156 | };
157 |
158 | static size_t const cacheline_size = 64;
159 | typedef char cacheline_pad_t [cacheline_size];
160 |
161 | cacheline_pad_t pad0_;
162 | cell_t* const buffer_;
163 | size_t const buffer_mask_;
164 | cacheline_pad_t pad1_;
165 | std::atomic enqueue_pos_;
166 | cacheline_pad_t pad2_;
167 | std::atomic dequeue_pos_;
168 | cacheline_pad_t pad3_;
169 |
170 | mpmc_bounded_queue(mpmc_bounded_queue const&);
171 | void operator = (mpmc_bounded_queue const&);
172 | };
173 |
174 | } // ns details
175 | } // ns spdlog
176 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/details/null_mutex.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 |
27 | // null, no cost mutex
28 |
29 | namespace spdlog
30 | {
31 | namespace details
32 | {
33 | struct null_mutex
34 | {
35 | void lock() {}
36 | void unlock() {}
37 | bool try_lock()
38 | {
39 | return true;
40 | }
41 | };
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/details/os.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 | #include
27 | #include
28 | #include
29 |
30 | #ifdef _WIN32
31 | # ifndef WIN32_LEAN_AND_MEAN
32 | # define WIN32_LEAN_AND_MEAN
33 | # endif
34 | # include
35 | #endif
36 |
37 | #include "../common.h"
38 |
39 | namespace spdlog
40 | {
41 | namespace details
42 | {
43 | namespace os
44 | {
45 |
46 | inline spdlog::log_clock::time_point now()
47 | {
48 |
49 | #ifdef SPDLOG_CLOCK_COARSE
50 | timespec ts;
51 | ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
52 | return std::chrono::time_point(
53 | std::chrono::duration_cast(
54 | std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
55 |
56 | #else
57 | return log_clock::now();
58 | #endif
59 |
60 | }
61 | inline std::tm localtime(const std::time_t &time_tt)
62 | {
63 |
64 | #ifdef _WIN32
65 | std::tm tm;
66 | localtime_s(&tm, &time_tt);
67 | #else
68 | std::tm tm;
69 | localtime_r(&time_tt, &tm);
70 | #endif
71 | return tm;
72 | }
73 |
74 | inline std::tm localtime()
75 | {
76 | std::time_t now_t = time(nullptr);
77 | return localtime(now_t);
78 | }
79 |
80 |
81 | inline std::tm gmtime(const std::time_t &time_tt)
82 | {
83 |
84 | #ifdef _WIN32
85 | std::tm tm;
86 | gmtime_s(&tm, &time_tt);
87 | #else
88 | std::tm tm;
89 | gmtime_r(&time_tt, &tm);
90 | #endif
91 | return tm;
92 | }
93 |
94 | inline std::tm gmtime()
95 | {
96 | std::time_t now_t = time(nullptr);
97 | return gmtime(now_t);
98 | }
99 | inline bool operator==(const std::tm& tm1, const std::tm& tm2)
100 | {
101 | return (tm1.tm_sec == tm2.tm_sec &&
102 | tm1.tm_min == tm2.tm_min &&
103 | tm1.tm_hour == tm2.tm_hour &&
104 | tm1.tm_mday == tm2.tm_mday &&
105 | tm1.tm_mon == tm2.tm_mon &&
106 | tm1.tm_year == tm2.tm_year &&
107 | tm1.tm_isdst == tm2.tm_isdst);
108 | }
109 |
110 | inline bool operator!=(const std::tm& tm1, const std::tm& tm2)
111 | {
112 | return !(tm1 == tm2);
113 | }
114 |
115 | #ifdef _WIN32
116 | inline const char* eol()
117 | {
118 | return "\r\n";
119 | }
120 | #else
121 | constexpr inline const char* eol()
122 | {
123 | return "\n";
124 | }
125 | #endif
126 |
127 | #ifdef _WIN32
128 | inline unsigned short eol_size()
129 | {
130 | return 2;
131 | }
132 | #else
133 | constexpr inline unsigned short eol_size()
134 | {
135 | return 1;
136 | }
137 | #endif
138 |
139 | //fopen_s on non windows for writing
140 | inline int fopen_s(FILE** fp, const std::string& filename, const char* mode)
141 | {
142 | #ifdef _WIN32
143 | *fp = _fsopen((filename.c_str()), mode, _SH_DENYWR);
144 | return *fp == nullptr;
145 | #else
146 | *fp = fopen((filename.c_str()), mode);
147 | return *fp == nullptr;
148 | #endif
149 |
150 |
151 | }
152 |
153 | //Return utc offset in minutes or -1 on failure
154 | inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
155 | {
156 |
157 | #ifdef _WIN32
158 | (void)tm; // avoid unused param warning
159 | DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
160 | auto rv = GetDynamicTimeZoneInformation(&tzinfo);
161 | if (!rv)
162 | return -1;
163 | return -1 * (tzinfo.Bias + tzinfo.DaylightBias);
164 | #else
165 | return static_cast(tm.tm_gmtoff / 60);
166 | #endif
167 | }
168 |
169 |
170 | } //os
171 | } //details
172 | } //spdlog
173 |
174 |
175 |
176 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/details/registry.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 | // Loggers registy of unique name->logger pointer
27 | // An attempt to create a logger with an alreasy existing name will be ignored
28 | // If user requests a non existing logger, nullptr will be returned
29 | // This class is thread safe
30 |
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | #include "../logger.h"
37 | #include "../async_logger.h"
38 | #include "../common.h"
39 |
40 | namespace spdlog
41 | {
42 | namespace details
43 | {
44 |
45 | class registry
46 | {
47 | public:
48 | std::shared_ptr get(const std::string& logger_name)
49 | {
50 | std::lock_guard lock(_mutex);
51 | auto found = _loggers.find(logger_name);
52 | return found == _loggers.end() ? nullptr : found->second;
53 | }
54 |
55 | template
56 | std::shared_ptr create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
57 | {
58 | std::lock_guard lock(_mutex);
59 | //If already exists, just return it
60 | auto found = _loggers.find(logger_name);
61 | if (found != _loggers.end())
62 | return found->second;
63 | std::shared_ptr new_logger;
64 | if (_async_mode)
65 | new_logger = std::make_shared(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy, _worker_warmup_cb);
66 | else
67 | new_logger = std::make_shared(logger_name, sinks_begin, sinks_end);
68 |
69 | if (_formatter)
70 | new_logger->set_formatter(_formatter);
71 | new_logger->set_level(_level);
72 | _loggers[logger_name] = new_logger;
73 | return new_logger;
74 | }
75 |
76 | void drop(const std::string& logger_name)
77 | {
78 | std::lock_guard lock(_mutex);
79 | _loggers.erase(logger_name);
80 | }
81 |
82 | void drop_all()
83 | {
84 | std::lock_guard lock(_mutex);
85 | _loggers.clear();
86 | }
87 | std::shared_ptr create(const std::string& logger_name, sinks_init_list sinks)
88 | {
89 | return create(logger_name, sinks.begin(), sinks.end());
90 | }
91 |
92 | std::shared_ptr create(const std::string& logger_name, sink_ptr sink)
93 | {
94 | return create(logger_name, { sink });
95 | }
96 |
97 |
98 | void formatter(formatter_ptr f)
99 | {
100 | std::lock_guard lock(_mutex);
101 | _formatter = f;
102 | for (auto& l : _loggers)
103 | l.second->set_formatter(_formatter);
104 | }
105 |
106 |
107 | void set_pattern(const std::string& pattern)
108 | {
109 | std::lock_guard lock(_mutex);
110 | _formatter = std::make_shared(pattern);
111 | for (auto& l : _loggers)
112 | l.second->set_formatter(_formatter);
113 |
114 | }
115 |
116 | void set_level(level::level_enum log_level)
117 | {
118 | std::lock_guard lock(_mutex);
119 | for (auto& l : _loggers)
120 | l.second->set_level(log_level);
121 | }
122 |
123 | void set_async_mode(size_t q_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb)
124 | {
125 | std::lock_guard lock(_mutex);
126 | _async_mode = true;
127 | _async_q_size = q_size;
128 | _overflow_policy = overflow_policy;
129 | _worker_warmup_cb = worker_warmup_cb;
130 | }
131 |
132 | void set_sync_mode()
133 | {
134 | std::lock_guard lock(_mutex);
135 | _async_mode = false;
136 | }
137 |
138 |
139 | static registry& instance()
140 | {
141 | static registry s_instance;
142 | return s_instance;
143 | }
144 |
145 | private:
146 | registry() = default;
147 | registry(const registry&) = delete;
148 | registry& operator=(const registry&) = delete;
149 | std::mutex _mutex;
150 | std::unordered_map > _loggers;
151 | formatter_ptr _formatter;
152 | level::level_enum _level = level::info;
153 | bool _async_mode = false;
154 | size_t _async_q_size = 0;
155 | async_overflow_policy _overflow_policy = async_overflow_policy::block_retry;
156 | std::function _worker_warmup_cb = nullptr;
157 | };
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/details/spdlog_impl.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 |
27 | //
28 | // Global registry functions
29 | //
30 | #include "registry.h"
31 | #include "../sinks/file_sinks.h"
32 | #include "../sinks/stdout_sinks.h"
33 | #include "../sinks/syslog_sink.h"
34 |
35 | inline std::shared_ptr spdlog::get(const std::string& name)
36 | {
37 | return details::registry::instance().get(name);
38 | }
39 |
40 | inline void spdlog::drop(const std::string &name)
41 | {
42 | details::registry::instance().drop(name);
43 | }
44 |
45 | // Create multi/single threaded rotating file logger
46 | inline std::shared_ptr spdlog::rotating_logger_mt(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush)
47 | {
48 | return create(logger_name, filename, "txt", max_file_size, max_files, force_flush);
49 | }
50 |
51 | inline std::shared_ptr spdlog::rotating_logger_st(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush)
52 | {
53 | return create(logger_name, filename, "txt", max_file_size, max_files, force_flush);
54 | }
55 |
56 | // Create file logger which creates new file at midnight):
57 | inline std::shared_ptr spdlog::daily_logger_mt(const std::string& logger_name, const std::string& filename, bool force_flush)
58 | {
59 | return create(logger_name, filename, "txt", force_flush);
60 | }
61 | inline std::shared_ptr spdlog::daily_logger_st(const std::string& logger_name, const std::string& filename, bool force_flush)
62 | {
63 | return create(logger_name, filename, "txt", force_flush);
64 | }
65 |
66 |
67 | // Create stdout/stderr loggers
68 | inline std::shared_ptr spdlog::stdout_logger_mt(const std::string& logger_name)
69 | {
70 | return create(logger_name);
71 | }
72 |
73 | inline std::shared_ptr spdlog::stdout_logger_st(const std::string& logger_name)
74 | {
75 | return create(logger_name);
76 | }
77 |
78 | inline std::shared_ptr spdlog::stderr_logger_mt(const std::string& logger_name)
79 | {
80 | return create(logger_name);
81 | }
82 |
83 | inline std::shared_ptr spdlog::stderr_logger_st(const std::string& logger_name)
84 | {
85 | return create(logger_name);
86 | }
87 |
88 | #ifdef __linux__
89 | // Create syslog logger
90 | inline std::shared_ptr spdlog::syslog_logger(const std::string& logger_name, const std::string& syslog_ident, int syslog_option)
91 | {
92 | return create(logger_name, syslog_ident, syslog_option);
93 | }
94 | #endif
95 |
96 |
97 | //Create logger with multiple sinks
98 |
99 | inline std::shared_ptr spdlog::create(const std::string& logger_name, spdlog::sinks_init_list sinks)
100 | {
101 | return details::registry::instance().create(logger_name, sinks);
102 | }
103 |
104 |
105 | template
106 | inline std::shared_ptr spdlog::create(const std::string& logger_name, const Args&... args)
107 | {
108 | sink_ptr sink = std::make_shared(args...);
109 | return details::registry::instance().create(logger_name, { sink });
110 | }
111 |
112 |
113 | template
114 | inline std::shared_ptr spdlog::create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end)
115 | {
116 | return details::registry::instance().create(logger_name, sinks_begin, sinks_end);
117 | }
118 |
119 | inline void spdlog::set_formatter(spdlog::formatter_ptr f)
120 | {
121 | details::registry::instance().formatter(f);
122 | }
123 |
124 | inline void spdlog::set_pattern(const std::string& format_string)
125 | {
126 | return details::registry::instance().set_pattern(format_string);
127 | }
128 |
129 | inline void spdlog::set_level(level::level_enum log_level)
130 | {
131 | return details::registry::instance().set_level(log_level);
132 | }
133 |
134 |
135 | inline void spdlog::set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb)
136 | {
137 | details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb);
138 | }
139 |
140 | inline void spdlog::set_sync_mode()
141 | {
142 | details::registry::instance().set_sync_mode();
143 | }
144 |
145 | inline void spdlog::drop_all()
146 | {
147 | details::registry::instance().drop_all();
148 | }
149 |
150 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/formatter.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 | #pragma once
25 |
26 | #include "details/log_msg.h"
27 | namespace spdlog
28 | {
29 | namespace details
30 | {
31 | class flag_formatter;
32 | }
33 |
34 | class formatter
35 | {
36 | public:
37 | virtual ~formatter() {}
38 | virtual void format(details::log_msg& msg) = 0;
39 | };
40 |
41 | class pattern_formatter : public formatter
42 | {
43 |
44 | public:
45 | explicit pattern_formatter(const std::string& pattern);
46 | pattern_formatter(const pattern_formatter&) = delete;
47 | pattern_formatter& operator=(const pattern_formatter&) = delete;
48 | void format(details::log_msg& msg) override;
49 | private:
50 | const std::string _pattern;
51 | std::vector> _formatters;
52 | void handle_flag(char flag);
53 | void compile_pattern(const std::string& pattern);
54 | };
55 | }
56 |
57 | #include "details/pattern_formatter_impl.h"
58 |
59 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/logger.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 |
27 | // Thread safe logger
28 | // Has name, log level, vector of std::shared sink pointers and formatter
29 | // Upon each log write the logger:
30 | // 1. Checks if its log level is enough to log the message
31 | // 2. Format the message using the formatter function
32 | // 3. Pass the formatted message to its sinks to performa the actual logging
33 |
34 | #include
35 | #include
36 | #include "sinks/base_sink.h"
37 | #include "common.h"
38 |
39 | namespace spdlog
40 | {
41 |
42 | namespace details
43 | {
44 | class line_logger;
45 | }
46 |
47 | class logger
48 | {
49 | public:
50 | logger(const std::string& logger_name, sink_ptr single_sink);
51 | logger(const std::string& name, sinks_init_list);
52 | template
53 | logger(const std::string& name, const It& begin, const It& end);
54 |
55 | virtual ~logger();
56 | logger(const logger&) = delete;
57 | logger& operator=(const logger&) = delete;
58 |
59 | void set_level(level::level_enum);
60 | level::level_enum level() const;
61 |
62 | const std::string& name() const;
63 | bool should_log(level::level_enum) const;
64 |
65 | // logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
66 | template details::line_logger trace(const char* fmt, const Args&... args);
67 | template details::line_logger debug(const char* fmt, const Args&... args);
68 | template details::line_logger info(const char* fmt, const Args&... args);
69 | template details::line_logger notice(const char* fmt, const Args&... args);
70 | template details::line_logger warn(const char* fmt, const Args&... args);
71 | template details::line_logger error(const char* fmt, const Args&... args);
72 | template details::line_logger critical(const char* fmt, const Args&... args);
73 | template details::line_logger alert(const char* fmt, const Args&... args);
74 | template details::line_logger emerg(const char* fmt, const Args&... args);
75 |
76 |
77 | // logger.info(msg) << ".." call style
78 | template details::line_logger trace(const T&);
79 | template details::line_logger debug(const T&);
80 | template details::line_logger info(const T&);
81 | template details::line_logger notice(const T&);
82 | template details::line_logger warn(const T&);
83 | template details::line_logger error(const T&);
84 | template details::line_logger critical(const T&);
85 | template details::line_logger alert(const T&);
86 | template details::line_logger emerg(const T&);
87 |
88 |
89 | // logger.info() << ".." call style
90 | details::line_logger trace();
91 | details::line_logger debug();
92 | details::line_logger info();
93 | details::line_logger notice();
94 | details::line_logger warn();
95 | details::line_logger error();
96 | details::line_logger critical();
97 | details::line_logger alert();
98 | details::line_logger emerg();
99 |
100 |
101 |
102 | // Create log message with the given level, no matter what is the actual logger's level
103 | template
104 | details::line_logger force_log(level::level_enum lvl, const char* fmt, const Args&... args);
105 |
106 | // Set the format of the log messages from this logger
107 | void set_pattern(const std::string&);
108 | void set_formatter(formatter_ptr);
109 |
110 |
111 | protected:
112 | virtual void _log_msg(details::log_msg&);
113 | virtual void _set_pattern(const std::string&);
114 | virtual void _set_formatter(formatter_ptr);
115 | details::line_logger _log_if_enabled(level::level_enum lvl);
116 | template
117 | details::line_logger _log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args);
118 | template
119 | inline details::line_logger _log_if_enabled(level::level_enum lvl, const T& msg);
120 |
121 |
122 | friend details::line_logger;
123 | std::string _name;
124 | std::vector _sinks;
125 | formatter_ptr _formatter;
126 | std::atomic_int _level;
127 |
128 | };
129 | }
130 |
131 | #include "./details/logger_impl.h"
132 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/sinks/base_sink.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 | //
27 | // base sink templated over a mutex (either dummy or realy)
28 | // concrete implementation should only overrid the _sink_it method.
29 | // all locking is taken care of here so no locking needed by the implementors..
30 | //
31 |
32 | #include
33 | #include
34 | #include
35 | #include "./sink.h"
36 | #include "../formatter.h"
37 | #include "../common.h"
38 | #include "../details/log_msg.h"
39 |
40 |
41 | namespace spdlog
42 | {
43 | namespace sinks
44 | {
45 | template
46 | class base_sink:public sink
47 | {
48 | public:
49 | base_sink():_mutex() {}
50 | virtual ~base_sink() = default;
51 |
52 | base_sink(const base_sink&) = delete;
53 | base_sink& operator=(const base_sink&) = delete;
54 |
55 | void log(const details::log_msg& msg) override
56 | {
57 | std::lock_guard lock(_mutex);
58 | _sink_it(msg);
59 | }
60 |
61 |
62 | protected:
63 | virtual void _sink_it(const details::log_msg& msg) = 0;
64 | Mutex _mutex;
65 | };
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/sinks/file_sinks.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 |
27 | #include
28 | #include "base_sink.h"
29 | #include "../details/null_mutex.h"
30 | #include "../details/file_helper.h"
31 | #include "../details/format.h"
32 |
33 |
34 | namespace spdlog
35 | {
36 | namespace sinks
37 | {
38 |
39 | /*
40 | * Trivial file sink with single file as target
41 | */
42 | template
43 | class simple_file_sink : public base_sink
44 | {
45 | public:
46 | explicit simple_file_sink(const std::string &filename,
47 | bool force_flush=false):
48 | _file_helper(force_flush)
49 | {
50 | _file_helper.open(filename);
51 | }
52 |
53 | protected:
54 | void _sink_it(const details::log_msg& msg) override
55 | {
56 | _file_helper.write(msg);
57 | }
58 | private:
59 | details::file_helper _file_helper;
60 | };
61 |
62 | typedef simple_file_sink simple_file_sink_mt;
63 | typedef simple_file_sink simple_file_sink_st;
64 |
65 | /*
66 | * Rotating file sink based on size
67 | */
68 | template
69 | class rotating_file_sink : public base_sink
70 | {
71 | public:
72 | rotating_file_sink(const std::string &base_filename, const std::string &extension,
73 | std::size_t max_size, std::size_t max_files,
74 | bool force_flush=false):
75 | _base_filename(base_filename),
76 | _extension(extension),
77 | _max_size(max_size),
78 | _max_files(max_files),
79 | _current_size(0),
80 | _file_helper(force_flush)
81 | {
82 | _file_helper.open(calc_filename(_base_filename, 0, _extension));
83 | }
84 |
85 |
86 | protected:
87 | void _sink_it(const details::log_msg& msg) override
88 | {
89 | _current_size += msg.formatted.size();
90 | if (_current_size > _max_size)
91 | {
92 | _rotate();
93 | _current_size = msg.formatted.size();
94 | }
95 | _file_helper.write(msg);
96 | }
97 |
98 |
99 | private:
100 | static std::string calc_filename(const std::string& filename, std::size_t index, const std::string& extension)
101 | {
102 | details::fmt::MemoryWriter w;
103 | if (index)
104 | w.write("{}.{}.{}", filename, index, extension);
105 | else
106 | w.write("{}.{}", filename, extension);
107 | return w.str();
108 | }
109 |
110 |
111 | // Rotate files:
112 | // log.txt -> log.1.txt
113 | // log.1.txt -> log2.txt
114 | // log.2.txt -> log3.txt
115 | // log.3.txt -> delete
116 |
117 |
118 | void _rotate()
119 | {
120 | _file_helper.close();
121 | for (auto i = _max_files; i > 0; --i)
122 | {
123 | std::string src = calc_filename(_base_filename, i - 1, _extension);
124 | std::string target = calc_filename(_base_filename, i, _extension);
125 |
126 | if (details::file_helper::file_exists(target))
127 | {
128 | if (std::remove(target.c_str()) != 0)
129 | {
130 | throw spdlog_ex("rotating_file_sink: failed removing " + target);
131 | }
132 | }
133 | if (details::file_helper::file_exists(src) && std::rename(src.c_str(), target.c_str()))
134 | {
135 | throw spdlog_ex("rotating_file_sink: failed renaming " + src + " to " + target);
136 | }
137 | }
138 | _file_helper.reopen(true);
139 | }
140 | std::string _base_filename;
141 | std::string _extension;
142 | std::size_t _max_size;
143 | std::size_t _max_files;
144 | std::size_t _current_size;
145 | details::file_helper _file_helper;
146 | };
147 |
148 | typedef rotating_file_sink rotating_file_sink_mt;
149 | typedef rotating_file_sinkrotating_file_sink_st;
150 |
151 | /*
152 | * Rotating file sink based on date. rotates at midnight
153 | */
154 | template
155 | class daily_file_sink:public base_sink
156 | {
157 | public:
158 | explicit daily_file_sink(const std::string& base_filename,
159 | const std::string& extension,
160 | bool force_flush=false):
161 | _base_filename(base_filename),
162 | _extension(extension),
163 | _midnight_tp (_calc_midnight_tp() ),
164 | _file_helper(force_flush)
165 | {
166 | _file_helper.open(calc_filename(_base_filename, _extension));
167 | }
168 |
169 |
170 | protected:
171 | void _sink_it(const details::log_msg& msg) override
172 | {
173 | if (std::chrono::system_clock::now() >= _midnight_tp)
174 | {
175 | _file_helper.close();
176 | _file_helper.open(calc_filename(_base_filename, _extension));
177 | _midnight_tp = _calc_midnight_tp();
178 | }
179 | _file_helper.write(msg);
180 | }
181 |
182 | private:
183 | // Return next midnight's time_point
184 | static std::chrono::system_clock::time_point _calc_midnight_tp()
185 | {
186 | using namespace std::chrono;
187 | auto now = system_clock::now();
188 | time_t tnow = std::chrono::system_clock::to_time_t(now);
189 | tm date = spdlog::details::os::localtime(tnow);
190 | date.tm_hour = date.tm_min = date.tm_sec = 0;
191 | auto midnight = std::chrono::system_clock::from_time_t(std::mktime(&date));
192 | return system_clock::time_point(midnight + hours(24));
193 | }
194 |
195 | //Create filename for the form basename.YYYY-MM-DD.extension
196 | static std::string calc_filename(const std::string& basename, const std::string& extension)
197 | {
198 | std::tm tm = spdlog::details::os::localtime();
199 | details::fmt::MemoryWriter w;
200 | w.write("{}.{:04d}-{:02d}-{:02d}.{}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, extension);
201 | return w.str();
202 | }
203 |
204 | std::string _base_filename;
205 | std::string _extension;
206 | std::chrono::system_clock::time_point _midnight_tp;
207 | details::file_helper _file_helper;
208 |
209 | };
210 |
211 | typedef daily_file_sink daily_file_sink_mt;
212 | typedef daily_file_sink daily_file_sink_st;
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/sinks/null_sink.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 | #include
27 | #include "./base_sink.h"
28 | #include "../details/null_mutex.h"
29 |
30 |
31 | namespace spdlog
32 | {
33 | namespace sinks
34 | {
35 |
36 | template
37 | class null_sink : public base_sink < Mutex >
38 | {
39 | protected:
40 | void _sink_it(const details::log_msg&) override
41 | {}
42 |
43 | };
44 | typedef null_sink null_sink_st;
45 | typedef null_sink null_sink_mt;
46 |
47 | }
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/sinks/ostream_sink.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 |
27 | #include
28 | #include
29 | #include
30 |
31 | #include "../details/null_mutex.h"
32 | #include "./base_sink.h"
33 |
34 | namespace spdlog
35 | {
36 | namespace sinks
37 | {
38 | template
39 | class ostream_sink: public base_sink
40 | {
41 | public:
42 | explicit ostream_sink(std::ostream& os, bool force_flush=false) :_ostream(os), _force_flush(force_flush) {}
43 | ostream_sink(const ostream_sink&) = delete;
44 | ostream_sink& operator=(const ostream_sink&) = delete;
45 | virtual ~ostream_sink() = default;
46 |
47 | protected:
48 | virtual void _sink_it(const details::log_msg& msg) override
49 | {
50 | _ostream.write(msg.formatted.data(), msg.formatted.size());
51 | if (_force_flush)
52 | _ostream.flush();
53 | }
54 | std::ostream& _ostream;
55 | bool _force_flush;
56 | };
57 |
58 | typedef ostream_sink ostream_sink_mt;
59 | typedef ostream_sink ostream_sink_st;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/sinks/sink.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 |
27 | #include "../details/log_msg.h"
28 |
29 | namespace spdlog
30 | {
31 | namespace sinks
32 | {
33 | class sink
34 | {
35 | public:
36 | virtual ~sink() {}
37 | virtual void log(const details::log_msg& msg) = 0;
38 | };
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/include/thirdparty/spdlog/sinks/stdout_sinks.h:
--------------------------------------------------------------------------------
1 | /*************************************************************************/
2 | /* spdlog - an extremely fast and easy to use c++11 logging library. */
3 | /* Copyright (c) 2014 Gabi Melman. */
4 | /* */
5 | /* Permission is hereby granted, free of charge, to any person obtaining */
6 | /* a copy of this software and associated documentation files (the */
7 | /* "Software"), to deal in the Software without restriction, including */
8 | /* without limitation the rights to use, copy, modify, merge, publish, */
9 | /* distribute, sublicense, and/or sell copies of the Software, and to */
10 | /* permit persons to whom the Software is furnished to do so, subject to */
11 | /* the following conditions: */
12 | /* */
13 | /* The above copyright notice and this permission notice shall be */
14 | /* included in all copies or substantial portions of the Software. */
15 | /* */
16 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
17 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
18 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
19 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
20 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
21 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
22 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 | /*************************************************************************/
24 |
25 | #pragma once
26 |
27 | #include
28 | #include
29 | #include "./ostream_sink.h"
30 | #include "../details/null_mutex.h"
31 |
32 | namespace spdlog
33 | {
34 | namespace sinks
35 | {
36 |
37 | template
38 | class stdout_sink : public ostream_sink
39 | {
40 | public:
41 | stdout_sink() : ostream_sink(std::cout, true) {}
42 |
43 | };
44 |
45 | typedef stdout_sink stdout_sink_st;
46 | typedef stdout_sink stdout_sink_mt;
47 |
48 |
49 | template
50 | class stderr_sink : public ostream_sink
51 | {
52 | public:
53 | stderr_sink() : ostream_sink(std::cerr, true) {}
54 | };
55 |
56 | typedef stderr_sink