├── Makefile ├── SECURITY.md ├── zlog-config.h ├── LICENSE ├── README.md ├── zlog.h ├── example.c ├── .github └── workflows │ ├── codacy.yml │ ├── codeql.yml │ └── codeql-analysis.yml ├── meson.build └── zlog.c /Makefile: -------------------------------------------------------------------------------- 1 | # In order to compile in DEBUG mode, simply add -D DEBUG flag to gcc. 2 | # If you dont want debug mode, simply delete it. 3 | 4 | default: info 5 | 6 | info: 7 | gcc -Wall -Wextra example.c zlog.c -o example -lpthread 8 | ./example 9 | 10 | debug: 11 | gcc -Wall -Wextra example.c zlog.c -o example -lpthread -D DEBUG 12 | ./example -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | main | :white_check_mark: | 11 | 12 | ## Reporting a Vulnerability 13 | 14 | Please email/message https://github.com/zma . 15 | -------------------------------------------------------------------------------- /zlog-config.h: -------------------------------------------------------------------------------- 1 | #ifndef ZLOG_CONFIG_H_ 2 | # define ZLOG_CONFIG_H_ 3 | 4 | // #define ZLOG_DISABLE_LOG 1 5 | #define ZLOG_BUFFER_STR_MAX_LEN 512 6 | #define ZLOG_BUFFER_SIZE (0x1 << 22) 7 | // ZLOG_BUFFER_TIME_STR_MAX_LEN must < ZLOG_BUFFER_STR_MAX_LEN 8 | #define ZLOG_BUFFER_TIME_STR_MAX_LEN 64 9 | 10 | // only for debug, enabling this will slow down the log 11 | // #define ZLOG_FORCE_FLUSH_BUFFER 12 | 13 | #define ZLOG_FLUSH_INTERVAL_SEC 180 14 | #define ZLOG_SLEEP_TIME_SEC 10 15 | // In practice: flush size < .8 * BUFFER_SIZE 16 | #define ZLOG_BUFFER_FLUSH_SIZE (0.8 * ZLOG_BUFFER_SIZE) 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zlog - a C In-memory Logging Library 2 | 3 | Hompage: https://www.ericzma.com/projects/zlog/ 4 | 5 | ## Introduction ## 6 | 7 | zlog is a C in-memory logging library. It allocates a buffer in memory for logging, and flush the buffer to the log file (or stdout) when the buffer is full, or it is instructed explicitly by the program or flushing thread. 8 | 9 | ### Usage example ### 10 | 11 | Example.c represents an use example of zlog library containing both INFO 12 | and DEBUG messages. If you want to include DEBUG messages you must compile 13 | with *-D DEBUG* flag. 14 | 15 | Makefile contains the corresponding gcc compilation commands to both INFO 16 | and DEBUG mode. Please keep in mind that DEBUG mode will log INFO and 17 | DEBUG messages whilst INFO mode will discard all DEBUG messages. The 18 | following Make commands can be used to compile either in DEBUG or INFO modes: 19 | 20 | * ``make`` or ``make info`` for **INFO** mode compilation. 21 | * ``make debug`` for **DEBUG** mode compilation. 22 | 23 | ## Source code ## 24 | 25 | Source code of zlog can be downloaded from http://github.com/zma/zlog/ . The source code is released into the public domain. 26 | 27 | ## Authors and contributors ## 28 | 29 | - Eric Ma (https://www.ericzma.com). 30 | - RazviOverflow (https://github.com/RazviOverflow) 31 | 32 | -------------------------------------------------------------------------------- /zlog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Zlog utility 3 | * By: Eric Ma https://www.ericzma.com 4 | * Released under Unlicense 5 | */ 6 | 7 | #ifndef ZLOG_H_ 8 | # define ZLOG_H_ 9 | 10 | #include 11 | 12 | #define ZLOG_LOC __FILE__, __LINE__ 13 | 14 | #define ZLOG_DEBUG_LOG_MSG 1 15 | #define ZLOG_INFO_LOG_MSG 0 16 | 17 | #ifdef DEBUG 18 | #define ZLOG_LOG_LEVEL 1 19 | #else 20 | #define ZLOG_LOG_LEVEL 0 21 | #endif 22 | 23 | extern FILE* zlog_fout; 24 | extern const char* zlog_file_log_name; 25 | 26 | // Start API 27 | 28 | // initialize zlog: flush to a log file 29 | void zlog_init(char const* log_file); 30 | // initialize zlog: flush to a STDOUT 31 | void zlog_init_stdout(void); 32 | // initialize zlog: flush to a STDERR 33 | void zlog_init_stderr(void); 34 | // creating a flushing thread 35 | void zlog_init_flush_thread(void); 36 | // create flush thread with flush interval 37 | void zlog_init_flush_thread_with_interval(int interval_sec); 38 | // finish using the zlog; clean up 39 | void zlog_finish(void); 40 | // Explicitly flush the buffer in memory 41 | void zlog_flush_buffer(void); 42 | 43 | // log an entry; using the printf format 44 | void zlogf(int msg_level, char const * fmt, ...); 45 | 46 | // log an entry with a timestamp 47 | void zlogf_time(int msg_level, char const * fmt, ...); 48 | 49 | // log an entry with the filename and location; 50 | // the first 2 arguments can be replaced by ZLOG_LOC which 51 | // will be filled by the compiler 52 | void zlog(int msg_level, char* filename, int line, char const * fmt, ...); 53 | 54 | // log an entry with the filename and location with a timestamp 55 | void zlog_time(int msg_level, char* filename, int line, char const * fmt, ...); 56 | 57 | // return where logs are being written (file absolute path) 58 | const char* zlog_get_log_file_name(void); 59 | 60 | // End API 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /example.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Bug reports to: Zhiqiang Ma (http://www.ericzma.com) 3 | * An example of zlog usage 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "zlog.h" 12 | 13 | int main(int argc, char* argv[]) 14 | { 15 | int i = 0; 16 | 17 | // log to stdout 18 | zlog_init_stdout(); 19 | 20 | // or log to file 21 | // zlog_init("/tmp/zlog.log"); 22 | 23 | // Optional: create flushing thread that flush the log 24 | // for each period of time 25 | // Otherwise, the in-memory log is flushed when the buffer 26 | // if full 27 | zlog_init_flush_thread(); 28 | 29 | // start to use the in-memory log 30 | 31 | // with timestamp 32 | zlogf_time(ZLOG_DEBUG_LOG_MSG, "zlog is initialized (debug)\n"); 33 | zlogf_time(ZLOG_INFO_LOG_MSG, "zlog is initialized (info)\n"); 34 | 35 | // without timestamp 36 | zlogf(ZLOG_INFO_LOG_MSG, "Command line: \n"); 37 | for (i = 0; i < argc; i++) { 38 | // use the directives as the format of printf 39 | zlogf(ZLOG_INFO_LOG_MSG, "argv[%d]: %s \n", i, argv[i]); 40 | zlogf(ZLOG_DEBUG_LOG_MSG, "(DEBUG) argv[%d]: %s \n", i, argv[i]); 41 | } 42 | zlogf(ZLOG_INFO_LOG_MSG, "\n\n"); 43 | 44 | zlogf_time(ZLOG_INFO_LOG_MSG, "I flush the buffer explicitly.\n"); 45 | 46 | zlogf(ZLOG_INFO_LOG_MSG, "This is just a ## [+] debug message [+] ##\n"); 47 | zlog_flush_buffer(); 48 | 49 | // with source code file and line info, and timestamp 50 | zlog_time(ZLOG_INFO_LOG_MSG, ZLOG_LOC, "Log with file and line. TIMESTAMPED.\n"); 51 | zlog_time(ZLOG_DEBUG_LOG_MSG, ZLOG_LOC, "(DEBUG) Log with file and line. TIMESTAMPED.\n"); 52 | 53 | // with source code file and line info, and without timestamp 54 | zlog(ZLOG_INFO_LOG_MSG, ZLOG_LOC, "Log with file and line. NO TIMESTAMP.\n"); 55 | 56 | // Example only: let the flushing thread work 57 | printf("FOR TEST: I will sleep for 200 seconds... Please be patient.\n"); 58 | sleep(200); 59 | 60 | zlogf_time(ZLOG_INFO_LOG_MSG, "finish using zlog\n"); 61 | 62 | // Before quit, finish zlog which will flush all the 63 | // logs in memory 64 | zlog_finish(); 65 | 66 | return 0; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /.github/workflows/codacy.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | # This workflow checks out code, performs a Codacy security scan 7 | # and integrates the results with the 8 | # GitHub Advanced Security code scanning feature. For more information on 9 | # the Codacy security scan action usage and parameters, see 10 | # https://github.com/codacy/codacy-analysis-cli-action. 11 | # For more information on Codacy Analysis CLI in general, see 12 | # https://github.com/codacy/codacy-analysis-cli. 13 | 14 | name: Codacy Security Scan 15 | 16 | on: 17 | push: 18 | branches: [ main ] 19 | pull_request: 20 | # The branches below must be a subset of the branches above 21 | branches: [ main ] 22 | schedule: 23 | - cron: '29 8 * * 2' 24 | 25 | permissions: 26 | contents: read 27 | 28 | jobs: 29 | codacy-security-scan: 30 | permissions: 31 | contents: read # for actions/checkout to fetch code 32 | security-events: write # for github/codeql-action/upload-sarif to upload SARIF results 33 | name: Codacy Security Scan 34 | runs-on: ubuntu-latest 35 | steps: 36 | # Checkout the repository to the GitHub Actions runner 37 | - name: Checkout code 38 | uses: actions/checkout@v3 39 | 40 | # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis 41 | - name: Run Codacy Analysis CLI 42 | uses: codacy/codacy-analysis-cli-action@d840f886c4bd4edc059706d09c6a1586111c540b 43 | with: 44 | # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository 45 | # You can also omit the token and run the tools that support default configurations 46 | project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} 47 | verbose: true 48 | output: results.sarif 49 | format: sarif 50 | # Adjust severity of non-security issues 51 | gh-code-scanning-compat: true 52 | # Force 0 exit code to allow SARIF file generation 53 | # This will handover control about PR rejection to the GitHub side 54 | max-allowed-issues: 2147483647 55 | 56 | # Upload the SARIF file generated in the previous step 57 | - name: Upload SARIF results file 58 | uses: github/codeql-action/upload-sarif@v2 59 | with: 60 | sarif_file: results.sarif 61 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # # 3 | # NAME: meson.build # 4 | # # 5 | # AUTHOR: Zhiqiang Ma. # 6 | # WRITTEN BY: Michael Brockus. # 7 | # # 8 | # License: Unlicense # 9 | # # 10 | ################################################################################### 11 | 12 | project('zlog', 'c', 13 | license : 'Unlicense', 14 | meson_version : '>=0.52.0', 15 | default_options : 16 | [ 17 | 'werror=true', 18 | 'optimization=3', 19 | 'warning_level=3' 20 | ] 21 | ) 22 | lang = 'c' 23 | cc = meson.get_compiler(lang) 24 | 25 | 26 | ## 27 | # 28 | # Meson: Add compiler flags 29 | # 30 | ## 31 | if cc.get_id() == 'clang' 32 | add_project_arguments(cc.get_supported_arguments( 33 | [ 34 | '-Wweak-vtables', '-Wexit-time-destructors', 35 | '-Wglobal-constructors', '-Wmissing-noreturn' 36 | ] 37 | ), language: lang) 38 | endif 39 | 40 | if cc.get_argument_syntax() == 'gcc' 41 | add_project_arguments(cc.get_supported_arguments( 42 | [ 43 | '-Wformat', '-Waddress', '-Winit-self', '-Wno-multichar', 44 | '-Wpointer-arith' , '-Wwrite-strings' , 45 | '-Wno-parentheses' , '-Wno-type-limits' , 46 | '-Wformat-security' , '-Wunreachable-code' , 47 | '-Waggregate-return' , '-Wformat-nonliteral' , 48 | '-Wmissing-prototypes' , '-Wold-style-definition' , 49 | '-Wmissing-declarations', '-Wmissing-include-dirs' , 50 | '-Wno-unused-parameter' , '-Wdeclaration-after-statement' 51 | ] 52 | ), language: lang) 53 | endif 54 | 55 | if cc.get_id() == 'msvc' 56 | add_project_arguments(cc.get_supported_arguments( 57 | [ 58 | '/w44265', '/w44061', '/w44062', 59 | '/wd4018', '/wd4146', '/wd4244', 60 | '/wd4305', 61 | ] 62 | ), language: lang) 63 | endif 64 | 65 | 66 | thread_dep = dependency('threads') 67 | 68 | 69 | zlog_lib = static_library(meson.project_name(), 70 | sources: ['zlog.c'], 71 | dependencies: thread_dep, 72 | include_directories: include_directories('.')) 73 | 74 | zlog_dep = declare_dependency( 75 | link_with: zlog_lib, 76 | include_directories: include_directories('.')) 77 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ main ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ main ] 20 | schedule: 21 | - cron: '44 5 * * 2' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'cpp' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ main ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ main ] 20 | schedule: 21 | - cron: '45 12 * * 6' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'cpp' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | -------------------------------------------------------------------------------- /zlog.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Zlog utility 3 | * By: Eric Ma https://www.ericzma.com 4 | * Released under Unlicense 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "zlog-config.h" 19 | #include "zlog.h" 20 | 21 | // -------------------------------------------------------------- 22 | // zlog utilities 23 | FILE* zlog_fout = NULL; 24 | const char* zlog_file_log_name = NULL; 25 | 26 | char _zlog_buffer[ZLOG_BUFFER_SIZE][ZLOG_BUFFER_STR_MAX_LEN]; 27 | int _zlog_buffer_size = 0; 28 | 29 | pthread_mutex_t _zlog_buffer_mutex = PTHREAD_MUTEX_INITIALIZER; 30 | // -------------------------------------------------------------- 31 | 32 | static inline void _zlog_buffer_lock(void) 33 | { 34 | pthread_mutex_lock(&_zlog_buffer_mutex); 35 | } 36 | 37 | static inline void _zlog_buffer_unlock(void) 38 | { 39 | pthread_mutex_unlock(&_zlog_buffer_mutex); 40 | } 41 | 42 | static void _zlog_flush_buffer(void) 43 | { 44 | int i = 0; 45 | for (i = 0; i < _zlog_buffer_size; i++) { 46 | fprintf(zlog_fout, "%s", _zlog_buffer[i]); 47 | } 48 | fflush(zlog_fout); 49 | _zlog_buffer_size = 0; 50 | } 51 | 52 | // first zlog_get_buffer, write to @return 53 | // then zlog_finish_buffer 54 | // 55 | // zlog_get_buffer may flush the buffer, which require I/O ops 56 | static inline char* zlog_get_buffer(void) 57 | { 58 | _zlog_buffer_lock(); 59 | if (_zlog_buffer_size == ZLOG_BUFFER_SIZE) { 60 | _zlog_flush_buffer(); 61 | } 62 | 63 | // allocate buffer 64 | _zlog_buffer_size++; 65 | return _zlog_buffer[_zlog_buffer_size-1]; 66 | } 67 | 68 | static inline void zlog_finish_buffer(void) 69 | { 70 | #ifdef ZLOG_FORCE_FLUSH_BUFFER 71 | _zlog_flush_buffer(); 72 | #endif 73 | _zlog_buffer_unlock(); 74 | } 75 | 76 | // Error reporting 77 | static inline void print_error(const char *function_name, char *error_msg){ 78 | fprintf(stderr, "Error in function %s: %s\n", function_name, error_msg); 79 | } 80 | 81 | // -------------------------------------------------------------- 82 | 83 | void zlog_init(char const* log_file) 84 | { 85 | zlog_file_log_name = strdup(log_file); 86 | 87 | zlog_fout = fopen(log_file, "a+"); 88 | 89 | if(!zlog_fout){ 90 | print_error(__func__, strerror(errno)); 91 | } 92 | } 93 | 94 | void zlog_init_stdout(void) 95 | { 96 | zlog_fout = stdout; 97 | } 98 | 99 | void zlog_init_stderr(void) 100 | { 101 | zlog_fout = stderr; 102 | } 103 | 104 | static void* zlog_buffer_flush_thread(void* interval_sec) 105 | { 106 | struct timeval tv; 107 | time_t lasttime; 108 | time_t curtime; 109 | int flush_interval = *(int*)interval_sec; 110 | free(interval_sec); 111 | int sleep_time_sec = ZLOG_SLEEP_TIME_SEC > flush_interval ? flush_interval : ZLOG_SLEEP_TIME_SEC; 112 | 113 | gettimeofday(&tv, NULL); 114 | 115 | lasttime = tv.tv_sec; 116 | 117 | do { 118 | sleep(sleep_time_sec); 119 | gettimeofday(&tv, NULL); 120 | curtime = tv.tv_sec; 121 | if ( (curtime - lasttime) >= flush_interval ) { 122 | // ZLOG_LOG_LEVEL is used to make the buffer flushing 123 | // seamlessly for the users. It does not matter what level 124 | // the messages are at this point because, if they do 125 | // not meet message level requirement, that wouldn't 126 | // have been buffered in the first place. 127 | zlog_flush_buffer(); 128 | lasttime = curtime; 129 | } else { 130 | _zlog_buffer_lock(); 131 | if (_zlog_buffer_size >= ZLOG_BUFFER_FLUSH_SIZE ) { 132 | _zlog_flush_buffer(); 133 | } 134 | _zlog_buffer_unlock(); 135 | } 136 | } while (1); 137 | return NULL; 138 | } 139 | 140 | void zlog_init_flush_thread(void) 141 | { 142 | zlog_init_flush_thread_with_interval(ZLOG_FLUSH_INTERVAL_SEC); 143 | } 144 | 145 | void zlog_init_flush_thread_with_interval(int interval_sec) 146 | { 147 | pthread_t thr; 148 | int* interval = (int*)malloc(sizeof(int)); 149 | *interval = interval_sec; 150 | pthread_create(&thr, NULL, zlog_buffer_flush_thread, (void*)interval); 151 | zlogf_time(ZLOG_LOG_LEVEL, "Flush thread is created.\n"); 152 | } 153 | 154 | void zlog_flush_buffer(void) 155 | { 156 | _zlog_buffer_lock(); 157 | _zlog_flush_buffer(); 158 | _zlog_buffer_unlock(); 159 | } 160 | 161 | void zlog_finish(void) 162 | { 163 | zlog_flush_buffer(); 164 | if (zlog_fout != stdout || zlog_fout != stderr) { 165 | fclose(zlog_fout); 166 | zlog_fout = stdout; 167 | } 168 | 169 | } 170 | 171 | inline void zlogf(int msg_level, char const * fmt, ...) 172 | { 173 | #ifdef ZLOG_DISABLE_LOG 174 | return ; 175 | #endif 176 | if(msg_level <= ZLOG_LOG_LEVEL){ 177 | va_list va; 178 | char* buffer = NULL; 179 | 180 | va_start(va, fmt); 181 | buffer = zlog_get_buffer(); 182 | 183 | vsnprintf(buffer, ZLOG_BUFFER_STR_MAX_LEN, fmt, va); 184 | zlog_finish_buffer(); 185 | va_end(va); 186 | } 187 | } 188 | 189 | void zlogf_time(int msg_level, char const * fmt, ...) 190 | { 191 | #ifdef ZLOG_DISABLE_LOG 192 | return ; 193 | #endif 194 | 195 | if(msg_level <= ZLOG_LOG_LEVEL){ 196 | char timebuf[ZLOG_BUFFER_TIME_STR_MAX_LEN]; 197 | struct timeval tv; 198 | //time_t curtime; 199 | char* buffer = NULL; 200 | 201 | // time_t ltime; 202 | // ltime = time(NULL); 203 | 204 | va_list va; 205 | 206 | gettimeofday(&tv, NULL); 207 | //curtime=tv.tv_sec; 208 | struct tm *tm_struct = localtime(&tv.tv_sec); 209 | snprintf(timebuf, ZLOG_BUFFER_TIME_STR_MAX_LEN, "%d:%02d:%d", tm_struct->tm_hour, tm_struct->tm_min, tm_struct->tm_sec); 210 | buffer = zlog_get_buffer(); 211 | snprintf(buffer, ZLOG_BUFFER_STR_MAX_LEN, "[%s.%06lds] ", timebuf, tv.tv_usec); 212 | buffer += strlen(timebuf) + 11; // space for time 213 | 214 | va_start(va, fmt); 215 | vsnprintf(buffer, ZLOG_BUFFER_STR_MAX_LEN, fmt, va); 216 | zlog_finish_buffer(); 217 | va_end(va); 218 | } 219 | } 220 | 221 | void zlog_time(int msg_level, char* filename, int line, char const * fmt, ...) 222 | { 223 | #ifdef ZLOG_DISABLE_LOG 224 | return ; 225 | #endif 226 | if(msg_level <= ZLOG_LOG_LEVEL){ 227 | static char timebuf[ZLOG_BUFFER_TIME_STR_MAX_LEN]; 228 | struct timeval tv; 229 | time_t curtime; 230 | char* buffer = NULL; 231 | 232 | va_list va; 233 | 234 | gettimeofday(&tv, NULL); 235 | curtime=tv.tv_sec; 236 | struct tm *tm_struct = localtime(&tv.tv_sec); 237 | snprintf(timebuf, ZLOG_BUFFER_TIME_STR_MAX_LEN, "%ld", curtime); 238 | snprintf(timebuf, ZLOG_BUFFER_TIME_STR_MAX_LEN, "%d:%02d:%d", tm_struct->tm_hour, tm_struct->tm_min, tm_struct->tm_sec); 239 | 240 | buffer = zlog_get_buffer(); 241 | snprintf(buffer, ZLOG_BUFFER_STR_MAX_LEN, "[%s.%06lds] [@%s:%d] ", timebuf, tv.tv_usec, filename, line); 242 | buffer += strlen(buffer); // print at most 5 digit of line 243 | 244 | va_start(va, fmt); 245 | vsnprintf(buffer, ZLOG_BUFFER_STR_MAX_LEN, fmt, va); 246 | zlog_finish_buffer(); 247 | va_end(va); 248 | } 249 | } 250 | 251 | void zlog(int msg_level, char* filename, int line, char const * fmt, ...) 252 | { 253 | #ifdef ZLOG_DISABLE_LOG 254 | return ; 255 | #endif 256 | if(msg_level <= ZLOG_LOG_LEVEL){ 257 | char* buffer = NULL; 258 | va_list va; 259 | 260 | buffer = zlog_get_buffer(); 261 | snprintf(buffer, ZLOG_BUFFER_STR_MAX_LEN, "[@%s:%d] ", filename, line); 262 | buffer += strlen(buffer); 263 | va_start(va, fmt); 264 | 265 | vsnprintf(buffer, ZLOG_BUFFER_STR_MAX_LEN, fmt, va); 266 | zlog_finish_buffer(); 267 | va_end(va); 268 | } 269 | } 270 | 271 | const char* zlog_get_log_file_name(void){ 272 | #ifdef ZLOG_DISABLE_LOG 273 | return ; 274 | #endif 275 | return zlog_file_log_name; 276 | } 277 | 278 | // End zlog utilities 279 | 280 | --------------------------------------------------------------------------------