├── .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 | [![Build Status](https://travis-ci.org/LightIO/LightQ.svg?branch=master)](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 : [![Apache License](http://img.shields.io/badge/license-apache-blue.svg?style=flat)](LICENSE-Apache) 316 | 317 | 318 | Dependecies: 319 | ZeroMQ LGPL: [![ZeroMQ LGPL](http://img.shields.io/badge/license-lgpl-blue.svg?style=flat)](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 stderr_sink_mt; 57 | typedef stderr_sink stderr_sink_st; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /include/thirdparty/spdlog/sinks/syslog_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 | #ifdef __linux__ 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include "./sink.h" 34 | #include "../common.h" 35 | #include "../details/log_msg.h" 36 | 37 | 38 | namespace spdlog 39 | { 40 | namespace sinks 41 | { 42 | /** 43 | * Sink that write to syslog using the `syscall()` library call. 44 | * 45 | * Locking is not needed, as `syslog()` itself is thread-safe. 46 | */ 47 | class syslog_sink : public sink 48 | { 49 | public: 50 | // 51 | syslog_sink(const std::string& ident = "", int syslog_option=0, int syslog_facility=LOG_USER): 52 | _ident(ident) 53 | { 54 | _priorities[static_cast(level::trace)] = LOG_DEBUG; 55 | _priorities[static_cast(level::debug)] = LOG_DEBUG; 56 | _priorities[static_cast(level::info)] = LOG_INFO; 57 | _priorities[static_cast(level::notice)] = LOG_NOTICE; 58 | _priorities[static_cast(level::warn)] = LOG_WARNING; 59 | _priorities[static_cast(level::err)] = LOG_ERR; 60 | _priorities[static_cast(level::critical)] = LOG_CRIT; 61 | _priorities[static_cast(level::alert)] = LOG_ALERT; 62 | _priorities[static_cast(level::emerg)] = LOG_EMERG; 63 | _priorities[static_cast(level::off)] = LOG_INFO; 64 | 65 | //set ident to be program name if empty 66 | ::openlog(_ident.empty()? nullptr:_ident.c_str(), syslog_option, syslog_facility); 67 | } 68 | ~syslog_sink() 69 | { 70 | ::closelog(); 71 | } 72 | 73 | syslog_sink(const syslog_sink&) = delete; 74 | syslog_sink& operator=(const syslog_sink&) = delete; 75 | 76 | void log(const details::log_msg &msg) override 77 | { 78 | ::syslog(syslog_prio_from_level(msg), "%s", msg.formatted.str().c_str()); 79 | } 80 | 81 | 82 | 83 | private: 84 | std::array _priorities; 85 | //must store the ident because the man says openlog might use the pointer as is and not a string copy 86 | const std::string _ident; 87 | 88 | // 89 | // Simply maps spdlog's log level to syslog priority level. 90 | // 91 | int syslog_prio_from_level(const details::log_msg &msg) const 92 | { 93 | return _priorities[static_cast(msg.level)]; 94 | } 95 | }; 96 | } 97 | } 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /include/thirdparty/spdlog/spdlog.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 | 26 | // spdlog main header file. 27 | //see example.cpp for usage example 28 | 29 | #pragma once 30 | 31 | 32 | 33 | #include "common.h" 34 | #include "logger.h" 35 | 36 | 37 | 38 | namespace spdlog 39 | { 40 | 41 | // Return an existing logger or nullptr if a logger with such name doesn't exist. 42 | // Examples: 43 | // 44 | // spdlog::get("mylog")->info("Hello"); 45 | // auto logger = spdlog::get("mylog"); 46 | // logger.info("This is another message" , x, y, z); 47 | // logger.info() << "This is another message" << x << y << z; 48 | std::shared_ptr get(const std::string& name); 49 | 50 | // 51 | // Set global formatting 52 | // example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v"); 53 | // 54 | void set_pattern(const std::string& format_string); 55 | void set_formatter(formatter_ptr f); 56 | 57 | // 58 | // Set global logging level for 59 | // 60 | void set_level(level::level_enum log_level); 61 | 62 | // 63 | // Turn on async mode (off by default) and set the queue size for each async_logger. 64 | // effective only for loggers created after this call. 65 | // queue_size: size of queue (must be power of 2): 66 | // Each logger will pre-allocate a dedicated queue with queue_size entries upon construction. 67 | // 68 | // async_overflow_policy (optional, block_retry by default): 69 | // async_overflow_policy::block_retry - if queue is full, block until queue has room for the new log entry. 70 | // async_overflow_policy::discard_log_msg - never block and discard any new messages when queue overflows. 71 | // 72 | // worker_warmup_cb (optional): 73 | // callback function that will be called in worker thread upon start (can be used to init stuff like thread affinity) 74 | // 75 | void set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, const std::function& worker_warmup_cb = nullptr); 76 | 77 | // Turn off async mode 78 | void set_sync_mode(); 79 | 80 | // 81 | // Create multi/single threaded rotating file logger 82 | // 83 | std::shared_ptr rotating_logger_mt(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush = false); 84 | std::shared_ptr rotating_logger_st(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush = false); 85 | 86 | // 87 | // Create file logger which creates new file at midnight): 88 | // 89 | std::shared_ptr daily_logger_mt(const std::string& logger_name, const std::string& filename, bool force_flush = false); 90 | std::shared_ptr daily_logger_st(const std::string& logger_name, const std::string& filename, bool force_flush = false); 91 | 92 | 93 | // 94 | // Create stdout/stderr loggers 95 | // 96 | std::shared_ptr stdout_logger_mt(const std::string& logger_name); 97 | std::shared_ptr stdout_logger_st(const std::string& logger_name); 98 | std::shared_ptr stderr_logger_mt(const std::string& logger_name); 99 | std::shared_ptr stderr_logger_st(const std::string& logger_name); 100 | 101 | 102 | // 103 | // Create a syslog logger 104 | // 105 | #ifdef __linux__ 106 | std::shared_ptr syslog_logger(const std::string& logger_name, const std::string& ident = "", int syslog_option = 0); 107 | #endif 108 | 109 | 110 | // Create a logger with multiple sinks 111 | std::shared_ptr create(const std::string& logger_name, sinks_init_list sinks); 112 | template 113 | std::shared_ptr create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end); 114 | 115 | 116 | // Create a logger with templated sink type 117 | // Example: spdlog::create("mylog", "dailylog_filename", "txt"); 118 | template 119 | std::shared_ptr create(const std::string& logger_name, const Args&...); 120 | 121 | // 122 | // Trace & debug macros to be switched on/off at compile time for zero cost debug statements. 123 | // Note: using these mactors overrides the runtime log threshold of the logger. 124 | // 125 | // Example: 126 | // 127 | // Enable debug macro, must be defined before including spdlog.h 128 | // #define SPDLOG_DEBUG_ON 129 | // include "spdlog/spdlog.h" 130 | // SPDLOG_DEBUG(my_logger, "Some debug message {} {}", 1, 3.2); 131 | // 132 | 133 | #ifdef SPDLOG_TRACE_ON 134 | #define SPDLOG_TRACE(logger, ...) logger->force_log(spdlog::level::trace, __VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")"; 135 | #else 136 | #define SPDLOG_TRACE(logger, ...) 137 | #endif 138 | 139 | 140 | #ifdef SPDLOG_DEBUG_ON 141 | #define SPDLOG_DEBUG(logger, ...) logger->force_log(spdlog::level::debug, __VA_ARGS__) 142 | #else 143 | #define SPDLOG_DEBUG(logger, ...) 144 | #endif 145 | 146 | 147 | 148 | // Drop the reference to the given logger 149 | void drop(const std::string &name); 150 | 151 | // Drop all references 152 | void drop_all(); 153 | 154 | } 155 | 156 | 157 | #include "details/spdlog_impl.h" 158 | -------------------------------------------------------------------------------- /include/thirdparty/zhelpers.hpp: -------------------------------------------------------------------------------- 1 | /* ========================================================================= 2 | zhelpers.h - ZeroMQ helpers for example applications 3 | 4 | Copyright (c) 1991-2010 iMatix Corporation and contributors 5 | 6 | This is free software; you can redistribute it and/or modify it under 7 | the terms of the Lesser GNU General Public License as published by 8 | the Free Software Foundation; either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This software is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | Lesser GNU General Public License for more details. 15 | 16 | You should have received a copy of the Lesser GNU General Public License 17 | along with this program. If not, see . 18 | ========================================================================= 19 | */ 20 | 21 | // Olivier Chamoux 22 | 23 | 24 | #ifndef __ZHELPERS_HPP_INCLUDED__ 25 | #define __ZHELPERS_HPP_INCLUDED__ 26 | 27 | // Include a bunch of headers that we will need in the examples 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #if (!defined(_WIN32)) 37 | #include 38 | #include 39 | #include 40 | #endif 41 | #include 42 | #include 43 | #include // random() RAND_MAX 44 | #include 45 | #include 46 | #include 47 | 48 | // Bring Windows MSVC up to C99 scratch 49 | #if (defined (_WIN32)) 50 | typedef unsigned long ulong; 51 | typedef unsigned int uint; 52 | typedef __int64 int64_t; 53 | #endif 54 | 55 | // Provide random number from 0..(num-1) 56 | #if (!defined(_WIN32)) 57 | #define within(num) (int) ((float) (num) * random () / (RAND_MAX + 1.0)) 58 | #else 59 | #define within(num) (int) ((float) (num) * rand () / (RAND_MAX + 1.0)) 60 | #endif 61 | 62 | 63 | // Receive 0MQ string from socket and convert into string 64 | static std::string 65 | s_recv (zmq::socket_t & socket) { 66 | 67 | zmq::message_t message; 68 | socket.recv(&message); 69 | return std::string(static_cast(message.data()), message.size()); 70 | } 71 | 72 | 73 | unsigned s_recv (zmq::socket_t & socket, std::string& buffer) { 74 | 75 | zmq::message_t message; 76 | socket.recv(&message); 77 | buffer.clear(); 78 | buffer.assign(static_cast(message.data()), message.size()); 79 | 80 | return message.size(); 81 | } 82 | 83 | // Convert string to 0MQ string and send to socket 84 | static bool 85 | s_send (zmq::socket_t & socket, const std::string & string, bool zerocopy=false) { 86 | if(zerocopy) { 87 | zmq::message_t message((void *)string.data(), string.size(), NULL, NULL); 88 | return socket.send (message); 89 | }else { 90 | zmq::message_t message(string.size()); 91 | memcpy (message.data(),string.data(), string.size()); 92 | return socket.send (message); 93 | } 94 | 95 | } 96 | 97 | 98 | static bool 99 | s_send (zmq::socket_t & socket, const char* buffer, unsigned length, bool zerocopy=false) { 100 | if(zerocopy) { 101 | zmq::message_t message((void *)buffer, length, NULL, NULL); 102 | return socket.send (message); 103 | }else { 104 | zmq::message_t message(length); 105 | memcpy (message.data(),buffer, length); 106 | return socket.send (message); 107 | } 108 | } 109 | 110 | // Sends string as 0MQ string, as multipart non-terminal 111 | static bool 112 | s_sendmore (zmq::socket_t & socket, const std::string & string, bool zerocopy=false) { 113 | 114 | zmq::message_t *pmessage = NULL; 115 | if(zerocopy) { 116 | zmq::message_t message ((void *)string.c_str(), string.length(), NULL, NULL); 117 | return socket.send (message, ZMQ_SNDMORE); 118 | }else { 119 | zmq::message_t message(string.size()); 120 | memcpy (message.data(), string.data(), string.size()); 121 | return socket.send (message, ZMQ_SNDMORE); 122 | } 123 | 124 | } 125 | 126 | // Receives all message parts from socket, prints neatly 127 | // 128 | static void 129 | s_dump (zmq::socket_t & socket) 130 | { 131 | std::cout << "----------------------------------------" << std::endl; 132 | 133 | while (1) { 134 | // Process all parts of the message 135 | zmq::message_t message; 136 | socket.recv(&message); 137 | 138 | // Dump the message as text or binary 139 | int size = message.size(); 140 | std::string data(static_cast(message.data()), size); 141 | 142 | bool is_text = true; 143 | 144 | int char_nbr; 145 | unsigned char byte; 146 | for (char_nbr = 0; char_nbr < size; char_nbr++) { 147 | byte = data [char_nbr]; 148 | if (byte < 32 || byte > 127) 149 | is_text = false; 150 | } 151 | std::cout << "[" << std::setfill('0') << std::setw(3) << size << "]"; 152 | for (char_nbr = 0; char_nbr < size; char_nbr++) { 153 | if (is_text) 154 | std::cout << (char)data [char_nbr]; 155 | else 156 | std::cout << std::setfill('0') << std::setw(2) 157 | << std::hex << (unsigned int) data [char_nbr]; 158 | } 159 | std::cout << std::endl; 160 | 161 | int more = 0; // Multipart detection 162 | size_t more_size = sizeof (more); 163 | socket.getsockopt (ZMQ_RCVMORE, &more, &more_size); 164 | if (!more) 165 | break; // Last message part 166 | } 167 | } 168 | 169 | // Set simple random printable identity on socket 170 | // 171 | inline std::string 172 | s_set_id (zmq::socket_t & socket) 173 | { 174 | std::stringstream ss; 175 | ss << std::hex << std::uppercase 176 | << std::setw(4) << std::setfill('0') << within (0x10000) << "-" 177 | << std::setw(4) << std::setfill('0') << within (0x10000); 178 | socket.setsockopt(ZMQ_IDENTITY, ss.str().c_str(), ss.str().length()); 179 | return ss.str(); 180 | } 181 | 182 | // Report 0MQ version number 183 | // 184 | static void 185 | s_version (void) 186 | { 187 | int major, minor, patch; 188 | zmq_version (&major, &minor, &patch); 189 | std::cout << "Current 0MQ version is " << major << "." << minor << "." << patch << std::endl; 190 | } 191 | 192 | static void 193 | s_version_assert (int want_major, int want_minor) 194 | { 195 | int major, minor, patch; 196 | zmq_version (&major, &minor, &patch); 197 | if (major < want_major 198 | || (major == want_major && minor < want_minor)) { 199 | std::cout << "Current 0MQ version is " << major << "." << minor << std::endl; 200 | std::cout << "Application needs at least " << want_major << "." << want_minor 201 | << " - cannot continue" << std::endl; 202 | exit (EXIT_FAILURE); 203 | } 204 | } 205 | 206 | // Return current system clock as milliseconds 207 | static int64_t 208 | s_clock (void) 209 | { 210 | #if (defined (_WIN32)) 211 | FILETIME fileTime; 212 | GetSystemTimeAsFileTime(&fileTime); 213 | unsigned __int64 largeInt = fileTime.dwHighDateTime; 214 | largeInt <<= 32; 215 | largeInt |= fileTime.dwLowDateTime; 216 | largeInt /= 10000; // FILETIME is in units of 100 nanoseconds 217 | return (int64_t)largeInt; 218 | #else 219 | struct timeval tv; 220 | gettimeofday (&tv, NULL); 221 | return (int64_t) (tv.tv_sec * 1000 + tv.tv_usec / 1000); 222 | #endif 223 | } 224 | 225 | // Sleep for a number of milliseconds 226 | static void 227 | s_sleep (int msecs) 228 | { 229 | #if (defined (_WIN32)) 230 | Sleep (msecs); 231 | #else 232 | struct timespec t; 233 | t.tv_sec = msecs / 1000; 234 | t.tv_nsec = (msecs % 1000) * 1000000; 235 | nanosleep (&t, NULL); 236 | #endif 237 | } 238 | 239 | static void 240 | s_console (const char *format, ...) 241 | { 242 | time_t curtime = time (NULL); 243 | struct tm *loctime = localtime (&curtime); 244 | char *formatted = new char[20]; 245 | strftime (formatted, 20, "%y-%m-%d %H:%M:%S ", loctime); 246 | printf ("%s", formatted); 247 | delete[] formatted; 248 | 249 | va_list argptr; 250 | va_start (argptr, format); 251 | vprintf (format, argptr); 252 | va_end (argptr); 253 | printf ("\n"); 254 | } 255 | 256 | // --------------------------------------------------------------------- 257 | // Signal handling 258 | // 259 | // Call s_catch_signals() in your application at startup, and then exit 260 | // your main loop if s_interrupted is ever 1. Works especially well with 261 | // zmq_poll. 262 | 263 | static int s_interrupted = 0; 264 | static void s_signal_handler (int signal_value) 265 | { 266 | s_interrupted = 1; 267 | } 268 | 269 | static void s_catch_signals () 270 | { 271 | #if (!defined(_WIN32)) 272 | struct sigaction action; 273 | action.sa_handler = s_signal_handler; 274 | action.sa_flags = 0; 275 | sigemptyset (&action.sa_mask); 276 | sigaction (SIGINT, &action, NULL); 277 | sigaction (SIGTERM, &action, NULL); 278 | #endif 279 | } 280 | 281 | #endif 282 | --------------------------------------------------------------------------------