├── .travis.yml ├── LICENSE ├── README.md ├── config ├── docs └── nginx-zmq ├── src ├── ngx_http_log_zmq.c ├── ngx_http_log_zmq.h ├── ngx_http_log_zmq_module.c └── ngx_http_log_zmq_module.h └── valgrind.supp /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | compiler: 3 | - gcc 4 | - clang 5 | 6 | env: 7 | - VER_NGINX=1.6.3 8 | - VER_NGINX=1.8.1 9 | - VER_NGINX=1.9.12 10 | 11 | sudo: false 12 | 13 | addons: 14 | apt: 15 | packages: 16 | - libzmq3-dev 17 | 18 | install: 19 | - mkdir ./vendor && cd ./vendor 20 | - wget "http://nginx.org/download/nginx-${VER_NGINX}.tar.gz" && tar -xf "nginx-${VER_NGINX}.tar.gz" 21 | 22 | - cd nginx-${VER_NGINX} 23 | - ./configure --add-module=../.. 24 | 25 | script: make 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015 SAPO - PT Comunicações S.A 4 | Copyright (c) 2016 Altice Labs 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | nginx-log-zmq 2 | ============= 3 | 4 | ZeroMQ logger module for nginx. 5 | 6 | [ZeroMQ](http://zeromq.org), \zero-em-queue\, is a protocol for messages exchange. It's a easy 7 | way to communicate using any language or platform via inproc, IPC, TCP, TPIC or multicast. 8 | It's asynchronous and only requires a small library. 9 | 10 | _This module is not distributed with the nginx source._ See the [installation instructions](#installation). 11 | 12 | [![Build Status](https://travis-ci.org/alticelabs/nginx-log-zmq.svg?branch=master)](https://travis-ci.org/alticelabs/nginx-log-zmq) 13 | 14 | Table of Contents 15 | ================= 16 | 17 | * [Status](#status) 18 | * [Description](#description) 19 | * [Synopsis](#synopsis) 20 | * [Directives](#directives) 21 | * [log_zmq_server](#log_zmq_server) 22 | * [log_zmq_endpoint](#log_zmq_endpoint) 23 | * [log_zmq_format](#log_zmq_format) 24 | * [log_zmq_off](#log_zmq_off) 25 | * [Installation](#installation) 26 | * [Compatibility](#compatibility) 27 | * [Report Bugs](#report-bugs) 28 | * [Authors](#authors) 29 | * [Copyright & Licence](#copyright--licence) 30 | 31 | Status 32 | ====== 33 | 34 | This module is already production ready. 35 | 36 | Description 37 | =========== 38 | 39 | This is a nginx logger module integrated with [ZeroMQ](http://zeromq.org) library. 40 | 41 | `nginx-log-zmq` provides a very efficient way to log data for one or more PUB/SUB subscribers, over one or more different endpoints. This can be useful for data gathering and processing. 42 | 43 | The message format can be the same as the tradicional log format which gives a interesting way to `tail` data via the network or exploring other text formats like JSON. As with the traditional log, it's possible to use nginx variables updated each request. 44 | 45 | All messages are sent asynchronously and do not block the normal behaviour of the nginx server. As expected, the connections are resilient to network failures. 46 | 47 | Synopsis 48 | ======== 49 | 50 | ``` 51 | http { 52 | # simple message to an IPC endpoint with 4 threads and 1000 queue elements 53 | 54 | log_zmq_server main "/tmp/main.ipc" ipc 4 1000; 55 | log_zmq_endpoint main "/topic/"; 56 | 57 | log_zmq_format main '{"remote_addr":"$remote_addr"}' 58 | 59 | # send messages to a subscriber listening at 127.0.0.1:5556 60 | 61 | log_zmq_server secondary 127.0.0.1:5556 tcp 4 1000; 62 | 63 | # set secondary endpoint 64 | log_zmq_endpoint secondary "/endpoint/"; 65 | 66 | # set format using multiline 67 | log_zmq_format secondary '{"request_uri":"$request_uri",' 68 | '{"status":"$status"}'; 69 | 70 | 71 | server { 72 | 73 | location /status { 74 | # mute all messages from log_zmq for this location 75 | 76 | log_zmq_off all; 77 | } 78 | 79 | location /endpoint { 80 | # mute main messages from log_zmq for this location 81 | 82 | log_zmq_off main; 83 | } 84 | } 85 | } 86 | ``` 87 | 88 | Directives 89 | ========== 90 | 91 | log_zmq_server 92 | ---------------- 93 | **syntax:** *log_zmq_server <definition_name> <address> <ipc|tcp> <threads> <queue size>* 94 | 95 | **default:** no 96 | 97 | **context:** http 98 | 99 | Configures a server (PUB/SUB subscriber) to connect to. 100 | 101 | The following options are required: 102 | 103 | **definition_name** <name> - the name that nginx will use to identify this logger instance. 104 | 105 | **address** <path>|<ipaddress>:<port> - the subscriber's address. If you are using the IPC 106 | protocol, you should specify the `` for the unix socket. If you are using the TCP 107 | protocol, you should specify the `` and `` where your ZeroMQ subscriber is listening. 108 | 109 | **protocol** <ipc|tcp> - the protocol to be used for communication. 110 | 111 | **threads** <integer> - the number of I/O threads to be used. 112 | 113 | **queue_size** <integer> - the maximum queue size for messages waiting to be sent. 114 | 115 | [Back to TOC](#table-of-contents) 116 | 117 | log_zmq_endpoint 118 | ------------------ 119 | 120 | **syntax:** *log_zmq_endpoint <definition_name> "<topic>"* 121 | 122 | **default:** no 123 | 124 | **context:** http 125 | 126 | Configures the topic for the ZeroMQ messages. 127 | 128 | **definition_name** <name> - the name that nginx will use to identify this logger instance. 129 | 130 | **topic** <topic> - the topic for the messages. This is a string (which can be a nginx variable) prepended to every sent message. For example, if you send the message "hello" to the "/talk:" topic, the message will end up as "/talk:hello". 131 | 132 | Example: 133 | 134 | ``` 135 | http { 136 | log_zmq_server main "/tmp/example.ipc" 4 1000; 137 | 138 | # send a message for for an topic based on response status 139 | log_zmq_endpoint main "/remote/$status"; 140 | } 141 | ``` 142 | 143 | [Back to TOC](#table-of-contents) 144 | 145 | log_zmq_format 146 | ---------------- 147 | 148 | **syntax:** *log_zmq_format <definition_name> "<format>"* 149 | 150 | **default:** no 151 | 152 | **context:** http 153 | 154 | Configures the ZeroMQ message format. 155 | 156 | **definition_name** <name> - the name that nginx will use to identify this logger instance. 157 | 158 | **format** <format> - the format for the messages. This defines the actual messages sent to the PUB/SUB subscriber. It follows the sames rules as the standard `log_format` directive. It is possible to use nginx variables here, and also to break it over multiple lines. 159 | 160 | ``` 161 | http { 162 | log_zmq_format main '{"line1": value,' 163 | '{"line2": value}'; 164 | } 165 | ``` 166 | 167 | [Back to TOC](#table-of-contents) 168 | 169 | log_zmq_off 170 | ------------- 171 | 172 | **syntax:** *log_zmq_off <definition_name>|all* 173 | 174 | **default:** no 175 | 176 | **context:** location 177 | 178 | Turn off ZeroMQ logging in the current context. 179 | 180 | **definition_name** <name> the name of the logger instance to be muted. If the special `all` name is used, all logger instances are muted. 181 | 182 | [Back to TOC](#table-of-contents) 183 | 184 | Installation 185 | ============ 186 | 187 | To build a nginx binary containting this module: 188 | 189 | * Download the latest version of this module from [GitHub](http://github.com/danielfbento/nginx-log-zmq/). 190 | * Grab the nginx source code from [nginx.org](http://www.nginx.org), for example, version 1.6.2 (see [nginx compatibility](#compatibility)), and then build it like so: 191 | 192 | ``` 193 | ./configure --prefix=/usr/local/nginx --add-module=/path/to/nginx-log-zmq 194 | 195 | make 196 | make install 197 | ``` 198 | 199 | [Back to TOC](#table-of-contents) 200 | 201 | Compatibility 202 | =========== 203 | 204 | The following versions of nginx are known to work with this module: 205 | 206 | * 1.8.0 207 | * 1.6.x (last tested: 1.6.2) 208 | * 1.5.x 209 | * 1.4.x (last tested: 1.4.4) 210 | 211 | [Back to TOC](#table-of-contents) 212 | 213 | Report Bugs 214 | =========== 215 | 216 | Bug reports, wishlists, or patches are welcome. You can submit them on our [GitHub repository](http://github.com/danielfbento/nginx-log-zmq/). 217 | 218 | [Back to TOC](#table-of-contents) 219 | 220 | Authors 221 | ======= 222 | 223 | * Dani Bento <dani@telecom.pt> 224 | 225 | [Back to TOC](#table-of-contents) 226 | 227 | Copyright & Licence 228 | =================== 229 | 230 | The MIT License (MIT) 231 | 232 | Copyright (c) 2014-2015 SAPO - PT Comunicações S.A 233 | Copyright (c) 2016 Altice Labs 234 | 235 | Permission is hereby granted, free of charge, to any person obtaining a copy 236 | of this software and associated documentation files (the "Software"), to deal 237 | in the Software without restriction, including without limitation the rights 238 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 239 | copies of the Software, and to permit persons to whom the Software is 240 | furnished to do so, subject to the following conditions: 241 | 242 | The above copyright notice and this permission notice shall be included in all 243 | copies or substantial portions of the Software. 244 | 245 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 246 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 247 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 248 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 249 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 250 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 251 | SOFTWARE. 252 | 253 | [Back to TOC](#table-of-contents) 254 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_feature_name= 2 | ngx_feature_run=yes 3 | ngx_feature_incs="#include " 4 | ngx_feature_test="if (ZMQ_VERSION < 20100) { return 1; }" 5 | 6 | if [ -n "$LIBZMQ_INC" -o -n "$LIBZMQ_LIB" ]; then 7 | # specified by LIBZMQ_INC and/or LIBZMQ_LIB 8 | ngx_feature="ZeroMQ library in directories specified by LIBZMQ_INC ($LIBZMQ_INC) and/or LIBZMQ_LIB ($LIBZMQ_LIB)" 9 | ngx_feature_path="$LIBZMQ_INC" 10 | if [ $NGX_RPATH = YES ]; then 11 | ngx_feature_libs="-R$LIBZMQ_LIB -L$LIBZMQ_LIB -lzmq" 12 | else 13 | ngx_feature_libs="-L$LIBZMQ_LIB -lzmq" 14 | fi 15 | . auto/feature 16 | else 17 | ngx_feature="ZeroMQ library" 18 | ngx_feature_path= 19 | ngx_feature_libs="-lzmq" 20 | . auto/feature 21 | fi 22 | 23 | if [ $ngx_found = no ]; then 24 | echo "$0: error: requires libzmq" 25 | exit 1 26 | fi 27 | 28 | ngx_addon_name="ngx_http_log_zmq_module" 29 | 30 | CORE_INCS="$CORE_INCS $ngx_feature_path $ngx_addon_dir/src" 31 | CORE_LIBS="$CORE_LIBS $ngx_feature_libs" 32 | 33 | ZMQ_MODULE="$ngx_addon_name" 34 | 35 | ZMQ_SRCS=" \ 36 | $ngx_addon_dir/src/ngx_http_log_zmq_module.c \ 37 | $ngx_addon_dir/src/ngx_http_log_zmq.c \ 38 | " 39 | 40 | ZMQ_DEPS=" \ 41 | $ngx_addon_dir/src/ngx_http_log_zmq_module.h \ 42 | $ngx_addon_dir/src/ngx_http_log_zmq.h \ 43 | " 44 | 45 | ngx_module_incs=$ngx_addon_dir 46 | ngx_module_deps=$ZMQ_DEPS 47 | ngx_module_libs= 48 | 49 | if [ "$ngx_module_link" = "DYNAMIC" ]; then 50 | ngx_module_type=MISC 51 | ngx_module_name="$ZMQ_MODULE" 52 | ngx_module_srcs="$ZMQ_SRCS" 53 | 54 | . auto/module 55 | 56 | elif [ "$ngx_module_link" = "YES" ]; then 57 | ngx_module_type=HTTP 58 | ngx_module_name="$ZMQ_MODULE" 59 | ngx_module_incs= 60 | ngx_module_deps= 61 | ngx_module_srcs="$ZMQ_SRCS" 62 | 63 | . auto/module 64 | 65 | fi 66 | -------------------------------------------------------------------------------- /docs/nginx-zmq: -------------------------------------------------------------------------------- 1 | # Doxyfile 1.7.6.1 2 | 3 | # This file describes the settings to be used by the documentation system 4 | # doxygen (www.doxygen.org) for a project. 5 | # 6 | # All text after a hash (#) is considered a comment and will be ignored. 7 | # The format is: 8 | # TAG = value [value, ...] 9 | # For lists items can also be appended using: 10 | # TAG += value [value, ...] 11 | # Values that contain spaces should be placed between quotes (" "). 12 | 13 | #--------------------------------------------------------------------------- 14 | # Project related configuration options 15 | #--------------------------------------------------------------------------- 16 | 17 | # This tag specifies the encoding used for all characters in the config file 18 | # that follow. The default is UTF-8 which is also the encoding used for all 19 | # text before the first occurrence of this tag. Doxygen uses libiconv (or the 20 | # iconv built into libc) for the transcoding. See 21 | # http://www.gnu.org/software/libiconv for the list of possible encodings. 22 | 23 | DOXYFILE_ENCODING = UTF-8 24 | 25 | # The PROJECT_NAME tag is a single word (or sequence of words) that should 26 | # identify the project. Note that if you do not use Doxywizard you need 27 | # to put quotes around the project name if it contains spaces. 28 | 29 | PROJECT_NAME = "nginx ZMQ" 30 | 31 | # The PROJECT_NUMBER tag can be used to enter a project or revision number. 32 | # This could be handy for archiving the generated documentation or 33 | # if some version control system is used. 34 | 35 | PROJECT_NUMBER = 36 | 37 | # Using the PROJECT_BRIEF tag one can provide an optional one line description 38 | # for a project that appears at the top of each page and should give viewer 39 | # a quick idea about the purpose of the project. Keep the description short. 40 | 41 | PROJECT_BRIEF = 42 | 43 | # With the PROJECT_LOGO tag one can specify an logo or icon that is 44 | # included in the documentation. The maximum height of the logo should not 45 | # exceed 55 pixels and the maximum width should not exceed 200 pixels. 46 | # Doxygen will copy the logo to the output directory. 47 | 48 | PROJECT_LOGO = 49 | 50 | # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 51 | # base path where the generated documentation will be put. 52 | # If a relative path is entered, it will be relative to the location 53 | # where doxygen was started. If left blank the current directory will be used. 54 | 55 | OUTPUT_DIRECTORY = docs 56 | 57 | # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 58 | # 4096 sub-directories (in 2 levels) under the output directory of each output 59 | # format and will distribute the generated files over these directories. 60 | # Enabling this option can be useful when feeding doxygen a huge amount of 61 | # source files, where putting all generated files in the same directory would 62 | # otherwise cause performance problems for the file system. 63 | 64 | CREATE_SUBDIRS = NO 65 | 66 | # The OUTPUT_LANGUAGE tag is used to specify the language in which all 67 | # documentation generated by doxygen is written. Doxygen will use this 68 | # information to generate all constant output in the proper language. 69 | # The default language is English, other supported languages are: 70 | # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 71 | # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, 72 | # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English 73 | # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, 74 | # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, 75 | # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. 76 | 77 | OUTPUT_LANGUAGE = English 78 | 79 | # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 80 | # include brief member descriptions after the members that are listed in 81 | # the file and class documentation (similar to JavaDoc). 82 | # Set to NO to disable this. 83 | 84 | BRIEF_MEMBER_DESC = YES 85 | 86 | # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 87 | # the brief description of a member or function before the detailed description. 88 | # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 89 | # brief descriptions will be completely suppressed. 90 | 91 | REPEAT_BRIEF = YES 92 | 93 | # This tag implements a quasi-intelligent brief description abbreviator 94 | # that is used to form the text in various listings. Each string 95 | # in this list, if found as the leading text of the brief description, will be 96 | # stripped from the text and the result after processing the whole list, is 97 | # used as the annotated text. Otherwise, the brief description is used as-is. 98 | # If left blank, the following values are used ("$name" is automatically 99 | # replaced with the name of the entity): "The $name class" "The $name widget" 100 | # "The $name file" "is" "provides" "specifies" "contains" 101 | # "represents" "a" "an" "the" 102 | 103 | ABBREVIATE_BRIEF = 104 | 105 | # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 106 | # Doxygen will generate a detailed section even if there is only a brief 107 | # description. 108 | 109 | ALWAYS_DETAILED_SEC = NO 110 | 111 | # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 112 | # inherited members of a class in the documentation of that class as if those 113 | # members were ordinary class members. Constructors, destructors and assignment 114 | # operators of the base classes will not be shown. 115 | 116 | INLINE_INHERITED_MEMB = NO 117 | 118 | # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 119 | # path before files name in the file list and in the header files. If set 120 | # to NO the shortest path that makes the file name unique will be used. 121 | 122 | FULL_PATH_NAMES = YES 123 | 124 | # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 125 | # can be used to strip a user-defined part of the path. Stripping is 126 | # only done if one of the specified strings matches the left-hand part of 127 | # the path. The tag can be used to show relative paths in the file list. 128 | # If left blank the directory from which doxygen is run is used as the 129 | # path to strip. 130 | 131 | STRIP_FROM_PATH = 132 | 133 | # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 134 | # the path mentioned in the documentation of a class, which tells 135 | # the reader which header file to include in order to use a class. 136 | # If left blank only the name of the header file containing the class 137 | # definition is used. Otherwise one should specify the include paths that 138 | # are normally passed to the compiler using the -I flag. 139 | 140 | STRIP_FROM_INC_PATH = 141 | 142 | # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 143 | # (but less readable) file names. This can be useful if your file system 144 | # doesn't support long names like on DOS, Mac, or CD-ROM. 145 | 146 | SHORT_NAMES = NO 147 | 148 | # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 149 | # will interpret the first line (until the first dot) of a JavaDoc-style 150 | # comment as the brief description. If set to NO, the JavaDoc 151 | # comments will behave just like regular Qt-style comments 152 | # (thus requiring an explicit @brief command for a brief description.) 153 | 154 | JAVADOC_AUTOBRIEF = NO 155 | 156 | # If the QT_AUTOBRIEF tag is set to YES then Doxygen will 157 | # interpret the first line (until the first dot) of a Qt-style 158 | # comment as the brief description. If set to NO, the comments 159 | # will behave just like regular Qt-style comments (thus requiring 160 | # an explicit \brief command for a brief description.) 161 | 162 | QT_AUTOBRIEF = NO 163 | 164 | # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 165 | # treat a multi-line C++ special comment block (i.e. a block of //! or /// 166 | # comments) as a brief description. This used to be the default behaviour. 167 | # The new default is to treat a multi-line C++ comment block as a detailed 168 | # description. Set this tag to YES if you prefer the old behaviour instead. 169 | 170 | MULTILINE_CPP_IS_BRIEF = NO 171 | 172 | # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 173 | # member inherits the documentation from any documented member that it 174 | # re-implements. 175 | 176 | INHERIT_DOCS = YES 177 | 178 | # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 179 | # a new page for each member. If set to NO, the documentation of a member will 180 | # be part of the file/class/namespace that contains it. 181 | 182 | SEPARATE_MEMBER_PAGES = NO 183 | 184 | # The TAB_SIZE tag can be used to set the number of spaces in a tab. 185 | # Doxygen uses this value to replace tabs by spaces in code fragments. 186 | 187 | TAB_SIZE = 8 188 | 189 | # This tag can be used to specify a number of aliases that acts 190 | # as commands in the documentation. An alias has the form "name=value". 191 | # For example adding "sideeffect=\par Side Effects:\n" will allow you to 192 | # put the command \sideeffect (or @sideeffect) in the documentation, which 193 | # will result in a user-defined paragraph with heading "Side Effects:". 194 | # You can put \n's in the value part of an alias to insert newlines. 195 | 196 | ALIASES = 197 | 198 | # This tag can be used to specify a number of word-keyword mappings (TCL only). 199 | # A mapping has the form "name=value". For example adding 200 | # "class=itcl::class" will allow you to use the command class in the 201 | # itcl::class meaning. 202 | 203 | TCL_SUBST = 204 | 205 | # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 206 | # sources only. Doxygen will then generate output that is more tailored for C. 207 | # For instance, some of the names that are used will be different. The list 208 | # of all members will be omitted, etc. 209 | 210 | OPTIMIZE_OUTPUT_FOR_C = YES 211 | 212 | # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 213 | # sources only. Doxygen will then generate output that is more tailored for 214 | # Java. For instance, namespaces will be presented as packages, qualified 215 | # scopes will look different, etc. 216 | 217 | OPTIMIZE_OUTPUT_JAVA = NO 218 | 219 | # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 220 | # sources only. Doxygen will then generate output that is more tailored for 221 | # Fortran. 222 | 223 | OPTIMIZE_FOR_FORTRAN = NO 224 | 225 | # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 226 | # sources. Doxygen will then generate output that is tailored for 227 | # VHDL. 228 | 229 | OPTIMIZE_OUTPUT_VHDL = NO 230 | 231 | # Doxygen selects the parser to use depending on the extension of the files it 232 | # parses. With this tag you can assign which parser to use for a given extension. 233 | # Doxygen has a built-in mapping, but you can override or extend it using this 234 | # tag. The format is ext=language, where ext is a file extension, and language 235 | # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, 236 | # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make 237 | # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C 238 | # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions 239 | # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. 240 | 241 | EXTENSION_MAPPING = 242 | 243 | # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 244 | # to include (a tag file for) the STL sources as input, then you should 245 | # set this tag to YES in order to let doxygen match functions declarations and 246 | # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 247 | # func(std::string) {}). This also makes the inheritance and collaboration 248 | # diagrams that involve STL classes more complete and accurate. 249 | 250 | BUILTIN_STL_SUPPORT = NO 251 | 252 | # If you use Microsoft's C++/CLI language, you should set this option to YES to 253 | # enable parsing support. 254 | 255 | CPP_CLI_SUPPORT = NO 256 | 257 | # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 258 | # Doxygen will parse them like normal C++ but will assume all classes use public 259 | # instead of private inheritance when no explicit protection keyword is present. 260 | 261 | SIP_SUPPORT = NO 262 | 263 | # For Microsoft's IDL there are propget and propput attributes to indicate getter 264 | # and setter methods for a property. Setting this option to YES (the default) 265 | # will make doxygen replace the get and set methods by a property in the 266 | # documentation. This will only work if the methods are indeed getting or 267 | # setting a simple type. If this is not the case, or you want to show the 268 | # methods anyway, you should set this option to NO. 269 | 270 | IDL_PROPERTY_SUPPORT = YES 271 | 272 | # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 273 | # tag is set to YES, then doxygen will reuse the documentation of the first 274 | # member in the group (if any) for the other members of the group. By default 275 | # all members of a group must be documented explicitly. 276 | 277 | DISTRIBUTE_GROUP_DOC = NO 278 | 279 | # Set the SUBGROUPING tag to YES (the default) to allow class member groups of 280 | # the same type (for instance a group of public functions) to be put as a 281 | # subgroup of that type (e.g. under the Public Functions section). Set it to 282 | # NO to prevent subgrouping. Alternatively, this can be done per class using 283 | # the \nosubgrouping command. 284 | 285 | SUBGROUPING = YES 286 | 287 | # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and 288 | # unions are shown inside the group in which they are included (e.g. using 289 | # @ingroup) instead of on a separate page (for HTML and Man pages) or 290 | # section (for LaTeX and RTF). 291 | 292 | INLINE_GROUPED_CLASSES = NO 293 | 294 | # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and 295 | # unions with only public data fields will be shown inline in the documentation 296 | # of the scope in which they are defined (i.e. file, namespace, or group 297 | # documentation), provided this scope is documented. If set to NO (the default), 298 | # structs, classes, and unions are shown on a separate page (for HTML and Man 299 | # pages) or section (for LaTeX and RTF). 300 | 301 | INLINE_SIMPLE_STRUCTS = NO 302 | 303 | # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 304 | # is documented as struct, union, or enum with the name of the typedef. So 305 | # typedef struct TypeS {} TypeT, will appear in the documentation as a struct 306 | # with name TypeT. When disabled the typedef will appear as a member of a file, 307 | # namespace, or class. And the struct will be named TypeS. This can typically 308 | # be useful for C code in case the coding convention dictates that all compound 309 | # types are typedef'ed and only the typedef is referenced, never the tag name. 310 | 311 | TYPEDEF_HIDES_STRUCT = NO 312 | 313 | # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to 314 | # determine which symbols to keep in memory and which to flush to disk. 315 | # When the cache is full, less often used symbols will be written to disk. 316 | # For small to medium size projects (<1000 input files) the default value is 317 | # probably good enough. For larger projects a too small cache size can cause 318 | # doxygen to be busy swapping symbols to and from disk most of the time 319 | # causing a significant performance penalty. 320 | # If the system has enough physical memory increasing the cache will improve the 321 | # performance by keeping more symbols in memory. Note that the value works on 322 | # a logarithmic scale so increasing the size by one will roughly double the 323 | # memory usage. The cache size is given by this formula: 324 | # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 325 | # corresponding to a cache size of 2^16 = 65536 symbols. 326 | 327 | SYMBOL_CACHE_SIZE = 0 328 | 329 | # Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be 330 | # set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given 331 | # their name and scope. Since this can be an expensive process and often the 332 | # same symbol appear multiple times in the code, doxygen keeps a cache of 333 | # pre-resolved symbols. If the cache is too small doxygen will become slower. 334 | # If the cache is too large, memory is wasted. The cache size is given by this 335 | # formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, 336 | # corresponding to a cache size of 2^16 = 65536 symbols. 337 | 338 | LOOKUP_CACHE_SIZE = 0 339 | 340 | #--------------------------------------------------------------------------- 341 | # Build related configuration options 342 | #--------------------------------------------------------------------------- 343 | 344 | # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 345 | # documentation are documented, even if no documentation was available. 346 | # Private class members and static file members will be hidden unless 347 | # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES 348 | 349 | EXTRACT_ALL = NO 350 | 351 | # If the EXTRACT_PRIVATE tag is set to YES all private members of a class 352 | # will be included in the documentation. 353 | 354 | EXTRACT_PRIVATE = NO 355 | 356 | # If the EXTRACT_STATIC tag is set to YES all static members of a file 357 | # will be included in the documentation. 358 | 359 | EXTRACT_STATIC = NO 360 | 361 | # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 362 | # defined locally in source files will be included in the documentation. 363 | # If set to NO only classes defined in header files are included. 364 | 365 | EXTRACT_LOCAL_CLASSES = YES 366 | 367 | # This flag is only useful for Objective-C code. When set to YES local 368 | # methods, which are defined in the implementation section but not in 369 | # the interface are included in the documentation. 370 | # If set to NO (the default) only methods in the interface are included. 371 | 372 | EXTRACT_LOCAL_METHODS = NO 373 | 374 | # If this flag is set to YES, the members of anonymous namespaces will be 375 | # extracted and appear in the documentation as a namespace called 376 | # 'anonymous_namespace{file}', where file will be replaced with the base 377 | # name of the file that contains the anonymous namespace. By default 378 | # anonymous namespaces are hidden. 379 | 380 | EXTRACT_ANON_NSPACES = NO 381 | 382 | # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 383 | # undocumented members of documented classes, files or namespaces. 384 | # If set to NO (the default) these members will be included in the 385 | # various overviews, but no documentation section is generated. 386 | # This option has no effect if EXTRACT_ALL is enabled. 387 | 388 | HIDE_UNDOC_MEMBERS = NO 389 | 390 | # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 391 | # undocumented classes that are normally visible in the class hierarchy. 392 | # If set to NO (the default) these classes will be included in the various 393 | # overviews. This option has no effect if EXTRACT_ALL is enabled. 394 | 395 | HIDE_UNDOC_CLASSES = NO 396 | 397 | # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 398 | # friend (class|struct|union) declarations. 399 | # If set to NO (the default) these declarations will be included in the 400 | # documentation. 401 | 402 | HIDE_FRIEND_COMPOUNDS = NO 403 | 404 | # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 405 | # documentation blocks found inside the body of a function. 406 | # If set to NO (the default) these blocks will be appended to the 407 | # function's detailed documentation block. 408 | 409 | HIDE_IN_BODY_DOCS = NO 410 | 411 | # The INTERNAL_DOCS tag determines if documentation 412 | # that is typed after a \internal command is included. If the tag is set 413 | # to NO (the default) then the documentation will be excluded. 414 | # Set it to YES to include the internal documentation. 415 | 416 | INTERNAL_DOCS = NO 417 | 418 | # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 419 | # file names in lower-case letters. If set to YES upper-case letters are also 420 | # allowed. This is useful if you have classes or files whose names only differ 421 | # in case and if your file system supports case sensitive file names. Windows 422 | # and Mac users are advised to set this option to NO. 423 | 424 | CASE_SENSE_NAMES = YES 425 | 426 | # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 427 | # will show members with their full class and namespace scopes in the 428 | # documentation. If set to YES the scope will be hidden. 429 | 430 | HIDE_SCOPE_NAMES = NO 431 | 432 | # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 433 | # will put a list of the files that are included by a file in the documentation 434 | # of that file. 435 | 436 | SHOW_INCLUDE_FILES = YES 437 | 438 | # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen 439 | # will list include files with double quotes in the documentation 440 | # rather than with sharp brackets. 441 | 442 | FORCE_LOCAL_INCLUDES = NO 443 | 444 | # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 445 | # is inserted in the documentation for inline members. 446 | 447 | INLINE_INFO = YES 448 | 449 | # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 450 | # will sort the (detailed) documentation of file and class members 451 | # alphabetically by member name. If set to NO the members will appear in 452 | # declaration order. 453 | 454 | SORT_MEMBER_DOCS = YES 455 | 456 | # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 457 | # brief documentation of file, namespace and class members alphabetically 458 | # by member name. If set to NO (the default) the members will appear in 459 | # declaration order. 460 | 461 | SORT_BRIEF_DOCS = NO 462 | 463 | # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen 464 | # will sort the (brief and detailed) documentation of class members so that 465 | # constructors and destructors are listed first. If set to NO (the default) 466 | # the constructors will appear in the respective orders defined by 467 | # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. 468 | # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO 469 | # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. 470 | 471 | SORT_MEMBERS_CTORS_1ST = NO 472 | 473 | # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 474 | # hierarchy of group names into alphabetical order. If set to NO (the default) 475 | # the group names will appear in their defined order. 476 | 477 | SORT_GROUP_NAMES = NO 478 | 479 | # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 480 | # sorted by fully-qualified names, including namespaces. If set to 481 | # NO (the default), the class list will be sorted only by class name, 482 | # not including the namespace part. 483 | # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. 484 | # Note: This option applies only to the class list, not to the 485 | # alphabetical list. 486 | 487 | SORT_BY_SCOPE_NAME = NO 488 | 489 | # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to 490 | # do proper type resolution of all parameters of a function it will reject a 491 | # match between the prototype and the implementation of a member function even 492 | # if there is only one candidate or it is obvious which candidate to choose 493 | # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen 494 | # will still accept a match between prototype and implementation in such cases. 495 | 496 | STRICT_PROTO_MATCHING = NO 497 | 498 | # The GENERATE_TODOLIST tag can be used to enable (YES) or 499 | # disable (NO) the todo list. This list is created by putting \todo 500 | # commands in the documentation. 501 | 502 | GENERATE_TODOLIST = YES 503 | 504 | # The GENERATE_TESTLIST tag can be used to enable (YES) or 505 | # disable (NO) the test list. This list is created by putting \test 506 | # commands in the documentation. 507 | 508 | GENERATE_TESTLIST = YES 509 | 510 | # The GENERATE_BUGLIST tag can be used to enable (YES) or 511 | # disable (NO) the bug list. This list is created by putting \bug 512 | # commands in the documentation. 513 | 514 | GENERATE_BUGLIST = YES 515 | 516 | # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 517 | # disable (NO) the deprecated list. This list is created by putting 518 | # \deprecated commands in the documentation. 519 | 520 | GENERATE_DEPRECATEDLIST= YES 521 | 522 | # The ENABLED_SECTIONS tag can be used to enable conditional 523 | # documentation sections, marked by \if sectionname ... \endif. 524 | 525 | ENABLED_SECTIONS = 526 | 527 | # The MAX_INITIALIZER_LINES tag determines the maximum number of lines 528 | # the initial value of a variable or macro consists of for it to appear in 529 | # the documentation. If the initializer consists of more lines than specified 530 | # here it will be hidden. Use a value of 0 to hide initializers completely. 531 | # The appearance of the initializer of individual variables and macros in the 532 | # documentation can be controlled using \showinitializer or \hideinitializer 533 | # command in the documentation regardless of this setting. 534 | 535 | MAX_INITIALIZER_LINES = 30 536 | 537 | # Set the SHOW_USED_FILES tag to NO to disable the list of files generated 538 | # at the bottom of the documentation of classes and structs. If set to YES the 539 | # list will mention the files that were used to generate the documentation. 540 | 541 | SHOW_USED_FILES = YES 542 | 543 | # If the sources in your project are distributed over multiple directories 544 | # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 545 | # in the documentation. The default is NO. 546 | 547 | SHOW_DIRECTORIES = NO 548 | 549 | # Set the SHOW_FILES tag to NO to disable the generation of the Files page. 550 | # This will remove the Files entry from the Quick Index and from the 551 | # Folder Tree View (if specified). The default is YES. 552 | 553 | SHOW_FILES = YES 554 | 555 | # Set the SHOW_NAMESPACES tag to NO to disable the generation of the 556 | # Namespaces page. 557 | # This will remove the Namespaces entry from the Quick Index 558 | # and from the Folder Tree View (if specified). The default is YES. 559 | 560 | SHOW_NAMESPACES = YES 561 | 562 | # The FILE_VERSION_FILTER tag can be used to specify a program or script that 563 | # doxygen should invoke to get the current version for each file (typically from 564 | # the version control system). Doxygen will invoke the program by executing (via 565 | # popen()) the command , where is the value of 566 | # the FILE_VERSION_FILTER tag, and is the name of an input file 567 | # provided by doxygen. Whatever the program writes to standard output 568 | # is used as the file version. See the manual for examples. 569 | 570 | FILE_VERSION_FILTER = 571 | 572 | # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed 573 | # by doxygen. The layout file controls the global structure of the generated 574 | # output files in an output format independent way. The create the layout file 575 | # that represents doxygen's defaults, run doxygen with the -l option. 576 | # You can optionally specify a file name after the option, if omitted 577 | # DoxygenLayout.xml will be used as the name of the layout file. 578 | 579 | LAYOUT_FILE = 580 | 581 | # The CITE_BIB_FILES tag can be used to specify one or more bib files 582 | # containing the references data. This must be a list of .bib files. The 583 | # .bib extension is automatically appended if omitted. Using this command 584 | # requires the bibtex tool to be installed. See also 585 | # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style 586 | # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this 587 | # feature you need bibtex and perl available in the search path. 588 | 589 | CITE_BIB_FILES = 590 | 591 | #--------------------------------------------------------------------------- 592 | # configuration options related to warning and progress messages 593 | #--------------------------------------------------------------------------- 594 | 595 | # The QUIET tag can be used to turn on/off the messages that are generated 596 | # by doxygen. Possible values are YES and NO. If left blank NO is used. 597 | 598 | QUIET = NO 599 | 600 | # The WARNINGS tag can be used to turn on/off the warning messages that are 601 | # generated by doxygen. Possible values are YES and NO. If left blank 602 | # NO is used. 603 | 604 | WARNINGS = YES 605 | 606 | # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 607 | # for undocumented members. If EXTRACT_ALL is set to YES then this flag will 608 | # automatically be disabled. 609 | 610 | WARN_IF_UNDOCUMENTED = YES 611 | 612 | # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 613 | # potential errors in the documentation, such as not documenting some 614 | # parameters in a documented function, or documenting parameters that 615 | # don't exist or using markup commands wrongly. 616 | 617 | WARN_IF_DOC_ERROR = YES 618 | 619 | # The WARN_NO_PARAMDOC option can be enabled to get warnings for 620 | # functions that are documented, but have no documentation for their parameters 621 | # or return value. If set to NO (the default) doxygen will only warn about 622 | # wrong or incomplete parameter documentation, but not about the absence of 623 | # documentation. 624 | 625 | WARN_NO_PARAMDOC = NO 626 | 627 | # The WARN_FORMAT tag determines the format of the warning messages that 628 | # doxygen can produce. The string should contain the $file, $line, and $text 629 | # tags, which will be replaced by the file and line number from which the 630 | # warning originated and the warning text. Optionally the format may contain 631 | # $version, which will be replaced by the version of the file (if it could 632 | # be obtained via FILE_VERSION_FILTER) 633 | 634 | WARN_FORMAT = "$file:$line: $text" 635 | 636 | # The WARN_LOGFILE tag can be used to specify a file to which warning 637 | # and error messages should be written. If left blank the output is written 638 | # to stderr. 639 | 640 | WARN_LOGFILE = 641 | 642 | #--------------------------------------------------------------------------- 643 | # configuration options related to the input files 644 | #--------------------------------------------------------------------------- 645 | 646 | # The INPUT tag can be used to specify the files and/or directories that contain 647 | # documented source files. You may enter file names like "myfile.cpp" or 648 | # directories like "/usr/src/myproject". Separate the files or directories 649 | # with spaces. 650 | 651 | INPUT = src 652 | 653 | # This tag can be used to specify the character encoding of the source files 654 | # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 655 | # also the default input encoding. Doxygen uses libiconv (or the iconv built 656 | # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 657 | # the list of possible encodings. 658 | 659 | INPUT_ENCODING = UTF-8 660 | 661 | # If the value of the INPUT tag contains directories, you can use the 662 | # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 663 | # and *.h) to filter out the source-files in the directories. If left 664 | # blank the following patterns are tested: 665 | # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh 666 | # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py 667 | # *.f90 *.f *.for *.vhd *.vhdl 668 | 669 | FILE_PATTERNS = *.c *.h 670 | 671 | # The RECURSIVE tag can be used to turn specify whether or not subdirectories 672 | # should be searched for input files as well. Possible values are YES and NO. 673 | # If left blank NO is used. 674 | 675 | RECURSIVE = YES 676 | 677 | # The EXCLUDE tag can be used to specify files and/or directories that should be 678 | # excluded from the INPUT source files. This way you can easily exclude a 679 | # subdirectory from a directory tree whose root is specified with the INPUT tag. 680 | # Note that relative paths are relative to the directory from which doxygen is 681 | # run. 682 | 683 | EXCLUDE = 684 | 685 | # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or 686 | # directories that are symbolic links (a Unix file system feature) are excluded 687 | # from the input. 688 | 689 | EXCLUDE_SYMLINKS = NO 690 | 691 | # If the value of the INPUT tag contains directories, you can use the 692 | # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 693 | # certain files from those directories. Note that the wildcards are matched 694 | # against the file with absolute path, so to exclude all test directories 695 | # for example use the pattern */test/* 696 | 697 | EXCLUDE_PATTERNS = 698 | 699 | # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 700 | # (namespaces, classes, functions, etc.) that should be excluded from the 701 | # output. The symbol name can be a fully qualified name, a word, or if the 702 | # wildcard * is used, a substring. Examples: ANamespace, AClass, 703 | # AClass::ANamespace, ANamespace::*Test 704 | 705 | EXCLUDE_SYMBOLS = 706 | 707 | # The EXAMPLE_PATH tag can be used to specify one or more files or 708 | # directories that contain example code fragments that are included (see 709 | # the \include command). 710 | 711 | EXAMPLE_PATH = 712 | 713 | # If the value of the EXAMPLE_PATH tag contains directories, you can use the 714 | # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 715 | # and *.h) to filter out the source-files in the directories. If left 716 | # blank all files are included. 717 | 718 | EXAMPLE_PATTERNS = 719 | 720 | # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 721 | # searched for input files to be used with the \include or \dontinclude 722 | # commands irrespective of the value of the RECURSIVE tag. 723 | # Possible values are YES and NO. If left blank NO is used. 724 | 725 | EXAMPLE_RECURSIVE = NO 726 | 727 | # The IMAGE_PATH tag can be used to specify one or more files or 728 | # directories that contain image that are included in the documentation (see 729 | # the \image command). 730 | 731 | IMAGE_PATH = 732 | 733 | # The INPUT_FILTER tag can be used to specify a program that doxygen should 734 | # invoke to filter for each input file. Doxygen will invoke the filter program 735 | # by executing (via popen()) the command , where 736 | # is the value of the INPUT_FILTER tag, and is the name of an 737 | # input file. Doxygen will then use the output that the filter program writes 738 | # to standard output. 739 | # If FILTER_PATTERNS is specified, this tag will be 740 | # ignored. 741 | 742 | INPUT_FILTER = 743 | 744 | # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 745 | # basis. 746 | # Doxygen will compare the file name with each pattern and apply the 747 | # filter if there is a match. 748 | # The filters are a list of the form: 749 | # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 750 | # info on how filters are used. If FILTER_PATTERNS is empty or if 751 | # non of the patterns match the file name, INPUT_FILTER is applied. 752 | 753 | FILTER_PATTERNS = 754 | 755 | # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 756 | # INPUT_FILTER) will be used to filter the input files when producing source 757 | # files to browse (i.e. when SOURCE_BROWSER is set to YES). 758 | 759 | FILTER_SOURCE_FILES = NO 760 | 761 | # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file 762 | # pattern. A pattern will override the setting for FILTER_PATTERN (if any) 763 | # and it is also possible to disable source filtering for a specific pattern 764 | # using *.ext= (so without naming a filter). This option only has effect when 765 | # FILTER_SOURCE_FILES is enabled. 766 | 767 | FILTER_SOURCE_PATTERNS = 768 | 769 | #--------------------------------------------------------------------------- 770 | # configuration options related to source browsing 771 | #--------------------------------------------------------------------------- 772 | 773 | # If the SOURCE_BROWSER tag is set to YES then a list of source files will 774 | # be generated. Documented entities will be cross-referenced with these sources. 775 | # Note: To get rid of all source code in the generated output, make sure also 776 | # VERBATIM_HEADERS is set to NO. 777 | 778 | SOURCE_BROWSER = NO 779 | 780 | # Setting the INLINE_SOURCES tag to YES will include the body 781 | # of functions and classes directly in the documentation. 782 | 783 | INLINE_SOURCES = NO 784 | 785 | # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 786 | # doxygen to hide any special comment blocks from generated source code 787 | # fragments. Normal C and C++ comments will always remain visible. 788 | 789 | STRIP_CODE_COMMENTS = YES 790 | 791 | # If the REFERENCED_BY_RELATION tag is set to YES 792 | # then for each documented function all documented 793 | # functions referencing it will be listed. 794 | 795 | REFERENCED_BY_RELATION = NO 796 | 797 | # If the REFERENCES_RELATION tag is set to YES 798 | # then for each documented function all documented entities 799 | # called/used by that function will be listed. 800 | 801 | REFERENCES_RELATION = NO 802 | 803 | # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) 804 | # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from 805 | # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will 806 | # link to the source code. 807 | # Otherwise they will link to the documentation. 808 | 809 | REFERENCES_LINK_SOURCE = YES 810 | 811 | # If the USE_HTAGS tag is set to YES then the references to source code 812 | # will point to the HTML generated by the htags(1) tool instead of doxygen 813 | # built-in source browser. The htags tool is part of GNU's global source 814 | # tagging system (see http://www.gnu.org/software/global/global.html). You 815 | # will need version 4.8.6 or higher. 816 | 817 | USE_HTAGS = NO 818 | 819 | # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 820 | # will generate a verbatim copy of the header file for each class for 821 | # which an include is specified. Set to NO to disable this. 822 | 823 | VERBATIM_HEADERS = YES 824 | 825 | #--------------------------------------------------------------------------- 826 | # configuration options related to the alphabetical class index 827 | #--------------------------------------------------------------------------- 828 | 829 | # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 830 | # of all compounds will be generated. Enable this if the project 831 | # contains a lot of classes, structs, unions or interfaces. 832 | 833 | ALPHABETICAL_INDEX = YES 834 | 835 | # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 836 | # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 837 | # in which this list will be split (can be a number in the range [1..20]) 838 | 839 | COLS_IN_ALPHA_INDEX = 5 840 | 841 | # In case all classes in a project start with a common prefix, all 842 | # classes will be put under the same header in the alphabetical index. 843 | # The IGNORE_PREFIX tag can be used to specify one or more prefixes that 844 | # should be ignored while generating the index headers. 845 | 846 | IGNORE_PREFIX = 847 | 848 | #--------------------------------------------------------------------------- 849 | # configuration options related to the HTML output 850 | #--------------------------------------------------------------------------- 851 | 852 | # If the GENERATE_HTML tag is set to YES (the default) Doxygen will 853 | # generate HTML output. 854 | 855 | GENERATE_HTML = YES 856 | 857 | # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 858 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 859 | # put in front of it. If left blank `html' will be used as the default path. 860 | 861 | HTML_OUTPUT = html 862 | 863 | # The HTML_FILE_EXTENSION tag can be used to specify the file extension for 864 | # each generated HTML page (for example: .htm,.php,.asp). If it is left blank 865 | # doxygen will generate files with .html extension. 866 | 867 | HTML_FILE_EXTENSION = .html 868 | 869 | # The HTML_HEADER tag can be used to specify a personal HTML header for 870 | # each generated HTML page. If it is left blank doxygen will generate a 871 | # standard header. Note that when using a custom header you are responsible 872 | # for the proper inclusion of any scripts and style sheets that doxygen 873 | # needs, which is dependent on the configuration options used. 874 | # It is advised to generate a default header using "doxygen -w html 875 | # header.html footer.html stylesheet.css YourConfigFile" and then modify 876 | # that header. Note that the header is subject to change so you typically 877 | # have to redo this when upgrading to a newer version of doxygen or when 878 | # changing the value of configuration settings such as GENERATE_TREEVIEW! 879 | 880 | HTML_HEADER = 881 | 882 | # The HTML_FOOTER tag can be used to specify a personal HTML footer for 883 | # each generated HTML page. If it is left blank doxygen will generate a 884 | # standard footer. 885 | 886 | HTML_FOOTER = 887 | 888 | # The HTML_STYLESHEET tag can be used to specify a user-defined cascading 889 | # style sheet that is used by each HTML page. It can be used to 890 | # fine-tune the look of the HTML output. If the tag is left blank doxygen 891 | # will generate a default style sheet. Note that doxygen will try to copy 892 | # the style sheet file to the HTML output directory, so don't put your own 893 | # style sheet in the HTML output directory as well, or it will be erased! 894 | 895 | HTML_STYLESHEET = 896 | 897 | # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or 898 | # other source files which should be copied to the HTML output directory. Note 899 | # that these files will be copied to the base HTML output directory. Use the 900 | # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these 901 | # files. In the HTML_STYLESHEET file, use the file name only. Also note that 902 | # the files will be copied as-is; there are no commands or markers available. 903 | 904 | HTML_EXTRA_FILES = 905 | 906 | # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. 907 | # Doxygen will adjust the colors in the style sheet and background images 908 | # according to this color. Hue is specified as an angle on a colorwheel, 909 | # see http://en.wikipedia.org/wiki/Hue for more information. 910 | # For instance the value 0 represents red, 60 is yellow, 120 is green, 911 | # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. 912 | # The allowed range is 0 to 359. 913 | 914 | HTML_COLORSTYLE_HUE = 220 915 | 916 | # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of 917 | # the colors in the HTML output. For a value of 0 the output will use 918 | # grayscales only. A value of 255 will produce the most vivid colors. 919 | 920 | HTML_COLORSTYLE_SAT = 100 921 | 922 | # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to 923 | # the luminance component of the colors in the HTML output. Values below 924 | # 100 gradually make the output lighter, whereas values above 100 make 925 | # the output darker. The value divided by 100 is the actual gamma applied, 926 | # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, 927 | # and 100 does not change the gamma. 928 | 929 | HTML_COLORSTYLE_GAMMA = 80 930 | 931 | # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML 932 | # page will contain the date and time when the page was generated. Setting 933 | # this to NO can help when comparing the output of multiple runs. 934 | 935 | HTML_TIMESTAMP = YES 936 | 937 | # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 938 | # files or namespaces will be aligned in HTML using tables. If set to 939 | # NO a bullet list will be used. 940 | 941 | HTML_ALIGN_MEMBERS = YES 942 | 943 | # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 944 | # documentation will contain sections that can be hidden and shown after the 945 | # page has loaded. For this to work a browser that supports 946 | # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 947 | # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). 948 | 949 | HTML_DYNAMIC_SECTIONS = NO 950 | 951 | # If the GENERATE_DOCSET tag is set to YES, additional index files 952 | # will be generated that can be used as input for Apple's Xcode 3 953 | # integrated development environment, introduced with OSX 10.5 (Leopard). 954 | # To create a documentation set, doxygen will generate a Makefile in the 955 | # HTML output directory. Running make will produce the docset in that 956 | # directory and running "make install" will install the docset in 957 | # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 958 | # it at startup. 959 | # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html 960 | # for more information. 961 | 962 | GENERATE_DOCSET = NO 963 | 964 | # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 965 | # feed. A documentation feed provides an umbrella under which multiple 966 | # documentation sets from a single provider (such as a company or product suite) 967 | # can be grouped. 968 | 969 | DOCSET_FEEDNAME = "Doxygen generated docs" 970 | 971 | # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 972 | # should uniquely identify the documentation set bundle. This should be a 973 | # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 974 | # will append .docset to the name. 975 | 976 | DOCSET_BUNDLE_ID = org.doxygen.Project 977 | 978 | # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify 979 | # the documentation publisher. This should be a reverse domain-name style 980 | # string, e.g. com.mycompany.MyDocSet.documentation. 981 | 982 | DOCSET_PUBLISHER_ID = org.doxygen.Publisher 983 | 984 | # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. 985 | 986 | DOCSET_PUBLISHER_NAME = Publisher 987 | 988 | # If the GENERATE_HTMLHELP tag is set to YES, additional index files 989 | # will be generated that can be used as input for tools like the 990 | # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 991 | # of the generated HTML documentation. 992 | 993 | GENERATE_HTMLHELP = NO 994 | 995 | # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 996 | # be used to specify the file name of the resulting .chm file. You 997 | # can add a path in front of the file if the result should not be 998 | # written to the html output directory. 999 | 1000 | CHM_FILE = 1001 | 1002 | # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 1003 | # be used to specify the location (absolute path including file name) of 1004 | # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 1005 | # the HTML help compiler on the generated index.hhp. 1006 | 1007 | HHC_LOCATION = 1008 | 1009 | # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 1010 | # controls if a separate .chi index file is generated (YES) or that 1011 | # it should be included in the master .chm file (NO). 1012 | 1013 | GENERATE_CHI = NO 1014 | 1015 | # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING 1016 | # is used to encode HtmlHelp index (hhk), content (hhc) and project file 1017 | # content. 1018 | 1019 | CHM_INDEX_ENCODING = 1020 | 1021 | # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 1022 | # controls whether a binary table of contents is generated (YES) or a 1023 | # normal table of contents (NO) in the .chm file. 1024 | 1025 | BINARY_TOC = NO 1026 | 1027 | # The TOC_EXPAND flag can be set to YES to add extra items for group members 1028 | # to the contents of the HTML help documentation and to the tree view. 1029 | 1030 | TOC_EXPAND = NO 1031 | 1032 | # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and 1033 | # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated 1034 | # that can be used as input for Qt's qhelpgenerator to generate a 1035 | # Qt Compressed Help (.qch) of the generated HTML documentation. 1036 | 1037 | GENERATE_QHP = NO 1038 | 1039 | # If the QHG_LOCATION tag is specified, the QCH_FILE tag can 1040 | # be used to specify the file name of the resulting .qch file. 1041 | # The path specified is relative to the HTML output folder. 1042 | 1043 | QCH_FILE = 1044 | 1045 | # The QHP_NAMESPACE tag specifies the namespace to use when generating 1046 | # Qt Help Project output. For more information please see 1047 | # http://doc.trolltech.com/qthelpproject.html#namespace 1048 | 1049 | QHP_NAMESPACE = org.doxygen.Project 1050 | 1051 | # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating 1052 | # Qt Help Project output. For more information please see 1053 | # http://doc.trolltech.com/qthelpproject.html#virtual-folders 1054 | 1055 | QHP_VIRTUAL_FOLDER = doc 1056 | 1057 | # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to 1058 | # add. For more information please see 1059 | # http://doc.trolltech.com/qthelpproject.html#custom-filters 1060 | 1061 | QHP_CUST_FILTER_NAME = 1062 | 1063 | # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the 1064 | # custom filter to add. For more information please see 1065 | # 1066 | # Qt Help Project / Custom Filters. 1067 | 1068 | QHP_CUST_FILTER_ATTRS = 1069 | 1070 | # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this 1071 | # project's 1072 | # filter section matches. 1073 | # 1074 | # Qt Help Project / Filter Attributes. 1075 | 1076 | QHP_SECT_FILTER_ATTRS = 1077 | 1078 | # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can 1079 | # be used to specify the location of Qt's qhelpgenerator. 1080 | # If non-empty doxygen will try to run qhelpgenerator on the generated 1081 | # .qhp file. 1082 | 1083 | QHG_LOCATION = 1084 | 1085 | # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files 1086 | # will be generated, which together with the HTML files, form an Eclipse help 1087 | # plugin. To install this plugin and make it available under the help contents 1088 | # menu in Eclipse, the contents of the directory containing the HTML and XML 1089 | # files needs to be copied into the plugins directory of eclipse. The name of 1090 | # the directory within the plugins directory should be the same as 1091 | # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before 1092 | # the help appears. 1093 | 1094 | GENERATE_ECLIPSEHELP = NO 1095 | 1096 | # A unique identifier for the eclipse help plugin. When installing the plugin 1097 | # the directory name containing the HTML and XML files should also have 1098 | # this name. 1099 | 1100 | ECLIPSE_DOC_ID = org.doxygen.Project 1101 | 1102 | # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) 1103 | # at top of each HTML page. The value NO (the default) enables the index and 1104 | # the value YES disables it. Since the tabs have the same information as the 1105 | # navigation tree you can set this option to NO if you already set 1106 | # GENERATE_TREEVIEW to YES. 1107 | 1108 | DISABLE_INDEX = NO 1109 | 1110 | # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index 1111 | # structure should be generated to display hierarchical information. 1112 | # If the tag value is set to YES, a side panel will be generated 1113 | # containing a tree-like index structure (just like the one that 1114 | # is generated for HTML Help). For this to work a browser that supports 1115 | # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). 1116 | # Windows users are probably better off using the HTML help feature. 1117 | # Since the tree basically has the same information as the tab index you 1118 | # could consider to set DISABLE_INDEX to NO when enabling this option. 1119 | 1120 | GENERATE_TREEVIEW = NO 1121 | 1122 | # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values 1123 | # (range [0,1..20]) that doxygen will group on one line in the generated HTML 1124 | # documentation. Note that a value of 0 will completely suppress the enum 1125 | # values from appearing in the overview section. 1126 | 1127 | ENUM_VALUES_PER_LINE = 4 1128 | 1129 | # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, 1130 | # and Class Hierarchy pages using a tree view instead of an ordered list. 1131 | 1132 | USE_INLINE_TREES = NO 1133 | 1134 | # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 1135 | # used to set the initial width (in pixels) of the frame in which the tree 1136 | # is shown. 1137 | 1138 | TREEVIEW_WIDTH = 250 1139 | 1140 | # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open 1141 | # links to external symbols imported via tag files in a separate window. 1142 | 1143 | EXT_LINKS_IN_WINDOW = NO 1144 | 1145 | # Use this tag to change the font size of Latex formulas included 1146 | # as images in the HTML documentation. The default is 10. Note that 1147 | # when you change the font size after a successful doxygen run you need 1148 | # to manually remove any form_*.png images from the HTML output directory 1149 | # to force them to be regenerated. 1150 | 1151 | FORMULA_FONTSIZE = 10 1152 | 1153 | # Use the FORMULA_TRANPARENT tag to determine whether or not the images 1154 | # generated for formulas are transparent PNGs. Transparent PNGs are 1155 | # not supported properly for IE 6.0, but are supported on all modern browsers. 1156 | # Note that when changing this option you need to delete any form_*.png files 1157 | # in the HTML output before the changes have effect. 1158 | 1159 | FORMULA_TRANSPARENT = YES 1160 | 1161 | # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax 1162 | # (see http://www.mathjax.org) which uses client side Javascript for the 1163 | # rendering instead of using prerendered bitmaps. Use this if you do not 1164 | # have LaTeX installed or if you want to formulas look prettier in the HTML 1165 | # output. When enabled you also need to install MathJax separately and 1166 | # configure the path to it using the MATHJAX_RELPATH option. 1167 | 1168 | USE_MATHJAX = NO 1169 | 1170 | # When MathJax is enabled you need to specify the location relative to the 1171 | # HTML output directory using the MATHJAX_RELPATH option. The destination 1172 | # directory should contain the MathJax.js script. For instance, if the mathjax 1173 | # directory is located at the same level as the HTML output directory, then 1174 | # MATHJAX_RELPATH should be ../mathjax. The default value points to the 1175 | # mathjax.org site, so you can quickly see the result without installing 1176 | # MathJax, but it is strongly recommended to install a local copy of MathJax 1177 | # before deployment. 1178 | 1179 | MATHJAX_RELPATH = http://www.mathjax.org/mathjax 1180 | 1181 | # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension 1182 | # names that should be enabled during MathJax rendering. 1183 | 1184 | MATHJAX_EXTENSIONS = 1185 | 1186 | # When the SEARCHENGINE tag is enabled doxygen will generate a search box 1187 | # for the HTML output. The underlying search engine uses javascript 1188 | # and DHTML and should work on any modern browser. Note that when using 1189 | # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets 1190 | # (GENERATE_DOCSET) there is already a search function so this one should 1191 | # typically be disabled. For large projects the javascript based search engine 1192 | # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. 1193 | 1194 | SEARCHENGINE = YES 1195 | 1196 | # When the SERVER_BASED_SEARCH tag is enabled the search engine will be 1197 | # implemented using a PHP enabled web server instead of at the web client 1198 | # using Javascript. Doxygen will generate the search PHP script and index 1199 | # file to put on the web server. The advantage of the server 1200 | # based approach is that it scales better to large projects and allows 1201 | # full text search. The disadvantages are that it is more difficult to setup 1202 | # and does not have live searching capabilities. 1203 | 1204 | SERVER_BASED_SEARCH = NO 1205 | 1206 | #--------------------------------------------------------------------------- 1207 | # configuration options related to the LaTeX output 1208 | #--------------------------------------------------------------------------- 1209 | 1210 | # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 1211 | # generate Latex output. 1212 | 1213 | GENERATE_LATEX = NO 1214 | 1215 | # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 1216 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 1217 | # put in front of it. If left blank `latex' will be used as the default path. 1218 | 1219 | LATEX_OUTPUT = latex 1220 | 1221 | # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 1222 | # invoked. If left blank `latex' will be used as the default command name. 1223 | # Note that when enabling USE_PDFLATEX this option is only used for 1224 | # generating bitmaps for formulas in the HTML output, but not in the 1225 | # Makefile that is written to the output directory. 1226 | 1227 | LATEX_CMD_NAME = latex 1228 | 1229 | # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 1230 | # generate index for LaTeX. If left blank `makeindex' will be used as the 1231 | # default command name. 1232 | 1233 | MAKEINDEX_CMD_NAME = makeindex 1234 | 1235 | # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 1236 | # LaTeX documents. This may be useful for small projects and may help to 1237 | # save some trees in general. 1238 | 1239 | COMPACT_LATEX = NO 1240 | 1241 | # The PAPER_TYPE tag can be used to set the paper type that is used 1242 | # by the printer. Possible values are: a4, letter, legal and 1243 | # executive. If left blank a4wide will be used. 1244 | 1245 | PAPER_TYPE = a4 1246 | 1247 | # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 1248 | # packages that should be included in the LaTeX output. 1249 | 1250 | EXTRA_PACKAGES = 1251 | 1252 | # The LATEX_HEADER tag can be used to specify a personal LaTeX header for 1253 | # the generated latex document. The header should contain everything until 1254 | # the first chapter. If it is left blank doxygen will generate a 1255 | # standard header. Notice: only use this tag if you know what you are doing! 1256 | 1257 | LATEX_HEADER = 1258 | 1259 | # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for 1260 | # the generated latex document. The footer should contain everything after 1261 | # the last chapter. If it is left blank doxygen will generate a 1262 | # standard footer. Notice: only use this tag if you know what you are doing! 1263 | 1264 | LATEX_FOOTER = 1265 | 1266 | # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 1267 | # is prepared for conversion to pdf (using ps2pdf). The pdf file will 1268 | # contain links (just like the HTML output) instead of page references 1269 | # This makes the output suitable for online browsing using a pdf viewer. 1270 | 1271 | PDF_HYPERLINKS = YES 1272 | 1273 | # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 1274 | # plain latex in the generated Makefile. Set this option to YES to get a 1275 | # higher quality PDF documentation. 1276 | 1277 | USE_PDFLATEX = YES 1278 | 1279 | # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 1280 | # command to the generated LaTeX files. This will instruct LaTeX to keep 1281 | # running if errors occur, instead of asking the user for help. 1282 | # This option is also used when generating formulas in HTML. 1283 | 1284 | LATEX_BATCHMODE = NO 1285 | 1286 | # If LATEX_HIDE_INDICES is set to YES then doxygen will not 1287 | # include the index chapters (such as File Index, Compound Index, etc.) 1288 | # in the output. 1289 | 1290 | LATEX_HIDE_INDICES = NO 1291 | 1292 | # If LATEX_SOURCE_CODE is set to YES then doxygen will include 1293 | # source code with syntax highlighting in the LaTeX output. 1294 | # Note that which sources are shown also depends on other settings 1295 | # such as SOURCE_BROWSER. 1296 | 1297 | LATEX_SOURCE_CODE = YES 1298 | 1299 | # The LATEX_BIB_STYLE tag can be used to specify the style to use for the 1300 | # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See 1301 | # http://en.wikipedia.org/wiki/BibTeX for more info. 1302 | 1303 | LATEX_BIB_STYLE = plain 1304 | 1305 | #--------------------------------------------------------------------------- 1306 | # configuration options related to the RTF output 1307 | #--------------------------------------------------------------------------- 1308 | 1309 | # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 1310 | # The RTF output is optimized for Word 97 and may not look very pretty with 1311 | # other RTF readers or editors. 1312 | 1313 | GENERATE_RTF = NO 1314 | 1315 | # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 1316 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 1317 | # put in front of it. If left blank `rtf' will be used as the default path. 1318 | 1319 | RTF_OUTPUT = rtf 1320 | 1321 | # If the COMPACT_RTF tag is set to YES Doxygen generates more compact 1322 | # RTF documents. This may be useful for small projects and may help to 1323 | # save some trees in general. 1324 | 1325 | COMPACT_RTF = NO 1326 | 1327 | # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 1328 | # will contain hyperlink fields. The RTF file will 1329 | # contain links (just like the HTML output) instead of page references. 1330 | # This makes the output suitable for online browsing using WORD or other 1331 | # programs which support those fields. 1332 | # Note: wordpad (write) and others do not support links. 1333 | 1334 | RTF_HYPERLINKS = NO 1335 | 1336 | # Load style sheet definitions from file. Syntax is similar to doxygen's 1337 | # config file, i.e. a series of assignments. You only have to provide 1338 | # replacements, missing definitions are set to their default value. 1339 | 1340 | RTF_STYLESHEET_FILE = 1341 | 1342 | # Set optional variables used in the generation of an rtf document. 1343 | # Syntax is similar to doxygen's config file. 1344 | 1345 | RTF_EXTENSIONS_FILE = 1346 | 1347 | #--------------------------------------------------------------------------- 1348 | # configuration options related to the man page output 1349 | #--------------------------------------------------------------------------- 1350 | 1351 | # If the GENERATE_MAN tag is set to YES (the default) Doxygen will 1352 | # generate man pages 1353 | 1354 | GENERATE_MAN = NO 1355 | 1356 | # The MAN_OUTPUT tag is used to specify where the man pages will be put. 1357 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 1358 | # put in front of it. If left blank `man' will be used as the default path. 1359 | 1360 | MAN_OUTPUT = man 1361 | 1362 | # The MAN_EXTENSION tag determines the extension that is added to 1363 | # the generated man pages (default is the subroutine's section .3) 1364 | 1365 | MAN_EXTENSION = .3 1366 | 1367 | # If the MAN_LINKS tag is set to YES and Doxygen generates man output, 1368 | # then it will generate one additional man file for each entity 1369 | # documented in the real man page(s). These additional files 1370 | # only source the real man page, but without them the man command 1371 | # would be unable to find the correct page. The default is NO. 1372 | 1373 | MAN_LINKS = NO 1374 | 1375 | #--------------------------------------------------------------------------- 1376 | # configuration options related to the XML output 1377 | #--------------------------------------------------------------------------- 1378 | 1379 | # If the GENERATE_XML tag is set to YES Doxygen will 1380 | # generate an XML file that captures the structure of 1381 | # the code including all documentation. 1382 | 1383 | GENERATE_XML = NO 1384 | 1385 | # The XML_OUTPUT tag is used to specify where the XML pages will be put. 1386 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 1387 | # put in front of it. If left blank `xml' will be used as the default path. 1388 | 1389 | XML_OUTPUT = xml 1390 | 1391 | # The XML_SCHEMA tag can be used to specify an XML schema, 1392 | # which can be used by a validating XML parser to check the 1393 | # syntax of the XML files. 1394 | 1395 | XML_SCHEMA = 1396 | 1397 | # The XML_DTD tag can be used to specify an XML DTD, 1398 | # which can be used by a validating XML parser to check the 1399 | # syntax of the XML files. 1400 | 1401 | XML_DTD = 1402 | 1403 | # If the XML_PROGRAMLISTING tag is set to YES Doxygen will 1404 | # dump the program listings (including syntax highlighting 1405 | # and cross-referencing information) to the XML output. Note that 1406 | # enabling this will significantly increase the size of the XML output. 1407 | 1408 | XML_PROGRAMLISTING = YES 1409 | 1410 | #--------------------------------------------------------------------------- 1411 | # configuration options for the AutoGen Definitions output 1412 | #--------------------------------------------------------------------------- 1413 | 1414 | # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 1415 | # generate an AutoGen Definitions (see autogen.sf.net) file 1416 | # that captures the structure of the code including all 1417 | # documentation. Note that this feature is still experimental 1418 | # and incomplete at the moment. 1419 | 1420 | GENERATE_AUTOGEN_DEF = NO 1421 | 1422 | #--------------------------------------------------------------------------- 1423 | # configuration options related to the Perl module output 1424 | #--------------------------------------------------------------------------- 1425 | 1426 | # If the GENERATE_PERLMOD tag is set to YES Doxygen will 1427 | # generate a Perl module file that captures the structure of 1428 | # the code including all documentation. Note that this 1429 | # feature is still experimental and incomplete at the 1430 | # moment. 1431 | 1432 | GENERATE_PERLMOD = NO 1433 | 1434 | # If the PERLMOD_LATEX tag is set to YES Doxygen will generate 1435 | # the necessary Makefile rules, Perl scripts and LaTeX code to be able 1436 | # to generate PDF and DVI output from the Perl module output. 1437 | 1438 | PERLMOD_LATEX = NO 1439 | 1440 | # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 1441 | # nicely formatted so it can be parsed by a human reader. 1442 | # This is useful 1443 | # if you want to understand what is going on. 1444 | # On the other hand, if this 1445 | # tag is set to NO the size of the Perl module output will be much smaller 1446 | # and Perl will parse it just the same. 1447 | 1448 | PERLMOD_PRETTY = YES 1449 | 1450 | # The names of the make variables in the generated doxyrules.make file 1451 | # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 1452 | # This is useful so different doxyrules.make files included by the same 1453 | # Makefile don't overwrite each other's variables. 1454 | 1455 | PERLMOD_MAKEVAR_PREFIX = 1456 | 1457 | #--------------------------------------------------------------------------- 1458 | # Configuration options related to the preprocessor 1459 | #--------------------------------------------------------------------------- 1460 | 1461 | # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 1462 | # evaluate all C-preprocessor directives found in the sources and include 1463 | # files. 1464 | 1465 | ENABLE_PREPROCESSING = YES 1466 | 1467 | # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 1468 | # names in the source code. If set to NO (the default) only conditional 1469 | # compilation will be performed. Macro expansion can be done in a controlled 1470 | # way by setting EXPAND_ONLY_PREDEF to YES. 1471 | 1472 | MACRO_EXPANSION = NO 1473 | 1474 | # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 1475 | # then the macro expansion is limited to the macros specified with the 1476 | # PREDEFINED and EXPAND_AS_DEFINED tags. 1477 | 1478 | EXPAND_ONLY_PREDEF = NO 1479 | 1480 | # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 1481 | # pointed to by INCLUDE_PATH will be searched when a #include is found. 1482 | 1483 | SEARCH_INCLUDES = YES 1484 | 1485 | # The INCLUDE_PATH tag can be used to specify one or more directories that 1486 | # contain include files that are not input files but should be processed by 1487 | # the preprocessor. 1488 | 1489 | INCLUDE_PATH = 1490 | 1491 | # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 1492 | # patterns (like *.h and *.hpp) to filter out the header-files in the 1493 | # directories. If left blank, the patterns specified with FILE_PATTERNS will 1494 | # be used. 1495 | 1496 | INCLUDE_FILE_PATTERNS = 1497 | 1498 | # The PREDEFINED tag can be used to specify one or more macro names that 1499 | # are defined before the preprocessor is started (similar to the -D option of 1500 | # gcc). The argument of the tag is a list of macros of the form: name 1501 | # or name=definition (no spaces). If the definition and the = are 1502 | # omitted =1 is assumed. To prevent a macro definition from being 1503 | # undefined via #undef or recursively expanded use the := operator 1504 | # instead of the = operator. 1505 | 1506 | PREDEFINED = 1507 | 1508 | # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 1509 | # this tag can be used to specify a list of macro names that should be expanded. 1510 | # The macro definition that is found in the sources will be used. 1511 | # Use the PREDEFINED tag if you want to use a different macro definition that 1512 | # overrules the definition found in the source code. 1513 | 1514 | EXPAND_AS_DEFINED = 1515 | 1516 | # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 1517 | # doxygen's preprocessor will remove all references to function-like macros 1518 | # that are alone on a line, have an all uppercase name, and do not end with a 1519 | # semicolon, because these will confuse the parser if not removed. 1520 | 1521 | SKIP_FUNCTION_MACROS = YES 1522 | 1523 | #--------------------------------------------------------------------------- 1524 | # Configuration::additions related to external references 1525 | #--------------------------------------------------------------------------- 1526 | 1527 | # The TAGFILES option can be used to specify one or more tagfiles. 1528 | # Optionally an initial location of the external documentation 1529 | # can be added for each tagfile. The format of a tag file without 1530 | # this location is as follows: 1531 | # 1532 | # TAGFILES = file1 file2 ... 1533 | # Adding location for the tag files is done as follows: 1534 | # 1535 | # TAGFILES = file1=loc1 "file2 = loc2" ... 1536 | # where "loc1" and "loc2" can be relative or absolute paths or 1537 | # URLs. If a location is present for each tag, the installdox tool 1538 | # does not have to be run to correct the links. 1539 | # Note that each tag file must have a unique name 1540 | # (where the name does NOT include the path) 1541 | # If a tag file is not located in the directory in which doxygen 1542 | # is run, you must also specify the path to the tagfile here. 1543 | 1544 | TAGFILES = 1545 | 1546 | # When a file name is specified after GENERATE_TAGFILE, doxygen will create 1547 | # a tag file that is based on the input files it reads. 1548 | 1549 | GENERATE_TAGFILE = 1550 | 1551 | # If the ALLEXTERNALS tag is set to YES all external classes will be listed 1552 | # in the class index. If set to NO only the inherited external classes 1553 | # will be listed. 1554 | 1555 | ALLEXTERNALS = NO 1556 | 1557 | # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 1558 | # in the modules index. If set to NO, only the current project's groups will 1559 | # be listed. 1560 | 1561 | EXTERNAL_GROUPS = YES 1562 | 1563 | # The PERL_PATH should be the absolute path and name of the perl script 1564 | # interpreter (i.e. the result of `which perl'). 1565 | 1566 | PERL_PATH = /usr/bin/perl 1567 | 1568 | #--------------------------------------------------------------------------- 1569 | # Configuration options related to the dot tool 1570 | #--------------------------------------------------------------------------- 1571 | 1572 | # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 1573 | # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 1574 | # or super classes. Setting the tag to NO turns the diagrams off. Note that 1575 | # this option also works with HAVE_DOT disabled, but it is recommended to 1576 | # install and use dot, since it yields more powerful graphs. 1577 | 1578 | CLASS_DIAGRAMS = YES 1579 | 1580 | # You can define message sequence charts within doxygen comments using the \msc 1581 | # command. Doxygen will then run the mscgen tool (see 1582 | # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 1583 | # documentation. The MSCGEN_PATH tag allows you to specify the directory where 1584 | # the mscgen tool resides. If left empty the tool is assumed to be found in the 1585 | # default search path. 1586 | 1587 | MSCGEN_PATH = 1588 | 1589 | # If set to YES, the inheritance and collaboration graphs will hide 1590 | # inheritance and usage relations if the target is undocumented 1591 | # or is not a class. 1592 | 1593 | HIDE_UNDOC_RELATIONS = YES 1594 | 1595 | # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 1596 | # available from the path. This tool is part of Graphviz, a graph visualization 1597 | # toolkit from AT&T and Lucent Bell Labs. The other options in this section 1598 | # have no effect if this option is set to NO (the default) 1599 | 1600 | HAVE_DOT = NO 1601 | 1602 | # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is 1603 | # allowed to run in parallel. When set to 0 (the default) doxygen will 1604 | # base this on the number of processors available in the system. You can set it 1605 | # explicitly to a value larger than 0 to get control over the balance 1606 | # between CPU load and processing speed. 1607 | 1608 | DOT_NUM_THREADS = 0 1609 | 1610 | # By default doxygen will use the Helvetica font for all dot files that 1611 | # doxygen generates. When you want a differently looking font you can specify 1612 | # the font name using DOT_FONTNAME. You need to make sure dot is able to find 1613 | # the font, which can be done by putting it in a standard location or by setting 1614 | # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the 1615 | # directory containing the font. 1616 | 1617 | DOT_FONTNAME = Helvetica 1618 | 1619 | # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. 1620 | # The default size is 10pt. 1621 | 1622 | DOT_FONTSIZE = 10 1623 | 1624 | # By default doxygen will tell dot to use the Helvetica font. 1625 | # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to 1626 | # set the path where dot can find it. 1627 | 1628 | DOT_FONTPATH = 1629 | 1630 | # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 1631 | # will generate a graph for each documented class showing the direct and 1632 | # indirect inheritance relations. Setting this tag to YES will force the 1633 | # CLASS_DIAGRAMS tag to NO. 1634 | 1635 | CLASS_GRAPH = YES 1636 | 1637 | # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 1638 | # will generate a graph for each documented class showing the direct and 1639 | # indirect implementation dependencies (inheritance, containment, and 1640 | # class references variables) of the class with other documented classes. 1641 | 1642 | COLLABORATION_GRAPH = YES 1643 | 1644 | # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 1645 | # will generate a graph for groups, showing the direct groups dependencies 1646 | 1647 | GROUP_GRAPHS = YES 1648 | 1649 | # If the UML_LOOK tag is set to YES doxygen will generate inheritance and 1650 | # collaboration diagrams in a style similar to the OMG's Unified Modeling 1651 | # Language. 1652 | 1653 | UML_LOOK = NO 1654 | 1655 | # If set to YES, the inheritance and collaboration graphs will show the 1656 | # relations between templates and their instances. 1657 | 1658 | TEMPLATE_RELATIONS = NO 1659 | 1660 | # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 1661 | # tags are set to YES then doxygen will generate a graph for each documented 1662 | # file showing the direct and indirect include dependencies of the file with 1663 | # other documented files. 1664 | 1665 | INCLUDE_GRAPH = YES 1666 | 1667 | # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 1668 | # HAVE_DOT tags are set to YES then doxygen will generate a graph for each 1669 | # documented header file showing the documented files that directly or 1670 | # indirectly include this file. 1671 | 1672 | INCLUDED_BY_GRAPH = YES 1673 | 1674 | # If the CALL_GRAPH and HAVE_DOT options are set to YES then 1675 | # doxygen will generate a call dependency graph for every global function 1676 | # or class method. Note that enabling this option will significantly increase 1677 | # the time of a run. So in most cases it will be better to enable call graphs 1678 | # for selected functions only using the \callgraph command. 1679 | 1680 | CALL_GRAPH = NO 1681 | 1682 | # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 1683 | # doxygen will generate a caller dependency graph for every global function 1684 | # or class method. Note that enabling this option will significantly increase 1685 | # the time of a run. So in most cases it will be better to enable caller 1686 | # graphs for selected functions only using the \callergraph command. 1687 | 1688 | CALLER_GRAPH = NO 1689 | 1690 | # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 1691 | # will generate a graphical hierarchy of all classes instead of a textual one. 1692 | 1693 | GRAPHICAL_HIERARCHY = YES 1694 | 1695 | # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 1696 | # then doxygen will show the dependencies a directory has on other directories 1697 | # in a graphical way. The dependency relations are determined by the #include 1698 | # relations between the files in the directories. 1699 | 1700 | DIRECTORY_GRAPH = YES 1701 | 1702 | # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 1703 | # generated by dot. Possible values are svg, png, jpg, or gif. 1704 | # If left blank png will be used. If you choose svg you need to set 1705 | # HTML_FILE_EXTENSION to xhtml in order to make the SVG files 1706 | # visible in IE 9+ (other browsers do not have this requirement). 1707 | 1708 | DOT_IMAGE_FORMAT = png 1709 | 1710 | # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to 1711 | # enable generation of interactive SVG images that allow zooming and panning. 1712 | # Note that this requires a modern browser other than Internet Explorer. 1713 | # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you 1714 | # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files 1715 | # visible. Older versions of IE do not have SVG support. 1716 | 1717 | INTERACTIVE_SVG = NO 1718 | 1719 | # The tag DOT_PATH can be used to specify the path where the dot tool can be 1720 | # found. If left blank, it is assumed the dot tool can be found in the path. 1721 | 1722 | DOT_PATH = 1723 | 1724 | # The DOTFILE_DIRS tag can be used to specify one or more directories that 1725 | # contain dot files that are included in the documentation (see the 1726 | # \dotfile command). 1727 | 1728 | DOTFILE_DIRS = 1729 | 1730 | # The MSCFILE_DIRS tag can be used to specify one or more directories that 1731 | # contain msc files that are included in the documentation (see the 1732 | # \mscfile command). 1733 | 1734 | MSCFILE_DIRS = 1735 | 1736 | # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 1737 | # nodes that will be shown in the graph. If the number of nodes in a graph 1738 | # becomes larger than this value, doxygen will truncate the graph, which is 1739 | # visualized by representing a node as a red box. Note that doxygen if the 1740 | # number of direct children of the root node in a graph is already larger than 1741 | # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 1742 | # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. 1743 | 1744 | DOT_GRAPH_MAX_NODES = 50 1745 | 1746 | # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 1747 | # graphs generated by dot. A depth value of 3 means that only nodes reachable 1748 | # from the root by following a path via at most 3 edges will be shown. Nodes 1749 | # that lay further from the root node will be omitted. Note that setting this 1750 | # option to 1 or 2 may greatly reduce the computation time needed for large 1751 | # code bases. Also note that the size of a graph can be further restricted by 1752 | # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. 1753 | 1754 | MAX_DOT_GRAPH_DEPTH = 0 1755 | 1756 | # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 1757 | # background. This is disabled by default, because dot on Windows does not 1758 | # seem to support this out of the box. Warning: Depending on the platform used, 1759 | # enabling this option may lead to badly anti-aliased labels on the edges of 1760 | # a graph (i.e. they become hard to read). 1761 | 1762 | DOT_TRANSPARENT = NO 1763 | 1764 | # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 1765 | # files in one run (i.e. multiple -o and -T options on the command line). This 1766 | # makes dot run faster, but since only newer versions of dot (>1.8.10) 1767 | # support this, this feature is disabled by default. 1768 | 1769 | DOT_MULTI_TARGETS = YES 1770 | 1771 | # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 1772 | # generate a legend page explaining the meaning of the various boxes and 1773 | # arrows in the dot generated graphs. 1774 | 1775 | GENERATE_LEGEND = YES 1776 | 1777 | # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 1778 | # remove the intermediate dot files that are used to generate 1779 | # the various graphs. 1780 | 1781 | DOT_CLEANUP = YES 1782 | -------------------------------------------------------------------------------- /src/ngx_http_log_zmq.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2014-2015 by SAPO - PT Comunicações 3 | * Copyright (c) 2016 by Altice Labs 4 | * 5 | *****************************************************************************/ 6 | 7 | /** 8 | * @file ngx_http_log_zmq.c 9 | * @author Dani Bento 10 | * @date 1 March 2014 11 | * @brief Brokerlog ZMQ 12 | * 13 | * @see http://www.zeromq.org/ 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | #include "ngx_http_log_zmq.h" 25 | 26 | /** 27 | * @brief initialize ZMQ context 28 | * 29 | * Each location is owner of a ZMQ context. We should see this effected 30 | * reflected on the number of threads created by each nginx process. 31 | * 32 | * @param ctx A ngx_http_log_zmq_ctx_t pointer representing the actual 33 | * location context 34 | * @return An int representing the OK (0) or error status 35 | * @note We should redefine this to ngx_int_t with NGX_OK | NGX_ERROR 36 | */ 37 | int 38 | zmq_init_ctx(ngx_http_log_zmq_ctx_t *ctx) 39 | { 40 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "ZMQ: zmq_init_ctx()"); 41 | /* each location has it's own context, we need to verify if this is the best 42 | * solution. We don't want to consume a lot of ZMQ threads to maintain the 43 | * communication */ 44 | ctx->zmq_context = zmq_init((int) ctx->iothreads); 45 | if (NULL == ctx->zmq_context) { 46 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "ZMQ: zmq_init(%d) fail", ctx->iothreads); 47 | return -1; 48 | } 49 | ctx->ccreated = 1; 50 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "ZMQ: zmq_init(%d) success", ctx->iothreads); 51 | return 0; 52 | } 53 | 54 | /** 55 | * @brief create ZMQ Context 56 | * 57 | * Read the actual configuration, verify if we dont have yet a context and 58 | * initiate it. 59 | * 60 | * @param cf A ngx_http_log_zmq_element_conf_t pointer to the location configuration 61 | * @return An int representing the OK (0) or error status 62 | * @note We should redefine this to ngx_int_t with NGX_OK | NGX_ERROR 63 | */ 64 | int 65 | zmq_create_ctx(ngx_http_log_zmq_element_conf_t *cf) 66 | { 67 | int rc = 0; 68 | 69 | /* TODO: should we create the context structure here? */ 70 | if (NULL == cf || NULL == cf->ctx) { 71 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->ctx->log, 0, "ZMQ: zmq_create_ctx() no configuration"); 72 | return 1; 73 | } 74 | /* context is already created, return NGX_OK */ 75 | if (1 == cf->ctx->ccreated) { 76 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->ctx->log, 0, "ZMQ: zmq_create_ctx() already created"); 77 | return 0; 78 | } 79 | 80 | /* create location context */ 81 | cf->ctx->iothreads = cf->iothreads; 82 | rc = zmq_init_ctx(cf->ctx); 83 | 84 | if (rc != 0) { 85 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->ctx->log, 0, "ZMQ: zmq_create_ctx() error"); 86 | ngx_log_error(NGX_LOG_ERR, cf->ctx->log, 0, "ZMQ: zmq_create_ctx() error"); 87 | return rc; 88 | } 89 | 90 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->ctx->log, 0, "ZMQ: zmq_create_ctx() success"); 91 | return 0; 92 | } 93 | 94 | /** 95 | * @brief close ZMQ sockets and term ZMQ context 96 | * 97 | * We should close all sockets and term the ZMQ context before we totaly exit 98 | * nginx. 99 | * 100 | * @param ctx A ngx_http_log_zmq_ctx_t pointer to the actual module context 101 | * @return Nothing 102 | * @note Should we free the context itself here? 103 | */ 104 | void 105 | zmq_term_ctx(ngx_http_log_zmq_ctx_t *ctx) 106 | { 107 | /* close and nullify context zmq_socket */ 108 | if (ctx->zmq_socket) { 109 | zmq_close(ctx->zmq_socket); 110 | ctx->zmq_socket = NULL; 111 | } 112 | 113 | /* term and nullify context zmq_context */ 114 | if (ctx->zmq_context) { 115 | zmq_ctx_destroy(ctx->zmq_context); 116 | ctx->zmq_context = NULL; 117 | } 118 | 119 | /* nullify log */ 120 | if (ctx->log) { 121 | ctx->log = NULL; 122 | } 123 | return; 124 | } 125 | 126 | /** 127 | * @brief create a ZMQ Socket 128 | * 129 | * Verify if it not exists and create a new socket to be available to write 130 | * messages. 131 | * 132 | * @param cf A ngx_http_log_zmq_element_conf_t pointer to the location configuration 133 | * @return An int representing the OK (0) or error status 134 | * @note We should redefine this to ngx_int_t with NGX_OK | NGX_ERROR 135 | * @warning It's important to look at here and define one socket per worker 136 | */ 137 | int 138 | zmq_create_socket(ngx_pool_t *pool, ngx_http_log_zmq_element_conf_t *cf) 139 | { 140 | int linger = ZMQ_NGINX_LINGER, rc = 0; 141 | zmq_hwm_t qlen = cf->qlen < 0 ? ZMQ_NGINX_QUEUE_LENGTH : cf->qlen; 142 | char *connection; 143 | 144 | /* verify if we have a context created */ 145 | if (NULL == cf->ctx->zmq_context) { 146 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->ctx->log, 0, "ZMQ: zmq_create_socket() context is NULL"); 147 | return -1; 148 | } 149 | 150 | /* verify if we have already a socket associated */ 151 | if (0 == cf->ctx->screated) { 152 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->ctx->log, 0, "ZMQ: zmq_create_socket() create socket"); 153 | cf->ctx->zmq_socket = zmq_socket(cf->ctx->zmq_context, ZMQ_PUB); 154 | /* verify if it was created */ 155 | if (NULL == cf->ctx->zmq_socket) { 156 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->ctx->log, 0, "ZMQ: zmq_create_socket() socket not created"); 157 | ngx_log_error(NGX_LOG_ERR, cf->ctx->log, 0, "ZMQ socket not created: %s", strerror(errno)); 158 | return -1; 159 | } 160 | cf->ctx->screated = 1; 161 | } 162 | 163 | /* set socket option ZMQ_SNDHWM (Must be done before ZMQ_LINGER or it fails, why?) */ 164 | rc = zmq_setsockopt(cf->ctx->zmq_socket, ZMQ_SNDHWM, &qlen, sizeof(qlen)); 165 | if (rc != 0) { 166 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->ctx->log, 0, "ZMQ: zmq_create_socket() error setting ZMQ_SNDHWM"); 167 | ngx_log_error(NGX_LOG_ERR, cf->ctx->log, 0, "ZMQ error setting option ZMQ_SNDHWM: %s", strerror(errno)); 168 | return -1; 169 | } 170 | 171 | /* set socket option ZMQ_LINGER */ 172 | rc = zmq_setsockopt(cf->ctx->zmq_socket, ZMQ_LINGER, &linger, sizeof(linger)); 173 | if (rc != 0) { 174 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->ctx->log, 0, "ZMQ: zmq_create_socket() error setting ZMQ_LINGER"); 175 | ngx_log_error(NGX_LOG_ERR, cf->ctx->log, 0, "ZMQ error setting option ZMQ_LINGER: %s", strerror(errno)); 176 | return -1; 177 | } 178 | 179 | /* create a simple char * to the connection name */ 180 | connection = ngx_pcalloc(pool, cf->server->connection->len + 1); 181 | ngx_memcpy(connection, cf->server->connection->data, cf->server->connection->len); 182 | 183 | ngx_log_debug(NGX_LOG_DEBUG_HTTP, cf->ctx->log, 0, "ZMQ: zmq_create_socket() connect to %s", connection); 184 | 185 | /* open zmq connection to */ 186 | rc = zmq_connect(cf->ctx->zmq_socket, connection); 187 | if (rc != 0) { 188 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->ctx->log, 0, "ZMQ: zmq_create_socket() error connecting"); 189 | ngx_log_error(NGX_LOG_ERR, cf->ctx->log, 0, "ZMQ error connecting: %s", strerror(errno)); 190 | ngx_pfree(pool, connection); 191 | return -1; 192 | } 193 | 194 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->ctx->log, 0, "ZMQ: zmq_create_socket() connected"); 195 | ngx_pfree(pool, connection); 196 | 197 | /* if all was OK, we should return 0 */ 198 | return rc; 199 | } 200 | 201 | /** 202 | * @brief serialize a ZMQ message 203 | * 204 | * Process all input data and the endpoint and build a message to be sent by ZMQ 205 | * 206 | * @param pool A ngx_pool_t pointer to the nginx memory manager 207 | * @param endpoint A ngx_str_t pointer to the current endpoint configured to use 208 | * @param data A ngx_str_t pointer with the message compiled to be sent 209 | * @param output A ngx_str_t pointer which will point to the final message to be sent 210 | * @return An ngx_int_t with NGX_OK | NGX_ERROR 211 | */ 212 | ngx_int_t 213 | log_zmq_serialize(ngx_pool_t *pool, ngx_str_t *endpoint, ngx_str_t *data, ngx_str_t *output) { 214 | /* the final message sent to zmq is composed by endpoint+data 215 | * eg: endpoint = /stratus/, data = {'num':1} 216 | * final message /stratus/{'num':1} 217 | */ 218 | output->len = endpoint->len + data->len; 219 | output->data = ngx_palloc(pool, output->len); 220 | 221 | if (NULL == output->data) { 222 | output->len = 0; 223 | return NGX_ERROR; 224 | } 225 | 226 | ngx_memcpy(output->data, (const char *) endpoint->data, endpoint->len); 227 | ngx_memcpy(output->data + endpoint->len, (const char *) data->data, data->len); 228 | 229 | return NGX_OK; 230 | } 231 | -------------------------------------------------------------------------------- /src/ngx_http_log_zmq.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2014-2015 by SAPO - PT Comunicações 3 | * Copyright (c) 2016 by Altice Labs 4 | * 5 | *****************************************************************************/ 6 | 7 | /** 8 | * @file ngx_http_log_zmq.h 9 | * @author Dani Bento 10 | * @date 1 March 2014 11 | * @brief Brokerlog ZMQ Header 12 | * 13 | * @see http://www.zeromq.org/ 14 | */ 15 | 16 | #ifndef NGX_HTTP_BROKERLOG_ZMQ_H 17 | 18 | #define NGX_HTTP_BROKERLOG_ZMQ_H 1 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include "ngx_http_log_zmq_module.h" 28 | 29 | #ifndef ZMQ_DONTWAIT 30 | 31 | #define ZMQ_DONTWAIT ZMQ_NOBLOCK 32 | 33 | #endif 34 | 35 | #if ZMQ_VERSION_MAJOR < 3 36 | 37 | #define zmq_msg_send(msg,sock,opt) zmq_send(sock, msg, opt) 38 | #define zmq_msg_recv(msg,sock,opt) zmq_recv(sock, msg, opt) 39 | #define zmq_ctx_destroy(context) zmq_term(context) 40 | #define ZMQ_POLL_MSEC 1000 41 | #define ZMQ_SNDHWM ZMQ_HWM 42 | #define ZMQ_RCVHWM ZMQ_HWM 43 | #define zmq_hwm_t uint64_t 44 | 45 | #else 46 | 47 | #define zmq_hwm_t int 48 | #define ZMQ_POLL_MSEC 1 49 | 50 | #endif 51 | 52 | #define ZMQ_NGINX_LINGER 0 53 | #define ZMQ_NGINX_QUEUE_LENGTH 100 54 | 55 | /* ZMQ makes use of three types of protocols: 56 | * 57 | * _TCP_ is used mainly to publish data to another service, 58 | * on other host. 59 | * 60 | * _IPC_ is used to maintain communication between processes 61 | * inside the same machine 62 | * 63 | * _INPROC_ is used to maintain communication inside the same 64 | * application or process 65 | */ 66 | #define ZMQ_TCP_KEY "tcp" 67 | #define ZMQ_TCP_HANDLER "tcp://" 68 | #define ZMQ_TCP_HLEN 6 69 | 70 | #define ZMQ_IPC_KEY "ipc" 71 | #define ZMQ_IPC_HANDLER "ipc://" 72 | #define ZMQ_IPC_HLEN 6 73 | 74 | #define ZMQ_INPROC_KEY "inproc" 75 | #define ZMQ_INPROC_HANDLER "inproc://" 76 | #define ZMQ_INPROC_HLEN 9 77 | 78 | int zmq_init_ctx(ngx_http_log_zmq_ctx_t *ctx); 79 | void zmq_term_ctx(ngx_http_log_zmq_ctx_t *ctx); 80 | int zmq_create_ctx(ngx_http_log_zmq_element_conf_t *cf); 81 | int zmq_create_socket(ngx_pool_t *pool, ngx_http_log_zmq_element_conf_t *cf); 82 | ngx_int_t log_zmq_serialize(ngx_pool_t *pool, ngx_str_t *endpoint, ngx_str_t *payload, ngx_str_t *output); 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /src/ngx_http_log_zmq_module.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2014-2015 by SAPO - PT Comunicações 3 | * Copyright (c) 2016 by Altice Labs 4 | * 5 | *****************************************************************************/ 6 | 7 | /** 8 | * @file ngx_http_log_zmq_module.c 9 | * @author Dani Bento 10 | * @date 1 March 2014 11 | * @brief Brokerlog Module for nginx using ZMQ Message 12 | * 13 | * @see http://www.zeromq.org/ 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "ngx_http_log_zmq_module.h" 23 | 24 | /** 25 | * @brief get default port for the input type of protocol 26 | * 27 | * This function is responsable to handle the request and log 28 | * the data we want to the log_zmq via zmq proccess. 29 | * It's important to note that if this function fails it should 30 | * not kill the nginx normal running. After all, this is the log 31 | * phase. 32 | * 33 | * @param kind A ngx_log_zmq_server_kind with the value TCP|IPC|INPROC 34 | * @return A in_port_t with an integer with the port 35 | * @note Should we move this to ngx_http_log_zmq.c ? 36 | */ 37 | 38 | static in_port_t __get_default_port(const ngx_log_zmq_server_kind kind){ 39 | static const in_port_t DEFAULT_PORT = 0; 40 | 41 | switch(kind){ 42 | case TCP: 43 | return 5555; 44 | case IPC: 45 | case INPROC: 46 | return 0; 47 | } 48 | 49 | return DEFAULT_PORT; 50 | } 51 | 52 | static void *ngx_http_log_zmq_create_main_conf(ngx_conf_t *cf); 53 | static char *ngx_http_log_zmq_init_main_conf(ngx_conf_t *cf, void *conf); 54 | static void *ngx_http_log_zmq_create_loc_conf(ngx_conf_t *cf); 55 | static char *ngx_http_log_zmq_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); 56 | 57 | static char *ngx_http_log_zmq_set_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 58 | static char *ngx_http_log_zmq_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 59 | static char *ngx_http_log_zmq_set_endpoint(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 60 | static char *ngx_http_log_zmq_set_off(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 61 | 62 | static ngx_http_log_zmq_element_conf_t *ngx_http_log_zmq_create_definition(ngx_conf_t *cf, ngx_http_log_zmq_main_conf_t *bkmc, ngx_str_t *name); 63 | static ngx_http_log_zmq_loc_element_conf_t *ngx_http_log_zmq_create_location_element(ngx_conf_t *cf, ngx_http_log_zmq_loc_conf_t *llcf, ngx_str_t *name); 64 | 65 | static ngx_int_t ngx_http_log_zmq_postconf(ngx_conf_t *cf); 66 | static void ngx_http_log_zmq_exitmaster(ngx_cycle_t *cycle); 67 | 68 | static ngx_command_t ngx_http_log_zmq_commands[] = { 69 | 70 | { ngx_string("log_zmq_server"), 71 | NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE5, 72 | ngx_http_log_zmq_set_server, 73 | NGX_HTTP_LOC_CONF_OFFSET, 74 | 0, 75 | NULL }, 76 | 77 | { ngx_string("log_zmq_format"), 78 | NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE, 79 | ngx_http_log_zmq_set_format, 80 | NGX_HTTP_LOC_CONF_OFFSET, 81 | 0, 82 | NULL }, 83 | 84 | { ngx_string("log_zmq_endpoint"), 85 | NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2, 86 | ngx_http_log_zmq_set_endpoint, 87 | NGX_HTTP_LOC_CONF_OFFSET, 88 | 0, 89 | NULL }, 90 | { ngx_string("log_zmq_off"), 91 | NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 92 | ngx_http_log_zmq_set_off, 93 | NGX_HTTP_LOC_CONF_OFFSET, 94 | 0, 95 | NULL }, 96 | ngx_null_command 97 | }; 98 | 99 | static ngx_http_module_t ngx_http_log_zmq_module_ctx = { 100 | NULL, /* preconfiguration */ 101 | ngx_http_log_zmq_postconf, /* postconfiguration */ 102 | ngx_http_log_zmq_create_main_conf, /* create main configuration */ 103 | ngx_http_log_zmq_init_main_conf, /* init main configuration */ 104 | NULL, /* create server configuration */ 105 | NULL, /* merge server configuration */ 106 | ngx_http_log_zmq_create_loc_conf, /* create location configuration */ 107 | ngx_http_log_zmq_merge_loc_conf /* merge location configuration */ 108 | }; 109 | 110 | extern ngx_module_t ngx_http_log_module; 111 | 112 | ngx_module_t ngx_http_log_zmq_module = { 113 | NGX_MODULE_V1, 114 | &ngx_http_log_zmq_module_ctx, /* module context */ 115 | ngx_http_log_zmq_commands, /* module directives */ 116 | NGX_HTTP_MODULE, /* module type */ 117 | NULL, /* init master */ 118 | NULL, /* init module */ 119 | NULL, /* init process */ 120 | NULL, /* init thread */ 121 | NULL, /* exit thread */ 122 | NULL, /* exit process */ 123 | ngx_http_log_zmq_exitmaster, /* exit master */ 124 | NGX_MODULE_V1_PADDING 125 | }; 126 | 127 | /** 128 | * @brief nginx module's handler for logger phase 129 | * 130 | * This function is responsable to handle the request and log 131 | * the data we want to the log_zmq via zmq proccess. 132 | * It's important to note that if this function fails it should 133 | * not kill the nginx normal running. After all, this is the log 134 | * phase. 135 | * 136 | * @param r A ngx_http_request_t that represents the current request 137 | * @return A ngx_int_t which can be NGX_ERROR | NGX_OK 138 | * @note If NGX_DEBUG is setted than we print some messages to the debug log 139 | */ 140 | ngx_int_t 141 | ngx_http_log_zmq_handler(ngx_http_request_t *r) 142 | { 143 | ngx_http_log_zmq_loc_conf_t *lccf; 144 | ngx_http_log_zmq_element_conf_t *clecf; 145 | ngx_http_log_zmq_loc_element_conf_t *lelcf, *clelcf; 146 | ngx_uint_t i; 147 | ngx_str_t data; 148 | ngx_str_t zmq_data; 149 | ngx_str_t endpoint; 150 | ngx_pool_t *pool = r->connection->pool; 151 | ngx_log_t *log = r->connection->log; 152 | ngx_int_t (*serializer)(ngx_pool_t*, ngx_str_t*, ngx_str_t*, ngx_str_t*) = NULL; 153 | zmq_msg_t query; 154 | int rc; 155 | 156 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler()"); 157 | 158 | /* get current location configuration */ 159 | lccf = ngx_http_get_module_loc_conf(r, ngx_http_log_zmq_module); 160 | 161 | /* simply return NGX_OK if location logs are off */ 162 | if (lccf->off == 1) { 163 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): all logs off"); 164 | return NGX_OK; 165 | } 166 | 167 | /* location configuration has an ngx_array of log elements, we should iterate 168 | * by each one 169 | */ 170 | lelcf = lccf->logs->elts; /* point to the initial position > element 0 */ 171 | 172 | /* we use "continue" for each error in the cycle because we do not want the stop 173 | * the iteration, but continue to the next log */ 174 | for (i = 0; i < lccf->logs->nelts; i++) { 175 | 176 | clelcf = lelcf + i; 177 | 178 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): %V, off=%d", 179 | clelcf->element->name, clelcf->off); 180 | 181 | if (clelcf->off == 1) { 182 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): element off"); 183 | continue; 184 | } 185 | 186 | clecf = clelcf->element; /* get the i element of the log array */ 187 | 188 | /* worst case? we get a null element ?! */ 189 | if (NULL == clecf) { 190 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): no element config"); 191 | continue; 192 | } 193 | 194 | /* we only proceed if all the variables were setted: endpoint, server, format */ 195 | if (clecf->eset == 0 || clecf->fset == 0 || clecf->sset == 0) { 196 | ngx_log_debug3(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): eset=%d, fset=%d, sset=%d", 197 | clecf->eset, clecf->fset, clecf->sset); 198 | continue; 199 | } 200 | 201 | /* our configuration doesn't has a name? some error ocorred */ 202 | if (NULL == clecf->name || 0 == clecf->name->len) { 203 | ngx_log_error(NGX_LOG_ERR, log, 0, "log_zmq: handler(): no element name"); 204 | continue; 205 | } else { 206 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): setting up \"%V\"", clecf->name); 207 | } 208 | 209 | /* we set the server variable... but we can use it? */ 210 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): checking server to log"); 211 | if (NULL == clecf->server) { 212 | ngx_log_error(NGX_LOG_ERR, log, 0, "log_zmq: handler(): no server to log"); 213 | continue; 214 | } else { 215 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): server connection \"%V\"", clecf->server->connection); 216 | } 217 | 218 | /* we set the data format... but we don't have any content to sent? */ 219 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): checking format to log"); 220 | if (NULL == clecf->data_lengths) { 221 | ngx_log_error(NGX_LOG_ERR, log, 0, "log_zmq: handler(): no format to log"); 222 | continue; 223 | } 224 | 225 | /* we set the endpoint... but we don't have any valid endpoint? */ 226 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): checking endpoint to log"); 227 | if (NULL == clecf->endpoint_lengths) { 228 | ngx_log_error(NGX_LOG_ERR, log, 0, "log_zmq: handler(): no endpoint to log"); 229 | continue; 230 | } 231 | 232 | /* process all data variables and write them back to the data values */ 233 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): script data"); 234 | if (NULL == ngx_http_script_run(r, &data, clecf->data_lengths->elts, 0, clecf->data_values->elts)) { 235 | ngx_log_error(NGX_LOG_ERR, log, 0, "log_zmq: handler(): error script data"); 236 | continue; 237 | } 238 | 239 | /* process all endpoint variables and write them back the the endpoint values */ 240 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): script endpoint"); 241 | if (NULL == ngx_http_script_run(r, &endpoint, clecf->endpoint_lengths->elts, 0, clecf->endpoint_values->elts)) { 242 | ngx_log_error(NGX_LOG_ERR, log, 0, "log_zmq: handler(): error script endpoint"); 243 | continue; 244 | } 245 | 246 | /* yes, we must go on */ 247 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): logging to server"); 248 | 249 | /* no data */ 250 | if (0 == data.len) { 251 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): no message to log"); 252 | continue; 253 | } 254 | 255 | /* serialize to the final message format */ 256 | serializer = &log_zmq_serialize; 257 | 258 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): serializing message"); 259 | if (NGX_ERROR == (*serializer)(pool, &endpoint, &data, &zmq_data)) { 260 | ngx_log_error(NGX_LOG_ERR, log, 0, "log_zmq: handler(): error serializing message"); 261 | ngx_pfree(pool, zmq_data.data); 262 | continue; 263 | } 264 | 265 | /* no context? we dont create any */ 266 | if (NULL == clecf->ctx) { 267 | ngx_log_error(NGX_LOG_ERR, log, 0, "log_zmq: handler(): no context"); 268 | continue; 269 | } 270 | 271 | clecf->ctx->log = log; 272 | 273 | rc = 1; /* we should have a rc = 0 after this call */ 274 | 275 | /* create zmq context if needed */ 276 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): verify ZMQ context"); 277 | if ((NULL == clecf->ctx->zmq_context) && (0 == clecf->ctx->ccreated)) { 278 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): creating context"); 279 | rc = zmq_create_ctx(clecf); 280 | if (rc != 0) { 281 | ngx_log_error(NGX_LOG_INFO, log, 0, "log_zmq: handler(): error creating context"); 282 | continue; 283 | } 284 | } 285 | 286 | /* open zmq socket if needed */ 287 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): verify ZMQ socket"); 288 | if (NULL == clecf->ctx->zmq_socket && 0 == clecf->ctx->screated) { 289 | ngx_log_debug0(NGX_LOG_INFO, log, 0, "log_zmq: handler(): creating socket"); 290 | rc = zmq_create_socket(pool, clecf); 291 | if (rc != 0) { 292 | ngx_log_error(NGX_LOG_INFO, log, 0, "log_zmq: handler(): error creating socket"); 293 | continue; 294 | } 295 | } 296 | 297 | /* initialize zmq message */ 298 | zmq_msg_init_size(&query, zmq_data.len); 299 | 300 | ngx_memcpy(zmq_msg_data(&query), zmq_data.data, zmq_data.len); 301 | 302 | if (zmq_msg_send(&query, clecf->ctx->zmq_socket, 0) >= 0) { 303 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): message sent: %V", &zmq_data); 304 | } else { 305 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "log_zmq: handler(): message not sent: %V", &zmq_data); 306 | } 307 | 308 | /* free all for the next iteration */ 309 | zmq_msg_close(&query); 310 | 311 | ngx_pfree(pool, zmq_data.data); 312 | } 313 | 314 | return NGX_OK; 315 | } 316 | 317 | /** 318 | * @brief nginx module's proccess to create main configuration 319 | * 320 | * @param cf A ngx_conf_t pointer to the main configuration cycle 321 | * @return A pointer with the module configuration that has been created 322 | * @note We use the configuration memory pool to create it 323 | */ 324 | 325 | static void * 326 | ngx_http_log_zmq_create_main_conf(ngx_conf_t *cf) 327 | { 328 | ngx_http_log_zmq_main_conf_t *bkmc; 329 | 330 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->cycle->log, 0, "log_zmq: create_main_conf()"); 331 | 332 | bkmc = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_zmq_main_conf_t)); 333 | if (bkmc == NULL) { 334 | ngx_log_error(NGX_LOG_INFO, cf->log, 0, "\"log_zmq\" error creating main configuration"); 335 | return NULL; 336 | } 337 | 338 | bkmc->cycle = cf->cycle; 339 | bkmc->log = cf->log; 340 | bkmc->logs = ngx_array_create(cf->pool, 4, sizeof(ngx_http_log_zmq_element_conf_t)); 341 | if (bkmc->logs == NULL) { 342 | ngx_log_error(NGX_LOG_INFO, cf->log, 0, "\"log_zmq\" error creating main definitions"); 343 | return NULL; 344 | } 345 | ngx_memzero(bkmc->logs->elts, bkmc->logs->size); 346 | 347 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->cycle->log, 0, "log_zmq: create_main_conf(): return OK"); 348 | 349 | return bkmc; 350 | } 351 | 352 | /** 353 | * @brief nginx module's proccess to init main configuration 354 | * 355 | * @param cf A ngx_conf_t pointer to the main configuration cycle 356 | * @param conf A pointer to the module's main configuration 357 | * @return NGX_CONF_OK 358 | */ 359 | 360 | static char * 361 | ngx_http_log_zmq_init_main_conf(ngx_conf_t *cf, void *conf) 362 | { 363 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: init_main_conf()"); 364 | 365 | if (conf == NULL) { 366 | ngx_log_error(NGX_LOG_INFO, cf->log, 0, "\"log_zmq\" main configuration not defined"); 367 | return NGX_CONF_ERROR; 368 | } 369 | 370 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: init_main_conf(): return OK"); 371 | 372 | return NGX_CONF_OK; 373 | } 374 | 375 | /** 376 | * @brief nginx module's proccess to create location configuration 377 | * 378 | * After the nginx start it is necessary to create all location configuration. 379 | * For each location, we can have different configs. 380 | * 381 | * @param cf A ngx_conf_t pointer to the main nginx configuration 382 | * @return A pointer with the module configuration that has been created 383 | * @note We use the configuration memory pool to create it 384 | */ 385 | static void * 386 | ngx_http_log_zmq_create_loc_conf(ngx_conf_t *cf) 387 | { 388 | ngx_http_log_zmq_loc_conf_t *conf; 389 | 390 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: create_loc_conf()"); 391 | 392 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_zmq_loc_conf_t)); 393 | if (conf == NULL) { 394 | ngx_log_error(NGX_LOG_INFO, cf->log, 0, "\"log_zmq\" error creating location configuration"); 395 | return NGX_CONF_ERROR; 396 | } 397 | 398 | conf->off = 0; 399 | conf->logs = ngx_array_create(cf->pool, 4, sizeof(ngx_http_log_zmq_loc_element_conf_t)); 400 | if (conf->logs == NULL) { 401 | ngx_log_error(NGX_LOG_INFO, cf->log, 0, "\"log_zmq\" error creating location elements"); 402 | return NGX_CONF_ERROR; 403 | } 404 | ngx_memzero(conf->logs->elts, conf->logs->size); 405 | conf->logs_definition = NGX_CONF_UNSET_PTR; 406 | conf->log = cf->log; 407 | 408 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: create_loc_conf(): return OK"); 409 | 410 | return conf; 411 | } 412 | 413 | /** 414 | * @brief nginx module's proccess to merge all location configuration 415 | * 416 | * To avoid a lot of memory allocation and to be possible to have similar 417 | * configurations, this proccess merge all data with a logical tree. 418 | * 419 | * @param cf A ngx_conf_t pointer to the main nginx configurion 420 | * @param parent A pointer to the parent configuration relatively to this 421 | * @param child A pointer to the child configuration relatively to this 422 | * @return A char pointer which represents the status NGX_CONF_ERROR | NGX_CONF_OK 423 | * @warning It's important to ensure that all variables are passed 424 | * between parents and childs 425 | */ 426 | static char * 427 | ngx_http_log_zmq_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) 428 | { 429 | ngx_http_log_zmq_main_conf_t *bkmc; 430 | ngx_http_log_zmq_loc_conf_t *prev = parent; 431 | ngx_http_log_zmq_loc_conf_t *conf = child; 432 | ngx_http_log_zmq_element_conf_t *element; 433 | ngx_http_log_zmq_element_conf_t *curelement; 434 | ngx_http_log_zmq_loc_element_conf_t *locelement; 435 | ngx_uint_t i, j, found; 436 | 437 | bkmc = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_zmq_module); 438 | 439 | if (bkmc == NULL) { 440 | ngx_log_error(NGX_LOG_INFO, cf->log, 0, "\"log_zmq\" main configuration not defined"); 441 | return NGX_CONF_ERROR; 442 | } 443 | 444 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: merge_loc_conf()"); 445 | 446 | if (NULL == conf->log) { 447 | conf->log = prev->log; 448 | } 449 | 450 | if (NULL == conf->logs_definition || NGX_CONF_UNSET_PTR == conf->logs_definition) { 451 | conf->logs_definition = (ngx_array_t *) prev->logs_definition; 452 | } 453 | 454 | if (prev->logs_definition && NGX_CONF_UNSET_PTR != prev->logs_definition) { 455 | element = (ngx_http_log_zmq_element_conf_t *) prev->logs_definition->elts; 456 | } else { 457 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: merge_loc_conf(): empty configuration"); 458 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: merge_loc_conf(): return OK"); 459 | 460 | return NGX_CONF_OK; 461 | } 462 | 463 | if (NULL == conf->logs || NGX_CONF_UNSET_PTR == conf->logs) { 464 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: merge_loc_conf(): no log reference"); 465 | conf->logs = ngx_array_create(cf->pool, 4, sizeof(ngx_http_log_zmq_loc_element_conf_t)); 466 | if (conf->logs == NULL) { 467 | ngx_log_error(NGX_LOG_INFO, cf->log, 0, "\"log_zmq\": error creating location logs"); 468 | return NGX_CONF_ERROR; 469 | } 470 | ngx_memzero(conf->logs->elts, conf->logs->size); 471 | } 472 | 473 | for (i = 0; i < prev->logs_definition->nelts; i++) { 474 | found = 0; 475 | locelement = conf->logs->elts; 476 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: merge_loc_conf(): verify \"%V\"", element[i].name); 477 | for (j = 0; j < conf->logs->nelts; j++) { 478 | curelement = locelement[j].element; 479 | if (element[i].name->len == curelement->name->len 480 | && ngx_strncmp(element[i].name->data, curelement->name->data, element[i].name->len) == 0) { 481 | found = 1; 482 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: merge_loc_conf(): \"%V\" found, off==%d", 483 | element[i].name, locelement[j].off); 484 | } 485 | } 486 | if (found == 0) { 487 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: merge_loc_conf(): \"%V\" not found", element[i].name); 488 | locelement = ngx_array_push(conf->logs); 489 | ngx_memzero(locelement, sizeof(ngx_http_log_zmq_loc_element_conf_t)); 490 | locelement->off = 0; 491 | locelement->element = element + i; 492 | } 493 | } 494 | #if (NGX_DEBUG) 495 | locelement = conf->logs->elts; 496 | for (i = 0; i < conf->logs->nelts; i++) { 497 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: merge_loc_conf(): \"%V\": off==%d", 498 | locelement[i].element->name, locelement[i].off); 499 | } 500 | #endif 501 | 502 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: merge_loc_conf(): return OK"); 503 | 504 | return NGX_CONF_OK; 505 | } 506 | 507 | /** 508 | * @brief nginx module's set server 509 | * 510 | * We set the server configuration here. We should introduce a valid url, to the 511 | * connection (it will be prepended with tcp://), the type of connection (zmq). 512 | * After this, we have two numbers, the first is the number of threads created by 513 | * the ZMQ context and the last one is the queue limit for this setting. 514 | * 515 | * @code{.conf} 516 | * log_zmq_server 127.0.0.1:5555 zmq 10 10000; 517 | * @endcode 518 | * 519 | * @param cf A ngx_conf_t pointer to the main nginx configurion 520 | * @param cmd A pointer to ngx_commant_t that defines the configuration line 521 | * @param conf A pointer to the configuration received 522 | * @return A char pointer which represents the status NGX_CONF_ERROR | NGX_CONF_OK 523 | * @warning It's important to rearrange this to permit MORE2 arguments and not TAKE4 524 | */ 525 | static char * 526 | ngx_http_log_zmq_set_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 527 | { 528 | ngx_http_log_zmq_main_conf_t *bkmc; 529 | ngx_http_log_zmq_loc_conf_t *llcf = conf; 530 | ngx_http_log_zmq_element_conf_t *lecf; 531 | ngx_http_log_zmq_loc_element_conf_t *lelcf; 532 | ngx_str_t *value; 533 | const unsigned char *kind; 534 | ngx_int_t iothreads; 535 | ngx_int_t qlen; 536 | ngx_url_t u; 537 | ngx_log_zmq_server_t *endpoint; 538 | char *connection; 539 | size_t connlen; 540 | size_t zmq_hdlen; 541 | 542 | bkmc = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_zmq_module); 543 | 544 | if (cf->cmd_type != NGX_HTTP_MAIN_CONF) { 545 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the \"log_zmq_server\" directive can only used in \"http\" context"); 546 | return NGX_CONF_ERROR; 547 | } 548 | 549 | if (bkmc == NULL) { 550 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "no \"log_zmq\" main configuration defined"); 551 | return NGX_CONF_ERROR; 552 | } 553 | 554 | /* value[0] variable name 555 | * value[1] definition name 556 | * value[2] server/target 557 | * value[3] protocol type 558 | * value[4] number of threads 559 | * value[5] queue len 560 | */ 561 | value = cf->args->elts; 562 | 563 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_server(): definition \"%V\"", &value[1]); 564 | lecf = ngx_http_log_zmq_create_definition(cf, bkmc, &value[1]); 565 | 566 | if (NULL == lecf) { 567 | return NGX_CONF_ERROR; 568 | } 569 | 570 | /* set the location logs to main configuration logs */ 571 | llcf->logs_definition = (ngx_array_t *) bkmc->logs; 572 | 573 | if (lecf->sset == 1) { 574 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_server\": \"%V\" was initializated before", &value[1]); 575 | return NGX_CONF_ERROR; 576 | } 577 | 578 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_server(): loc definition \"%V\"", &value[1]); 579 | lelcf = ngx_http_log_zmq_create_location_element(cf, llcf, &value[1]); 580 | 581 | if (NULL == lelcf) { 582 | return NGX_CONF_ERROR; 583 | } 584 | 585 | /* create ZMQ context structure */ 586 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_server(): create context"); 587 | 588 | lecf->ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_zmq_ctx_t)); 589 | if (NULL == lecf->ctx) { 590 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_server\": error creating context \"%V\"", &value[1]); 591 | return NGX_CONF_ERROR; 592 | } 593 | 594 | lecf->ctx->log = cf->cycle->log; 595 | 596 | /* update definition name and cycle log*/ 597 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_server(): set definition name"); 598 | 599 | lecf->name = ngx_palloc(cf->pool, sizeof(ngx_str_t)); 600 | if (lecf->name == NULL) { 601 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_server\": error setting name \"%V\"", &value[1]); 602 | return NGX_CONF_ERROR; 603 | } 604 | lecf->name->data = ngx_palloc(cf->pool, value[1].len); 605 | lecf->name->len = value[1].len; 606 | ngx_memcpy(lecf->name->data, value[1].data, value[1].len); 607 | 608 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_server(): initialize element \"%V\"", &value[1]); 609 | lecf->log = cf->cycle->log; 610 | lecf->off = 0; 611 | 612 | /* set the type of protocol TCP|IPC|INPROC */ 613 | kind = value[3].data; 614 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_server(): server kind \"%V\"", &value[3]); 615 | 616 | endpoint = ngx_pcalloc(cf->pool, sizeof(ngx_log_zmq_server_t)); 617 | 618 | if (endpoint == NULL) { 619 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_server\": error creating endpoint \"%V\"", &value[1]); 620 | return NGX_CONF_ERROR; 621 | } 622 | 623 | if (0 == ngx_strcmp(kind, ZMQ_TCP_KEY)) { 624 | endpoint->kind = TCP; 625 | } else if (0 == ngx_strcmp(kind, ZMQ_IPC_KEY)) { 626 | endpoint->kind = IPC; 627 | } else if (0 == ngx_strcmp(kind, ZMQ_INPROC_KEY)) { 628 | endpoint->kind = INPROC; 629 | } else { 630 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_server\": invalid ZMQ connection type: %s \"%V\"", kind, &value[1]); 631 | return NGX_CONF_ERROR; 632 | } 633 | 634 | /* set the number of threads associated with this context */ 635 | iothreads = ngx_atoi(value[4].data, value[4].len); 636 | 637 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_server(): iothreads \"%V\"", &value[4]); 638 | 639 | if (iothreads == NGX_ERROR || iothreads <= 0) { 640 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_server\": invalid I/O threads %d \"%V\"", iothreads, &value[1]); 641 | return NGX_CONF_ERROR; 642 | } 643 | 644 | lecf->iothreads = iothreads; 645 | 646 | /* set the queue size associated with this context */ 647 | qlen = ngx_atoi(value[5].data, value[5].len); 648 | 649 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_server(): queue length \"%V\"", &value[5]); 650 | 651 | if (qlen == NGX_ERROR || qlen < 0) { 652 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_server\": invalid queue size %d \"%V\"", qlen, &value[1]); 653 | } 654 | 655 | lecf->qlen = qlen; 656 | 657 | /* if the protocol used is TCP, parse it and use nginx parse_url to validate the input */ 658 | if (endpoint->kind == TCP) { 659 | u.url = value[2]; 660 | u.default_port = __get_default_port(endpoint->kind); 661 | u.no_resolve = 0; 662 | u.listen = 1; 663 | 664 | if(ngx_parse_url(cf->pool, &u) != NGX_OK) { 665 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_server\": invalid server: %s \"%V\"", u.err, &value[1]); 666 | return NGX_CONF_ERROR; 667 | } 668 | endpoint->peer_addr = u.addrs[0]; 669 | } else { 670 | u.url = value[2]; 671 | } 672 | 673 | /* create a connection based on the protocol type */ 674 | switch (endpoint->kind) { 675 | case TCP: 676 | zmq_hdlen = ZMQ_TCP_HLEN; 677 | connlen = u.url.len + zmq_hdlen; 678 | connection = (char *) ngx_pcalloc(cf->pool, connlen + 1); 679 | ngx_memcpy(connection, ZMQ_TCP_HANDLER, zmq_hdlen); 680 | ngx_memcpy(&connection[zmq_hdlen], u.url.data, u.url.len); 681 | break; 682 | case IPC: 683 | zmq_hdlen = ZMQ_IPC_HLEN; 684 | connlen = u.url.len + zmq_hdlen; 685 | connection = (char *) ngx_pcalloc(cf->pool, connlen + 1); 686 | ngx_memcpy(connection, ZMQ_IPC_HANDLER, zmq_hdlen); 687 | ngx_memcpy(&connection[zmq_hdlen], u.url.data, u.url.len); 688 | break; 689 | case INPROC: 690 | zmq_hdlen = ZMQ_INPROC_HLEN; 691 | connlen = u.url.len + zmq_hdlen; 692 | connection = (char *) ngx_pcalloc(cf->pool, connlen + 1); 693 | ngx_memcpy(connection, ZMQ_INPROC_HANDLER, zmq_hdlen); 694 | ngx_memcpy(&connection[zmq_hdlen], u.url.data, u.url.len); 695 | break; 696 | default: 697 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_server\": invalid endpoint type \"%V\"", &value[1]); 698 | return NGX_CONF_ERROR; 699 | } 700 | 701 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_server(): connection %s", connection); 702 | 703 | if (NULL == connection) { 704 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_server\": error creating connection \"%V\"", &value[1]); 705 | return NGX_CONF_ERROR; 706 | } 707 | 708 | /* create the final connection endpoint to be used on socket connection */ 709 | endpoint->connection = ngx_palloc(cf->pool, sizeof(ngx_str_t)); 710 | endpoint->connection->data = ngx_palloc(cf->pool, connlen); 711 | endpoint->connection->len = connlen; 712 | ngx_memcpy(endpoint->connection->data, connection, connlen); 713 | lecf->server = endpoint; 714 | 715 | /* set the server as done */ 716 | lecf->sset = 1; 717 | 718 | /* by default, the configuration for this location is unmuted */ 719 | lelcf->element = (ngx_http_log_zmq_element_conf_t *) lecf; 720 | lelcf->off = 0; 721 | 722 | /* by default, the configuration is unmuted */ 723 | llcf->off = 0; 724 | 725 | ngx_pfree(cf->pool, connection); 726 | 727 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_server() return OK \"%V\"", &value[1]); 728 | 729 | return NGX_CONF_OK; 730 | } 731 | 732 | /** 733 | * @brief nginx module's set format 734 | * 735 | * This function evaluate the format string introducted in the configuration file. 736 | * The string is allocated and parsed to evaluate if it has any variables to 737 | * expand. This is the message sent to the log_zmq. 738 | * 739 | * @code{.conf} 740 | * log_zmq_format definition "put your stuff in here like vars $status" 741 | * @endcode 742 | * 743 | * @param cf A ngx_conf_t pointer to the main nginx configurion 744 | * @param cmd A pointer to ngx_commant_t that defines the configuration line 745 | * @param conf A pointer to the configuration received 746 | * @return A char pointer which represents the status NGX_CONF_ERROR | NGX_CONF_OK 747 | */ 748 | static char * 749 | ngx_http_log_zmq_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 750 | { 751 | ngx_http_log_zmq_main_conf_t *bkmc; 752 | ngx_http_log_zmq_loc_conf_t *llcf = conf; 753 | ngx_http_log_zmq_element_conf_t *lecf; 754 | ngx_http_log_zmq_loc_element_conf_t *lelcf; 755 | ngx_str_t *log_format, *value; 756 | ngx_http_script_compile_t sc; 757 | size_t i, len, log_len; 758 | u_char *p; 759 | 760 | bkmc = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_zmq_module); 761 | 762 | if (cf->cmd_type != NGX_HTTP_MAIN_CONF) { 763 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the \"log_zmq_format\" directive can only be used in \"http\" context"); 764 | return NGX_CONF_ERROR; 765 | } 766 | 767 | if (bkmc == NULL) { 768 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "no \"log_zmq\" main configuration defined"); 769 | return NGX_CONF_ERROR; 770 | } 771 | 772 | len = 0; 773 | log_len = 0; 774 | 775 | /* value[0] variable name 776 | * value[1] definition name 777 | * value[2] format 778 | */ 779 | value = cf->args->elts; 780 | 781 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_format(): definition \"%V\"", &value[1]); 782 | lecf = ngx_http_log_zmq_create_definition(cf, bkmc, &value[1]); 783 | 784 | if (NULL == lecf) { 785 | return NGX_CONF_ERROR; 786 | } 787 | 788 | /* set the location logs to main configuration logs */ 789 | llcf->logs_definition = (ngx_array_t *) bkmc->logs; 790 | 791 | if (lecf->fset == 1) { 792 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_format\" %V was initializated before", &value[1]); 793 | return NGX_CONF_ERROR; 794 | } 795 | 796 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_format(): loc definition \"%V\"", &value[1]); 797 | lelcf = ngx_http_log_zmq_create_location_element(cf, llcf, &value[1]); 798 | 799 | if (NULL == lelcf) { 800 | return NGX_CONF_ERROR; 801 | } 802 | 803 | /* this shoulnd get into this */ 804 | if (lecf->data_lengths != NULL) { 805 | ngx_pfree(cf->pool, lecf->data_lengths); 806 | lecf->data_lengths = NULL; 807 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_format(): clean data lengths"); 808 | } 809 | if (lecf->data_values != NULL) { 810 | ngx_pfree(cf->pool, lecf->data_values); 811 | lecf->data_values = NULL; 812 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_format(): clean data values"); 813 | } 814 | 815 | /* we support multiline logs format */ 816 | 817 | /* get the size of the log len (because multiline formats) */ 818 | for (i = 2; i < cf->args->nelts; i++) { 819 | log_len = log_len + value[i].len; 820 | } 821 | 822 | log_format = ngx_palloc(cf->pool, sizeof(ngx_str_t)); 823 | log_format->len = log_len; 824 | log_format->data = ngx_palloc(cf->pool, log_len + 1); 825 | 826 | p = &(log_format->data[0]); 827 | 828 | for (i = 2; i < cf->args->nelts; i++) { 829 | len = value[i].len; 830 | ngx_memcpy(p, value[i].data, len); 831 | p = p + len; 832 | } 833 | 834 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_format(): value \"%V\"", &value[2]); 835 | 836 | /* recompile all together */ 837 | ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); 838 | sc.cf = cf; 839 | sc.source = log_format; 840 | sc.lengths = &(lecf->data_lengths); 841 | sc.values = &(lecf->data_values); 842 | sc.variables = ngx_http_script_variables_count(log_format); 843 | sc.complete_lengths = 1; 844 | sc.complete_values = 1; 845 | 846 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_format(): compile"); 847 | 848 | if (ngx_http_script_compile(&sc) != NGX_OK) { 849 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_format\": error compiling format \"%V\"", &value[1]); 850 | return NGX_CONF_ERROR; 851 | } 852 | 853 | /* set the format as done */ 854 | lecf->fset = 1; 855 | 856 | /* by default, this location have all configuration elements unmuted */ 857 | lelcf->element = (ngx_http_log_zmq_element_conf_t *) lecf; 858 | lelcf->off = 0; 859 | 860 | /* by default, this location is unmuted */ 861 | llcf->off = 0; 862 | 863 | ngx_pfree(cf->pool, log_format); 864 | 865 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_format() return OK \"%V\"", &value[1]); 866 | 867 | return NGX_CONF_OK; 868 | } 869 | /** 870 | * @brief nginx module's set endpoint 871 | * 872 | * Like ngx_http_log_zmq_set_format this function is pre-compiled. This is the endpoint 873 | * for the zmq message. To receive messages we have to be listening this topic. By nature 874 | * this endpoint can be dynamic in the same way we have variables in the configuration file. 875 | * 876 | * @code{.conf} 877 | * log_zmq_endpoint definition "/servers/nginx/$domain" 878 | * @endcode 879 | * 880 | * @param cf A ngx_conf_t pointer to the main nginx configurion 881 | * @param cmd A pointer to ngx_commant_t that defines the configuration line 882 | * @param conf A pointer to the configuration received 883 | * @return A char pointer which represents the status NGX_CONF_ERROR | NGX_CONF_OK 884 | * @note XXX it can be refactor (similar to the set_format) 885 | */ 886 | static char * 887 | ngx_http_log_zmq_set_endpoint(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 888 | { 889 | ngx_http_log_zmq_main_conf_t *bkmc; 890 | ngx_http_log_zmq_loc_conf_t *llcf = conf; 891 | ngx_http_log_zmq_element_conf_t *lecf; 892 | ngx_http_log_zmq_loc_element_conf_t *lelcf; 893 | ngx_str_t *value; 894 | ngx_http_script_compile_t sc; 895 | 896 | bkmc = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_zmq_module); 897 | 898 | if (cf->cmd_type != NGX_HTTP_MAIN_CONF) { 899 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the \"log_zmq_endpoint\" directive can only used in \"http\" context"); 900 | return NGX_CONF_ERROR; 901 | } 902 | 903 | if (bkmc == NULL) { 904 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "no \"log_zmq\" main configuration defined"); 905 | return NGX_CONF_ERROR; 906 | } 907 | 908 | /* value[0] variable name 909 | * value[1] definition name 910 | * value[2] endpoint 911 | */ 912 | 913 | value = cf->args->elts; 914 | 915 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_endpoint(): definition \"%V\"", &value[1]); 916 | lecf = ngx_http_log_zmq_create_definition(cf, bkmc, &value[1]); 917 | 918 | if (NULL == lecf) { 919 | return NGX_CONF_ERROR; 920 | } 921 | 922 | /* set the location logs to main configuration logs */ 923 | llcf->logs_definition = (ngx_array_t *) bkmc->logs; 924 | 925 | if (lecf->eset == 1) { 926 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_endpoint\" %V was initializated before", &value[1]); 927 | return NGX_CONF_ERROR; 928 | } 929 | 930 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_endpoint(): loc definition \"%V\"", &value[1]); 931 | lelcf = ngx_http_log_zmq_create_location_element(cf, llcf, &value[1]); 932 | 933 | if (NULL == lelcf) { 934 | return NGX_CONF_ERROR; 935 | } 936 | 937 | if (lecf->endpoint_lengths != NULL) { 938 | ngx_pfree(cf->pool, lecf->endpoint_lengths); 939 | lecf->endpoint_lengths = NULL; 940 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_endpoint(): clean endpoint lengths"); 941 | } 942 | if (lecf->endpoint_values != NULL) { 943 | ngx_pfree(cf->pool, lecf->endpoint_values); 944 | lecf->endpoint_values = NULL; 945 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_endpoint(): clean endpoint values"); 946 | } 947 | 948 | /* the endpoint is a string where we can place some nginx environment variables which are compiled 949 | * each time we process them. here we evaluate this set of data and prepare them to be used */ 950 | ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); 951 | sc.cf = cf; 952 | sc.source = &value[2]; 953 | sc.lengths = &(lecf->endpoint_lengths); 954 | sc.values = &(lecf->endpoint_values); 955 | sc.variables = ngx_http_script_variables_count(&value[2]); 956 | sc.complete_lengths = 1; 957 | sc.complete_values = 1; 958 | 959 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_endpoint(): compile"); 960 | 961 | if (ngx_http_script_compile(&sc) != NGX_OK) { 962 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_endpoint\": error compiling format \"%V\"", &value[1]); 963 | return NGX_CONF_ERROR; 964 | } 965 | 966 | /* mark the endpoint as setted */ 967 | lecf->eset = 1; 968 | 969 | lelcf->element = (ngx_http_log_zmq_element_conf_t *) lecf; 970 | lelcf->off = 0; 971 | llcf->off = 0; 972 | 973 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_endpoint() return OK \"%V\"", &value[1]); 974 | 975 | return NGX_CONF_OK; 976 | } 977 | 978 | static char * 979 | ngx_http_log_zmq_set_off(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 980 | { 981 | ngx_http_log_zmq_main_conf_t *bkmc; 982 | ngx_http_log_zmq_loc_conf_t *llcf = conf; 983 | ngx_http_log_zmq_element_conf_t *lecf; 984 | ngx_http_log_zmq_loc_element_conf_t *lelcf; 985 | ngx_str_t *value; 986 | ngx_uint_t i, found = 0; 987 | 988 | bkmc = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_zmq_module); 989 | 990 | if (NULL == bkmc) { 991 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "no \"log_zmq\" main configuration defined"); 992 | return NGX_CONF_ERROR; 993 | } 994 | 995 | if (NULL == bkmc->logs || NGX_CONF_UNSET_PTR == bkmc->logs) { 996 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq\" doesn't have any log defined"); 997 | return NGX_CONF_ERROR; 998 | } 999 | 1000 | llcf->logs_definition = (ngx_array_t *) bkmc->logs; 1001 | 1002 | /* value[0] variable name 1003 | * value[1] definition name 1004 | */ 1005 | value = cf->args->elts; 1006 | 1007 | if ((value[1].len == 3) && (ngx_strncmp(value[1].data, "all", value[1].len) == 0)) { 1008 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_off(): all"); 1009 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_off(): return OK"); 1010 | llcf->off = 1; 1011 | return NGX_CONF_OK; 1012 | } 1013 | 1014 | /* let's verify if we are muting an existent definition */ 1015 | lecf = bkmc->logs->elts; 1016 | for (i = 0; i < bkmc->logs->nelts; i++) { 1017 | if (lecf[i].name->len == value[1].len 1018 | && ngx_strncmp(lecf[i].name->data, value[1].data, lecf[i].name->len) == 0) { 1019 | lecf = lecf + i; 1020 | found = 1; 1021 | break; 1022 | } 1023 | } 1024 | 1025 | if (!found) { 1026 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq_off\": \"%V\" definition not found", &value[1]); 1027 | return NGX_CONF_ERROR; 1028 | } 1029 | 1030 | llcf->off = 0; 1031 | found = 0; 1032 | 1033 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_off(): loc definition \"%V\"", &value[1]); 1034 | lelcf = ngx_http_log_zmq_create_location_element(cf, llcf, &value[1]); 1035 | 1036 | if (NULL == lelcf) { 1037 | return NGX_CONF_ERROR; 1038 | } 1039 | 1040 | lelcf->off = 1; 1041 | lelcf->element = (ngx_http_log_zmq_element_conf_t *) lecf; 1042 | 1043 | ngx_log_debug3(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_off(): \"%V\", off=%d (\"%V\")", 1044 | lelcf->element->name, lelcf->off, &value[1]); 1045 | 1046 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: set_off(): return OK \"%V\"", &value[1]); 1047 | 1048 | return NGX_CONF_OK; 1049 | } 1050 | 1051 | /** 1052 | * @brief nginx module after the configuration was submited 1053 | * 1054 | * In this phase of the module initiation we push our handler to the 1055 | * core handler list to be proccessed each request 1056 | * 1057 | * @param cf A ngx_conf_t pointer to the main nginx configurion 1058 | * @return A ngx_int_t which can be NGX_ERROR | NGX_OK 1059 | */ 1060 | static ngx_int_t 1061 | ngx_http_log_zmq_postconf(ngx_conf_t *cf) 1062 | { 1063 | ngx_http_core_main_conf_t *cmcf; 1064 | ngx_http_handler_pt *h; 1065 | 1066 | cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); 1067 | 1068 | h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers); 1069 | if (h == NULL) { 1070 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->cycle->log, 0, "log_zmq: postconf(): error pushing handler"); 1071 | return NGX_ERROR; 1072 | } 1073 | 1074 | *h = ngx_http_log_zmq_handler; 1075 | 1076 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->cycle->log, 0, "log_zmq: postconf(): return OK"); 1077 | 1078 | return NGX_OK; 1079 | } 1080 | 1081 | /** 1082 | * @brief nginx module after exit the master proccess 1083 | * 1084 | * We are exiting nginx and, to avoid memory problems, we clean all 1085 | * stuff we created before. 1086 | * 1087 | * @param cycle A ngx_cycle_t pointer to the current nginx cycle 1088 | * @return Nothing 1089 | */ 1090 | static void 1091 | ngx_http_log_zmq_exitmaster(ngx_cycle_t *cycle) 1092 | { 1093 | } 1094 | static ngx_http_log_zmq_element_conf_t * 1095 | ngx_http_log_zmq_create_definition(ngx_conf_t *cf, ngx_http_log_zmq_main_conf_t *bkmc, ngx_str_t *name) 1096 | { 1097 | ngx_http_log_zmq_element_conf_t *lecf = NULL; 1098 | ngx_uint_t i, found; 1099 | 1100 | found = 0; 1101 | 1102 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: create_definition(): \"%V\"", name); 1103 | 1104 | if (bkmc->logs && bkmc->logs != NGX_CONF_UNSET_PTR) { 1105 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: create_definition(): search \"%V\"", name); 1106 | lecf = bkmc->logs->elts; 1107 | for (i = 0; i < bkmc->logs->nelts; i++) { 1108 | if (lecf[i].name->len == name->len 1109 | && ngx_strncmp(lecf[i].name->data, name->data, lecf[i].name->len) == 0) { 1110 | lecf = lecf + i; 1111 | found = 1; 1112 | break; 1113 | } 1114 | } 1115 | } else { 1116 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: create_definition(): empty definitions"); 1117 | bkmc->logs = ngx_array_create(cf->pool, 4, sizeof(ngx_http_log_zmq_element_conf_t)); 1118 | if (bkmc->logs == NULL) { 1119 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq\": error creating space for definitions \"%V\"", name); 1120 | return NULL; 1121 | } 1122 | ngx_memzero(bkmc->logs->elts, bkmc->logs->size); 1123 | } 1124 | if (!found) { 1125 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: create_definition(): create definition \"%V\"", name); 1126 | lecf = ngx_array_push(bkmc->logs); 1127 | 1128 | if (NULL == lecf) { 1129 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq\": error creating definitions \"%V\"", name); 1130 | return NULL; 1131 | } 1132 | ngx_memzero(lecf, sizeof(ngx_http_log_zmq_element_conf_t)); 1133 | } 1134 | 1135 | return lecf; 1136 | } 1137 | 1138 | static ngx_http_log_zmq_loc_element_conf_t * 1139 | ngx_http_log_zmq_create_location_element(ngx_conf_t *cf, ngx_http_log_zmq_loc_conf_t *llcf, ngx_str_t *name) 1140 | { 1141 | ngx_http_log_zmq_loc_element_conf_t *lelcf = NULL; 1142 | ngx_uint_t i, found; 1143 | 1144 | found = 0; 1145 | 1146 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: create_location_element(): \"%V\"", name); 1147 | 1148 | if (llcf->logs && llcf->logs != NGX_CONF_UNSET_PTR) { 1149 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: create_location_element(): search \"%V\"", name); 1150 | lelcf = llcf->logs->elts; 1151 | for (i = 0; i < llcf->logs->nelts; i++) { 1152 | if (lelcf[i].element->name->len == name->len 1153 | && ngx_strncmp(lelcf[i].element->name->data, name->data, lelcf[i].element->name->len) == 0) { 1154 | lelcf = lelcf + i; 1155 | found = 1; 1156 | break; 1157 | } 1158 | } 1159 | } else { 1160 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: create_location_element(): empty location definitions"); 1161 | llcf->logs = ngx_array_create(cf->pool, 4, sizeof(ngx_http_log_zmq_loc_element_conf_t)); 1162 | if (llcf->logs == NULL) { 1163 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq\": error creating location log \"%V\"", name); 1164 | return NULL; 1165 | } 1166 | } 1167 | 1168 | if (!found) { 1169 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "log_zmq: create_location_element(): create location definition \"%V\"", name); 1170 | lelcf = ngx_array_push(llcf->logs); 1171 | if (NULL == lelcf) { 1172 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"log_zmq\": error creating location log \"%V\"", name); 1173 | return NULL; 1174 | } 1175 | ngx_memzero(lelcf, sizeof(ngx_http_log_zmq_loc_element_conf_t)); 1176 | } 1177 | 1178 | return lelcf; 1179 | } 1180 | -------------------------------------------------------------------------------- /src/ngx_http_log_zmq_module.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright (c) 2014-2015 by SAPO - PT Comunicações 3 | * Copyright (c) 2014 by Altice Labs 4 | * 5 | *****************************************************************************/ 6 | 7 | /** 8 | * @file ngx_http_log_zmq_module.h 9 | * @author Dani Bento 10 | * @date 1 March 2014 11 | * @brief Brokerlog Module Header 12 | * 13 | * @see http://www.zeromq.org/ 14 | */ 15 | 16 | #ifndef NGX_HTTP_BROKERLOG_H 17 | 18 | #define NGX_HTTP_BROKERLOG_H 1 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | /** 26 | * @brief define a type to use as an address structure 27 | * 28 | * This type is used to evaluate the url configuration 29 | */ 30 | typedef ngx_addr_t ngx_log_zmq_addr_t; 31 | 32 | /** 33 | * @brief ZMQ protocols 34 | * 35 | */ 36 | typedef enum{ 37 | TCP = 0, 38 | IPC, 39 | INPROC 40 | } ngx_log_zmq_server_kind; 41 | 42 | /** 43 | * @brief representation of a zmq server 44 | * 45 | * We have the address, the type of the connection and the final 46 | * string with the connection name (prepended with tcp://) 47 | */ 48 | typedef struct { 49 | ngx_log_zmq_addr_t peer_addr; /**< Address URL */ 50 | ngx_log_zmq_server_kind kind; /**< Type of server (TCP|IPC|INPROC) */ 51 | ngx_str_t *connection; /**< Final connection string 52 | tcp://: 53 | ipc:// 54 | inproc:// */ 55 | } ngx_log_zmq_server_t; 56 | 57 | /** 58 | * @brief module's context 59 | * 60 | * Define essencial variables to maintain the context of the ZMQ conection 61 | * during all module phases and nginx requests 62 | */ 63 | typedef struct { 64 | ngx_log_t *log; /**< Pointer to the logger */ 65 | ngx_int_t iothreads; /**< Number of threads to create */ 66 | void *zmq_context; /**< The ZMQ Context Initiator */ 67 | void *zmq_socket; /**< The ZMQ Socket to use */ 68 | int ccreated; /**< Was the context created? */ 69 | int screated; /**< Was the socket created? */ 70 | } ngx_http_log_zmq_ctx_t; 71 | 72 | /** 73 | * @brief element log configuration 74 | * 75 | * @note nginx has a ngx flag type, we should change sset/fset/eset to that type 76 | */ 77 | typedef struct { 78 | ngx_log_zmq_server_t *server; /**< Configuration server */ 79 | ngx_int_t iothreads; /**< Configuration number of threads */ 80 | ngx_int_t qlen; /**< Configuration queue length */ 81 | ngx_array_t *data_lengths; /**< Data length after format and compiling */ 82 | ngx_array_t *data_values; /**< Data values */ 83 | ngx_array_t *endpoint_lengths; /**< Endpoint length after format and compiling */ 84 | ngx_array_t *endpoint_values; /**< Endpoint values */ 85 | ngx_cycle_t *cycle; /**< Current configuration cycle */ 86 | ngx_http_log_zmq_ctx_t *ctx; /**< Current module context */ 87 | ngx_str_t *name; /**< Configuration name */ 88 | ngx_log_t *log; /**< Pointer to the logger */ 89 | ngx_uint_t sset; /**< Was the server setted? */ 90 | ngx_uint_t fset; /**< Was the format setted? */ 91 | ngx_uint_t eset; /**< Was the endpoint setted? */ 92 | ngx_uint_t off; /**< Is this element deactivated? */ 93 | } ngx_http_log_zmq_element_conf_t; 94 | 95 | /** 96 | * @brief location log configuration 97 | */ 98 | typedef struct { 99 | ngx_uint_t off; /**< Is this element deactivated? */ 100 | ngx_http_log_zmq_element_conf_t *element; /**< Pointer to the log definition */ 101 | } ngx_http_log_zmq_loc_element_conf_t; 102 | 103 | /** 104 | * @brief location configuration 105 | * 106 | * @note nginx as ngx flag type, we should change off to that type 107 | */ 108 | typedef struct { 109 | ngx_array_t *logs; /**< Array of logs to handle in this location */ 110 | ngx_uint_t off; /**< Should we off all the logs in this location? */ 111 | ngx_log_t *log; /**< Pointer to the logger */ 112 | ngx_array_t *logs_definition; /**< Pointer to the main conf logs definition */ 113 | } ngx_http_log_zmq_loc_conf_t; 114 | 115 | /** 116 | * @brief module main configuration 117 | * 118 | * @note for now, this configuration doesn't has any use, but we should mantain it for futher requests 119 | */ 120 | typedef struct { 121 | ngx_cycle_t *cycle; /**< Pointer to the current nginx cycle */ 122 | ngx_log_t *log; /**< Pointer to the logger */ 123 | ngx_array_t *logs; /**< Array of logs definitions */ 124 | } ngx_http_log_zmq_main_conf_t; 125 | 126 | #include "ngx_http_log_zmq.h" 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /valgrind.supp: -------------------------------------------------------------------------------- 1 | { 2 | 3 | Memcheck:Param 4 | socketcall.sendto(msg) 5 | fun:send 6 | ... 7 | } 8 | { 9 | 10 | Memcheck:Param 11 | socketcall.send(msg) 12 | fun:send 13 | ... 14 | } 15 | --------------------------------------------------------------------------------