├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── QTFFPlayer_zh_CN.ts ├── README.md ├── build-scripts ├── .DS_Store ├── init_library_for_macos.sh ├── init_library_for_ubuntu.sh └── init_qtffplayer_pc.sh └── src ├── base ├── IObserver.cpp ├── IObserver.h ├── IThread.cpp └── IThread.h ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui └── utils ├── log4z.cpp └── log4z.h /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | *.slo 3 | *.lo 4 | *.o 5 | *.a 6 | *.la 7 | *.lai 8 | *.so 9 | *.so.* 10 | *.dll 11 | *.dylib 12 | 13 | # Qt-es 14 | object_script.*.Release 15 | object_script.*.Debug 16 | *_plugin_import.cpp 17 | /.qmake.cache 18 | /.qmake.stash 19 | *.pro.user 20 | *.pro.user.* 21 | *.qbs.user 22 | *.qbs.user.* 23 | *.moc 24 | moc_*.cpp 25 | moc_*.h 26 | qrc_*.cpp 27 | ui_*.h 28 | *.qmlc 29 | *.jsc 30 | Makefile* 31 | #*build-* 32 | *cmake-build-* 33 | *.qm 34 | *.prl 35 | 36 | # Qt unit tests 37 | target_wrapper.* 38 | 39 | # QtCreator 40 | *.autosave 41 | 42 | # QtCreator Qml 43 | *.qmlproject.user 44 | *.qmlproject.user.* 45 | 46 | # QtCreator CMake 47 | CMakeLists.txt.user* 48 | 49 | # QtCreator 4.8< compilation database 50 | compile_commands.json 51 | 52 | # QtCreator local machine specific files for imported projects 53 | *creator.user* 54 | 55 | /output 56 | /temp 57 | /bin 58 | /lib 59 | /libs 60 | /source 61 | .idea 62 | *build-* 63 | /CMakeFiles 64 | .DS_Store 65 | *.mp4 66 | *.mp3 67 | *.zip 68 | *.yuv 69 | *.h264 70 | *.dylib 71 | *.a 72 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(QTFFPlayer VERSION 0.0.1 LANGUAGES CXX) 4 | 5 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 6 | 7 | set(CMAKE_AUTOUIC ON) 8 | set(CMAKE_AUTOMOC ON) 9 | set(CMAKE_AUTORCC ON) 10 | 11 | set(CMAKE_CXX_STANDARD 11) 12 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 13 | 14 | set(CMAKE_PREFIX_PATH "/Users/devyk/Data/qt/install/5/5.14.2/5.14.2/clang_64/lib/cmake") 15 | set(QT_VERSION_MAJOR 5) 16 | set(REQUIRED_LIBS Core Gui Widgets Multimedia OpenGL) 17 | set(REQUIRED_LIBS_QUALIFIED Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Multimedia Qt5::OpenGL) 18 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS ${REQUIRED_LIBS} REQUIRED) 19 | #平台判断 20 | if (WIN32) 21 | message("Now is windows") 22 | elseif (APPLE) 23 | message("Now is Apple systens.") 24 | elseif (ANDROID) 25 | message("Now is ANDROID systens.") 26 | elseif (UNIX) 27 | message("Now is UNIX systens.") 28 | endif () 29 | 30 | set(TS_FILES QTFFPlayer_zh_CN.ts) 31 | set(FFMPEG_PREFIX_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libs") 32 | message("CMAKE_HOST_SYSTEM_NAME--->${CMAKE_HOST_SYSTEM_NAME}") 33 | message("CMAKE_SYSTEM_NAME--->${CMAKE_SYSTEM_NAME}") 34 | 35 | message("FFMPEG_PREFIX_DIR=${FFMPEG_PREFIX_DIR}") 36 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/output/) 37 | set(FFMPEG_INCLUDE_DIRS "${FFMPEG_PREFIX_DIR}/include/") 38 | set(FFMPEG_LIB_DIRS "${FFMPEG_PREFIX_DIR}/lib/") 39 | 40 | set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) 41 | set(BASE_DIR ${SRC_DIR}/base) 42 | set(DECODE_DIR ${SRC_DIR}/decode) 43 | set(DEMUX_DIR ${SRC_DIR}/demux) 44 | set(RESAMPLE_DIR ${SRC_DIR}/resample) 45 | set(PROXY_DIR ${SRC_DIR}/proxy) 46 | set(WIDGET_DIR ${SRC_DIR}/widget) 47 | set(UTILS_DIR ${SRC_DIR}/utils) 48 | 49 | include_directories(${BASE_DIR}) 50 | include_directories(${DECODE_DIR}) 51 | include_directories(${DEMUX_DIR}) 52 | include_directories(${RESAMPLE_DIR}) 53 | include_directories(${PROXY_DIR}) 54 | include_directories(${WIDGET_DIR}) 55 | include_directories(${UTILS_DIR}) 56 | include_directories(${FFMPEG_INCLUDE_DIRS}) 57 | 58 | link_directories(${FFMPEG_LIB_DIRS}) 59 | 60 | 61 | set(PROJECT_SOURCES 62 | src/main.cpp 63 | src/mainwindow.cpp 64 | src/mainwindow.h 65 | src/mainwindow.ui 66 | ${TS_FILES} 67 | src/base/IThread.cpp 68 | src/base/IObserver.cpp 69 | src/utils/log4z.cpp 70 | ) 71 | add_library(QTFFPlayer SHARED 72 | ${PROJECT_SOURCES} 73 | ) 74 | add_executable(QTFFPlayer_GUI 75 | ${PROJECT_SOURCES} 76 | ) 77 | 78 | 79 | target_link_libraries(QTFFPlayer PRIVATE 80 | Qt${QT_VERSION_MAJOR}::Widgets 81 | #FFmpeg 支持 82 | avcodec avdevice avfilter avformat avutil swscale swresample 83 | ) 84 | 85 | target_link_libraries(QTFFPlayer_GUI PRIVATE 86 | Qt${QT_VERSION_MAJOR}::Widgets 87 | #FFmpeg 支持 88 | avcodec avdevice avfilter avformat avutil swscale swresample 89 | ) 90 | 91 | 92 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /QTFFPlayer_zh_CN.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MainWindow 6 | 7 | 8 | 9 | MainWindow 10 | 11 | 12 | 13 | 14 | 15 | 我是 MAC OS 系统 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QTFFPlayer 2 | MAC、Win、Linux、Android、IOS 跨平台播放器开发 3 | 4 | ##如何使用 5 | 6 | 1、cd build-scripts 7 | 8 | 2、执行编译 9 | 10 | **Mac** 11 | 12 | 第一个参数是编译平台,第二个是编译的目录,直接给当前项目的最对路径即可 13 | 14 | ./init_qtffplayer_pc.sh mac /Users/devyk/Data/qt/project/QTFFPlayer/libs 15 | 16 | **ubuntu** 17 | 18 | ./init_qtffplayer_pc.sh ubuntu /Users/devyk/Data/qt/project/QTFFPlayer/libs 19 | 20 | -------------------------------------------------------------------------------- /build-scripts/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangkun19921001/QTFFPlayer/686f417449df4ad268d6d9378f43bfb5ebefedb8/build-scripts/.DS_Store -------------------------------------------------------------------------------- /build-scripts/init_library_for_macos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | brew install pkg-config fdk-aac x264 yasm lame x265 zimg zmq libsoxr speex openjpeg libass xvid webp libvpx libvidstab theora snappy rubberband opus dav1d libbluray aom 5 | 6 | -------------------------------------------------------------------------------- /build-scripts/init_library_for_ubuntu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #参考 http://www.manks.top/ffmpeg-install-linux-centos.html#_label5 4 | 5 | sudo apt-get update && sudo apt-get install autoconf automake libfreetype6-dev libtool make pkg-config zlib1g zlib1g.dev clang yasm yasm libgnutls28-dev \ 6 | nasm libx264-dev libnuma-dev \ 7 | libx265-dev libnuma-dev libvpx-dev \ 8 | libfdk-aac-dev libmp3lame-dev libopus-dev \ 9 | libspeex-dev frei0r-plugins-dev libsdl2-2.0 libsdl2-dev libxss1 \ 10 | 11 | 12 | sudo apt-get install python3-pip && \ 13 | pip3 install --user meson \ 14 | 15 | 16 | 17 | if [ ! -d "../src" ]; then 18 | mkdir ../src 19 | fi 20 | 21 | 22 | # cd ../src/ 23 | # PREFIX=$(pwd)/../libs/ 24 | 25 | # #编译 nasm 26 | # echo ">>>>>>> start build nasm <<<<<<<<<" 27 | # curl -O -L https://www.nasm.us/pub/nasm/releasebuilds/2.15.05/nasm-2.15.05.tar.bz2 28 | # tar xjvf nasm-2.15.05.tar.bz2 29 | # cd nasm-2.15.05 30 | # ./autogen.sh 31 | # ./configure --prefix="$PREFIX" --bindir="$PREFIX/nasm-2.15.05/bin" 32 | # make 33 | # make install 34 | # ln -s $PREFIX/nasm-2.15.05/bin/nasm /usr/bin/nasm 35 | # cd .. 36 | 37 | # #编译 yasm 38 | # echo ">>>>>>> start build yasm <<<<<<<<<" 39 | # curl -O -L https://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz 40 | # tar xzvf yasm-1.3.0.tar.gz 41 | # cd yasm-1.3.0 42 | # ./configure --prefix="$PREFIX" --bindir="$PREFIX/yasm-1.3.0/bin" 43 | # make 44 | # make install 45 | # ln -s $PREFIX/yasm-1.3.0/bin/yasm /usr/bin/yasm 46 | # cd .. 47 | 48 | 49 | # #编译 libx264 50 | # echo ">>>>>>> start build libx264 <<<<<<<<<" 51 | # git clone --branch stable --depth 1 https://code.videolan.org/videolan/x264.git 52 | # cd x264 53 | # PKG_CONFIG_PATH="$PREFIX/pkgconfig" ./configure --prefix="$PREFIX" --bindir="$PREFIX/x264/bin" --enable-static 54 | # make 55 | # make install 56 | # cd .. 57 | 58 | # #编译 libx265 59 | # echo ">>>>>>> start build libx265 <<<<<<<<<" 60 | # git clone --branch stable --depth 2 https://bitbucket.org/multicoreware/x265_git 61 | # cd x265_git/build/linux 62 | # cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="$PREFIX" -DENABLE_SHARED:bool=off 63 | # make 64 | # make install 65 | # cd .. 66 | 67 | 68 | # #编译 libfdk_aac 69 | # echo ">>>>>>> start build libfdk_aac <<<<<<<<<" 70 | # git clone --depth 1 https://github.com/mstorsjo/fdk-aac 71 | # cd fdk-aac 72 | # autoreconf -fiv 73 | # ./configure --prefix="$PREFIX" --disable-shared 74 | # make 75 | # make install 76 | # cd .. 77 | 78 | # #编译 libmp3lame 79 | # echo ">>>>>>> start build libmp3lame <<<<<<<<<" 80 | # curl -O -L https://downloads.sourceforge.net/project/lame/lame/3.100/lame-3.100.tar.gz 81 | # tar xzvf lame-3.100.tar.gz 82 | # cd lame-3.100 83 | # ./configure --prefix="$PREFIX" --bindir="$PREFIX/lame-3.100/bin" --disable-shared --enable-nasm 84 | # make 85 | # make install 86 | # cd .. 87 | 88 | 89 | # #编译 libopus 90 | # echo ">>>>>>> start build libopus <<<<<<<<<" 91 | # curl -O -L https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz 92 | # tar xzvf opus-1.3.1.tar.gz 93 | # cd opus-1.3.1 94 | # ./configure --prefix="$PREFIX" --disable-shared 95 | # make 96 | # make install 97 | # cd .. 98 | 99 | 100 | # #编译 libvpx 101 | # echo ">>>>>>> start build libvpx <<<<<<<<<" 102 | # git clone --depth 1 https://chromium.googlesource.com/webm/libvpx.git 103 | # cd libvpx 104 | # ./configure --prefix="$PREFIX" --disable-examples --disable-unit-tests --enable-vp9-highbitdepth --as=yasm 105 | # make 106 | # make install 107 | # cd .. 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /build-scripts/init_qtffplayer_pc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #参考 https://lvv.me/blog/posts/2020/04/14_build_ffmpeg/ 3 | #https://blog.avdancedu.com/f3f66133/ 4 | 5 | set -e 6 | 7 | FFMPEG_VERSION=4.4 8 | 9 | FFMPEG_PREFIX=$2 10 | 11 | 12 | if [ ! -d "../source" ]; then 13 | mkdir ../source 14 | if [ ! -d "../source/ffmpeg" ]; then 15 | mkdir ../source/ffmpeg 16 | fi 17 | fi 18 | 19 | TARGET=$1 20 | 21 | 22 | if [ $TARGET == "mac" ] 23 | then 24 | echo "mac" 25 | chmod +x init_library_for_macos.sh 26 | ./init_library_for_macos.sh 27 | elif [ $TARGET == "ubuntu" ] 28 | then 29 | echo "ubuntu" 30 | chmod +x init_library_for_ubuntu.sh 31 | ./init_library_for_ubuntu.sh 32 | else 33 | echo "not found $1" 34 | fi 35 | 36 | 37 | cd ../source/ffmpeg 38 | 39 | echo $PWD 40 | 41 | 42 | if [ ! -d "ffmpeg-4.4" ]; then 43 | wget https://ffmpeg.org/releases/ffmpeg-4.4.tar.bz2 44 | tar -zxvf ffmpeg-4.4.tar.bz2 45 | fi 46 | 47 | cd ffmpeg-$FFMPEG_VERSION 48 | echo "--->$(pwd)" 49 | 50 | sudo rm -rf $FFMPEG_PREFIX 51 | 52 | 53 | ./configure \ 54 | --prefix=$FFMPEG_PREFIX \ 55 | --enable-shared \ 56 | --disable-static \ 57 | --enable-pthreads \ 58 | --enable-gpl \ 59 | --enable-nonfree \ 60 | --enable-libmp3lame \ 61 | --enable-libsnappy \ 62 | --enable-libtheora \ 63 | --enable-libx264 \ 64 | --enable-libx265 \ 65 | --enable-libfdk-aac \ 66 | --enable-libfontconfig \ 67 | --enable-libfreetype \ 68 | --enable-libspeex \ 69 | 70 | make -j8 71 | make install 72 | 73 | cd ../../../libs/ 74 | ls -lht 75 | 76 | 77 | -------------------------------------------------------------------------------- /src/base/IObserver.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangkun19921001/QTFFPlayer/686f417449df4ad268d6d9378f43bfb5ebefedb8/src/base/IObserver.cpp -------------------------------------------------------------------------------- /src/base/IObserver.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangkun19921001/QTFFPlayer/686f417449df4ad268d6d9378f43bfb5ebefedb8/src/base/IObserver.h -------------------------------------------------------------------------------- /src/base/IThread.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangkun19921001/QTFFPlayer/686f417449df4ad268d6d9378f43bfb5ebefedb8/src/base/IThread.cpp -------------------------------------------------------------------------------- /src/base/IThread.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangkun19921001/QTFFPlayer/686f417449df4ad268d6d9378f43bfb5ebefedb8/src/base/IThread.h -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | 3 | #include 4 | #include "log4z.h" 5 | using namespace zsummer::log4z; 6 | int main(int argc, char *argv[]) 7 | { 8 | ILog4zManager::getRef().start(); 9 | QApplication a(argc, argv); 10 | MainWindow w; 11 | w.show(); 12 | 13 | //begin test stream log input.... 14 | LOGT("stream input *** " << "LOGT LOGT LOGT LOGT" << " *** "); 15 | LOGD("stream input *** " << "LOGD LOGD LOGD LOGD" << " *** "); 16 | LOGI("stream input *** " << "LOGI LOGI LOGI LOGI" << " *** "); 17 | LOGW("stream input *** " << "LOGW LOGW LOGW LOGW" << " *** "); 18 | LOGE("stream input *** " << "LOGE LOGE LOGE LOGE" << " *** "); 19 | LOGA("stream input *** " << "LOGA LOGA LOGA LOGA" << " *** "); 20 | LOGF("stream input *** " << "LOGF LOGF LOGF LOGF" << " *** "); 21 | 22 | // cannot support VC6 or VS2003 23 | //begin test format log input.... 24 | LOGFMTT("format input *** %s *** %d ***", "LOGFMTT", 123456); 25 | LOGFMTD("format input *** %s *** %d ***", "LOGFMTD", 123456); 26 | LOGFMTI("format input *** %s *** %d ***", "LOGFMTI", 123456); 27 | LOGFMTW("format input *** %s *** %d ***", "LOGFMTW", 123456); 28 | LOGFMTE("format input *** %s *** %d ***", "LOGFMTE", 123456); 29 | LOGFMTA("format input *** %s *** %d ***", "LOGFMTA", 123456); 30 | LOGFMTF("format input *** %s *** %d ***", "LOGFMTF", 123456); 31 | 32 | LOGA("main quit ..."); 33 | return a.exec(); 34 | } 35 | -------------------------------------------------------------------------------- /src/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "./ui_mainwindow.h" 3 | #include 4 | 5 | extern "C"{ 6 | #include "libavcodec/avcodec.h" 7 | #include "libavutil/avutil.h" 8 | } 9 | 10 | MainWindow::MainWindow(QWidget *parent) 11 | : QMainWindow(parent) 12 | , ui(new Ui::MainWindow) 13 | { 14 | 15 | ui->setupUi(this); 16 | printf("Ffmpeg cmkae build = \n %s",avcodec_configuration()); 17 | } 18 | 19 | MainWindow::~MainWindow() 20 | { 21 | delete ui; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | 6 | QT_BEGIN_NAMESPACE 7 | namespace Ui { class MainWindow; } 8 | QT_END_NAMESPACE 9 | 10 | class MainWindow : public QMainWindow 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | MainWindow(QWidget *parent = nullptr); 16 | ~MainWindow(); 17 | 18 | private: 19 | Ui::MainWindow *ui; 20 | }; 21 | #endif // MAINWINDOW_H 22 | -------------------------------------------------------------------------------- /src/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 502 10 | 434 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 190 21 | 170 22 | 113 23 | 21 24 | 25 | 26 | 27 | 我是 MAC OS 系统 28 | 29 | 30 | 31 | 32 | 33 | 34 | 0 35 | 0 36 | 502 37 | 24 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/utils/log4z.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Log4z License 3 | * ----------- 4 | * 5 | * Log4z is licensed under the terms of the MIT license reproduced below. 6 | * This means that Log4z is free software and can be used for both academic 7 | * and commercial purposes at absolutely no cost. 8 | * 9 | * 10 | * =============================================================================== 11 | * 12 | * Copyright (C) 2010-2017 YaweiZhang . 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a copy 15 | * of this software and associated documentation files (the "Software"), to deal 16 | * in the Software without restriction, including without limitation the rights 17 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | * copies of the Software, and to permit persons to whom the Software is 19 | * furnished to do so, subject to the following conditions: 20 | * 21 | * The above copyright notice and this permission notice shall be included in 22 | * all copies or substantial portions of the Software. 23 | * 24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 | * THE SOFTWARE. 31 | * 32 | * =============================================================================== 33 | * 34 | * (end of COPYRIGHT) 35 | */ 36 | 37 | #include "log4z.h" 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | 52 | #ifdef WIN32 53 | #include 54 | #include 55 | #include 56 | #pragma comment(lib, "shlwapi") 57 | #pragma comment(lib, "User32.lib") 58 | #pragma warning(disable:4996) 59 | 60 | #else 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #endif 74 | 75 | 76 | #ifdef __APPLE__ 77 | #include "TargetConditionals.h" 78 | #include 79 | #if !TARGET_OS_IPHONE 80 | #define LOG4Z_HAVE_LIBPROC 81 | #include 82 | #endif 83 | #endif 84 | 85 | 86 | 87 | _ZSUMMER_BEGIN 88 | _ZSUMMER_LOG4Z_BEGIN 89 | 90 | static const char *const LOG_STRING[]= 91 | { 92 | "LOG_TRACE", 93 | "LOG_DEBUG", 94 | "LOG_INFO ", 95 | "LOG_WARN ", 96 | "LOG_ERROR", 97 | "LOG_ALARM", 98 | "LOG_FATAL", 99 | }; 100 | static const size_t LOG_STRING_LEN[] = 101 | { 102 | sizeof("LOG_TRACE") - 1, 103 | sizeof("LOG_DEBUG") - 1, 104 | sizeof("LOG_INFO") - 1, 105 | sizeof("LOG_WARN") - 1, 106 | sizeof("LOG_ERROR") - 1, 107 | sizeof("LOG_ALARM") - 1, 108 | sizeof("LOG_FATAL") - 1, 109 | }; 110 | 111 | #ifdef WIN32 112 | const static WORD LOG_COLOR[LOG_LEVEL_FATAL + 1] = { 113 | 0, 114 | 0, 115 | FOREGROUND_BLUE | FOREGROUND_GREEN, 116 | FOREGROUND_GREEN | FOREGROUND_RED, 117 | FOREGROUND_RED, 118 | FOREGROUND_GREEN, 119 | FOREGROUND_RED | FOREGROUND_BLUE }; 120 | #else 121 | 122 | const static char LOG_COLOR[LOG_LEVEL_FATAL + 1][50] = { 123 | "\e[0m", 124 | "\e[0m", 125 | "\e[34m\e[1m",//hight blue 126 | "\e[33m", //yellow 127 | "\e[31m", //red 128 | "\e[32m", //green 129 | "\e[35m" }; 130 | #endif 131 | 132 | ////////////////////////////////////////////////////////////////////////// 133 | //! Log4zFileHandler 134 | ////////////////////////////////////////////////////////////////////////// 135 | class Log4zFileHandler 136 | { 137 | public: 138 | Log4zFileHandler(){ _file = NULL; } 139 | ~Log4zFileHandler(){ close(); } 140 | inline bool isOpen(){ return _file != NULL; } 141 | inline long open(const char *path, const char * mod) 142 | { 143 | if (_file != NULL){fclose(_file);_file = NULL;} 144 | _file = fopen(path, mod); 145 | if (_file) 146 | { 147 | long tel = 0; 148 | long cur = ftell(_file); 149 | fseek(_file, 0L, SEEK_END); 150 | tel = ftell(_file); 151 | fseek(_file, cur, SEEK_SET); 152 | return tel; 153 | } 154 | return -1; 155 | } 156 | inline void clean(int index, int len) 157 | { 158 | #if !defined(__APPLE__) && !defined(WIN32) 159 | if (_file != NULL) 160 | { 161 | int fd = fileno(_file); 162 | fsync(fd); 163 | posix_fadvise(fd, index, len, POSIX_FADV_DONTNEED); 164 | fsync(fd); 165 | } 166 | #endif 167 | } 168 | inline void close() 169 | { 170 | if (_file != NULL){clean(0, 0); fclose(_file);_file = NULL;} 171 | } 172 | inline void write(const char * data, size_t len) 173 | { 174 | if (_file && len > 0) 175 | { 176 | if (fwrite(data, 1, len, _file) != len) 177 | { 178 | close(); 179 | } 180 | } 181 | } 182 | inline void flush(){ if (_file) fflush(_file); } 183 | 184 | inline std::string readLine() 185 | { 186 | char buf[500] = { 0 }; 187 | if (_file && fgets(buf, 500, _file) != NULL) 188 | { 189 | return std::string(buf); 190 | } 191 | return std::string(); 192 | } 193 | inline const std::string readContent(); 194 | inline bool removeFile(const std::string & path) { return ::remove(path.c_str()) == 0; } 195 | public: 196 | FILE *_file; 197 | }; 198 | 199 | 200 | ////////////////////////////////////////////////////////////////////////// 201 | //! UTILITY 202 | ////////////////////////////////////////////////////////////////////////// 203 | 204 | 205 | static void fixPath(std::string &path); 206 | static void trimLogConfig(std::string &str, std::string extIgnore = std::string()); 207 | static std::pair splitPairString(const std::string & str, const std::string & delimiter); 208 | 209 | 210 | static bool isDirectory(std::string path); 211 | static bool createRecursionDir(std::string path); 212 | static std::string getProcessID(); 213 | static std::string getProcessName(); 214 | 215 | 216 | 217 | ////////////////////////////////////////////////////////////////////////// 218 | //! LockHelper 219 | ////////////////////////////////////////////////////////////////////////// 220 | class LockHelper 221 | { 222 | public: 223 | LockHelper(); 224 | virtual ~LockHelper(); 225 | 226 | public: 227 | void lock(); 228 | void unLock(); 229 | private: 230 | #ifdef WIN32 231 | CRITICAL_SECTION _crit; 232 | #else 233 | pthread_mutex_t _crit; 234 | #endif 235 | }; 236 | 237 | ////////////////////////////////////////////////////////////////////////// 238 | //! AutoLock 239 | ////////////////////////////////////////////////////////////////////////// 240 | class AutoLock 241 | { 242 | public: 243 | explicit AutoLock(LockHelper & lk):_lock(lk){_lock.lock();} 244 | ~AutoLock(){_lock.unLock();} 245 | private: 246 | LockHelper & _lock; 247 | }; 248 | 249 | 250 | 251 | 252 | 253 | 254 | ////////////////////////////////////////////////////////////////////////// 255 | //! SemHelper 256 | ////////////////////////////////////////////////////////////////////////// 257 | class SemHelper 258 | { 259 | public: 260 | SemHelper(); 261 | virtual ~SemHelper(); 262 | public: 263 | bool create(int initcount); 264 | bool wait(int timeout = 0); 265 | bool post(); 266 | private: 267 | #ifdef WIN32 268 | HANDLE _hSem; 269 | #elif defined(__APPLE__) 270 | dispatch_semaphore_t _semid; 271 | #else 272 | sem_t _semid; 273 | bool _isCreate; 274 | #endif 275 | 276 | }; 277 | 278 | 279 | 280 | ////////////////////////////////////////////////////////////////////////// 281 | //! ThreadHelper 282 | ////////////////////////////////////////////////////////////////////////// 283 | #ifdef WIN32 284 | static unsigned int WINAPI threadProc(LPVOID lpParam); 285 | #else 286 | static void * threadProc(void * pParam); 287 | #endif 288 | 289 | class ThreadHelper 290 | { 291 | public: 292 | ThreadHelper(){_hThreadID = 0;} 293 | virtual ~ThreadHelper(){} 294 | public: 295 | bool start(); 296 | bool wait(); 297 | virtual void run() = 0; 298 | private: 299 | unsigned long long _hThreadID; 300 | #ifndef WIN32 301 | pthread_t _phtreadID; 302 | #endif 303 | }; 304 | 305 | #ifdef WIN32 306 | unsigned int WINAPI threadProc(LPVOID lpParam) 307 | { 308 | ThreadHelper * p = (ThreadHelper *) lpParam; 309 | p->run(); 310 | return 0; 311 | } 312 | #else 313 | void * threadProc(void * pParam) 314 | { 315 | ThreadHelper * p = (ThreadHelper *) pParam; 316 | p->run(); 317 | return NULL; 318 | } 319 | #endif 320 | 321 | 322 | ////////////////////////////////////////////////////////////////////////// 323 | //! LogData 324 | ////////////////////////////////////////////////////////////////////////// 325 | enum LogDataType 326 | { 327 | LDT_GENERAL, 328 | LDT_ENABLE_LOGGER, 329 | LDT_SET_LOGGER_NAME, 330 | LDT_SET_LOGGER_PATH, 331 | LDT_SET_LOGGER_LEVEL, 332 | LDT_SET_LOGGER_FILELINE, 333 | LDT_SET_LOGGER_DISPLAY, 334 | LDT_SET_LOGGER_OUTFILE, 335 | LDT_SET_LOGGER_LIMITSIZE, 336 | LDT_SET_LOGGER_MONTHDIR, 337 | LDT_SET_LOGGER_RESERVETIME, 338 | // LDT_SET_LOGGER_, 339 | }; 340 | 341 | 342 | ////////////////////////////////////////////////////////////////////////// 343 | //! LoggerInfo 344 | ////////////////////////////////////////////////////////////////////////// 345 | struct LoggerInfo 346 | { 347 | //! attribute 348 | std::string _key; //logger key 349 | std::string _name; // one logger one name. 350 | std::string _path; //path for log file. 351 | int _level; //filter level 352 | bool _display; //display to screen 353 | bool _outfile; //output to file 354 | bool _monthdir; //create directory per month 355 | unsigned int _limitsize; //limit file's size, unit Million byte. 356 | bool _enable; //logger is enable 357 | bool _fileLine; //enable/disable the log's suffix.(file name:line number) 358 | time_t _logReserveTime; //log file reserve time. unit is time second. 359 | //! runtime info 360 | time_t _curFileCreateTime; //file create time 361 | time_t _curFileCreateDay; //file create day time 362 | unsigned int _curFileIndex; //rolling file index 363 | unsigned int _curWriteLen; //current file length 364 | Log4zFileHandler _handle; //file handle. 365 | //!history 366 | std::list > _historyLogs; 367 | 368 | 369 | LoggerInfo() 370 | { 371 | _enable = false; 372 | _path = LOG4Z_DEFAULT_PATH; 373 | _level = LOG4Z_DEFAULT_LEVEL; 374 | _display = LOG4Z_DEFAULT_DISPLAY; 375 | _outfile = LOG4Z_DEFAULT_OUTFILE; 376 | 377 | _monthdir = LOG4Z_DEFAULT_MONTHDIR; 378 | _limitsize = LOG4Z_DEFAULT_LIMITSIZE; 379 | _fileLine = LOG4Z_DEFAULT_SHOWSUFFIX; 380 | 381 | _curFileCreateTime = 0; 382 | _curFileCreateDay = 0; 383 | _curFileIndex = 0; 384 | _curWriteLen = 0; 385 | _logReserveTime = 0; 386 | } 387 | }; 388 | 389 | 390 | ////////////////////////////////////////////////////////////////////////// 391 | //! LogerManager 392 | ////////////////////////////////////////////////////////////////////////// 393 | class LogerManager : public ThreadHelper, public ILog4zManager 394 | { 395 | public: 396 | LogerManager(); 397 | virtual ~LogerManager(); 398 | 399 | bool configFromStringImpl(std::string content, bool isUpdate); 400 | //! 读取配置文件并覆写 401 | virtual bool config(const char* configPath); 402 | virtual bool configFromString(const char* configContent); 403 | 404 | //! 覆写式创建 405 | virtual LoggerId createLogger(const char* key); 406 | virtual bool start(); 407 | virtual bool stop(); 408 | virtual bool prePushLog(LoggerId id, int level); 409 | virtual bool pushLog(LogData * pLog, const char * file, int line); 410 | //! 查找ID 411 | virtual LoggerId findLogger(const char* key); 412 | bool hotChange(LoggerId id, LogDataType ldt, int num, const std::string & text); 413 | virtual bool enableLogger(LoggerId id, bool enable); 414 | virtual bool setLoggerName(LoggerId id, const char * name); 415 | virtual bool setLoggerPath(LoggerId id, const char * path); 416 | virtual bool setLoggerLevel(LoggerId id, int nLevel); 417 | virtual bool setLoggerFileLine(LoggerId id, bool enable); 418 | virtual bool setLoggerDisplay(LoggerId id, bool enable); 419 | virtual bool setLoggerOutFile(LoggerId id, bool enable); 420 | virtual bool setLoggerLimitsize(LoggerId id, unsigned int limitsize); 421 | virtual bool setLoggerMonthdir(LoggerId id, bool enable); 422 | virtual bool setLoggerReserveTime(LoggerId id, time_t sec); 423 | virtual bool setAutoUpdate(int interval); 424 | virtual bool updateConfig(); 425 | virtual bool isLoggerEnable(LoggerId id); 426 | virtual unsigned long long getStatusTotalWriteCount(){return _ullStatusTotalWriteFileCount;} 427 | virtual unsigned long long getStatusTotalWriteBytes() { return _ullStatusTotalWriteFileBytes; } 428 | virtual unsigned long long getStatusTotalPushQueue() { return _ullStatusTotalPushLog; } 429 | virtual unsigned long long getStatusTotalPopQueue() { return _ullStatusTotalPopLog; } 430 | virtual unsigned int getStatusActiveLoggers(); 431 | protected: 432 | virtual LogData * makeLogData(LoggerId id, int level); 433 | virtual void freeLogData(LogData * log); 434 | void showColorText(const char *text, int level = LOG_LEVEL_DEBUG); 435 | bool onHotChange(LoggerId id, LogDataType ldt, int num, const std::string & text); 436 | bool openLogger(LogData * log); 437 | bool closeLogger(LoggerId id); 438 | bool popLog(LogData *& log); 439 | virtual void run(); 440 | private: 441 | 442 | //! thread status. 443 | bool _runing; 444 | //! wait thread started. 445 | SemHelper _semaphore; 446 | 447 | //! hot change name or path for one logger 448 | int _hotUpdateInterval; 449 | unsigned int _checksum; 450 | 451 | //! the process info. 452 | std::string _pid; 453 | std::string _proName; 454 | 455 | //! config file name 456 | std::string _configFile; 457 | 458 | //! logger id manager, [logger name]:[logger id]. 459 | std::map _ids; 460 | // the last used id of _loggers 461 | LoggerId _lastId; 462 | LoggerInfo _loggers[LOG4Z_LOGGER_MAX]; 463 | 464 | 465 | //! log queue 466 | char _chunk1[256]; 467 | LockHelper _logLock; 468 | std::deque _logs; 469 | unsigned long long _ullStatusTotalPushLog; 470 | 471 | char _chunk2[256]; 472 | LockHelper _freeLock; 473 | std::vector _freeLogDatas; 474 | 475 | char _chunk3[256]; 476 | //show color lock 477 | LockHelper _scLock; 478 | //status statistics 479 | //write file 480 | char _chunk4[256]; 481 | std::deque _logsCache; 482 | unsigned long long _ullStatusTotalPopLog; 483 | unsigned long long _ullStatusTotalWriteFileCount; 484 | unsigned long long _ullStatusTotalWriteFileBytes; 485 | }; 486 | 487 | 488 | 489 | 490 | ////////////////////////////////////////////////////////////////////////// 491 | //! Log4zFileHandler 492 | ////////////////////////////////////////////////////////////////////////// 493 | 494 | const std::string Log4zFileHandler::readContent() 495 | { 496 | std::string content; 497 | 498 | if (!_file) 499 | { 500 | return content; 501 | } 502 | char buf[BUFSIZ]; 503 | size_t ret = 0; 504 | do 505 | { 506 | ret = fread(buf, sizeof(char), BUFSIZ, _file); 507 | content.append(buf, ret); 508 | } 509 | while (ret == BUFSIZ); 510 | 511 | return content; 512 | } 513 | 514 | 515 | 516 | 517 | ////////////////////////////////////////////////////////////////////////// 518 | //! utility 519 | ////////////////////////////////////////////////////////////////////////// 520 | 521 | 522 | static inline void sleepMillisecond(unsigned int ms) 523 | { 524 | #ifdef WIN32 525 | ::Sleep(ms); 526 | #else 527 | usleep(1000*ms); 528 | #endif 529 | } 530 | 531 | static inline struct tm timeToTm(time_t t) 532 | { 533 | #ifdef WIN32 534 | #if _MSC_VER < 1400 //VS2003 535 | return * localtime(&t); 536 | #else //vs2005->vs2013-> 537 | struct tm tt = { 0 }; 538 | localtime_s(&tt, &t); 539 | return tt; 540 | #endif 541 | #else //linux 542 | struct tm tt = { 0 }; 543 | localtime_r(&t, &tt); 544 | return tt; 545 | #endif 546 | } 547 | 548 | 549 | 550 | 551 | static void fixPath(std::string &path) 552 | { 553 | if (path.empty()){return;} 554 | for (std::string::iterator iter = path.begin(); iter != path.end(); ++iter) 555 | { 556 | if (*iter == '\\'){*iter = '/';} 557 | } 558 | if (path.at(path.length()-1) != '/'){path.append("/");} 559 | } 560 | 561 | static void trimLogConfig(std::string &str, std::string extIgnore) 562 | { 563 | if (str.empty()){return;} 564 | extIgnore += "\r\n\t "; 565 | int length = (int)str.length(); 566 | int posBegin = 0; 567 | int posEnd = 0; 568 | 569 | //trim utf8 file bom 570 | if (str.length() >= 3 571 | && (unsigned char)str[0] == 0xef 572 | && (unsigned char)str[1] == 0xbb 573 | && (unsigned char)str[2] == 0xbf) 574 | { 575 | posBegin = 3; 576 | } 577 | 578 | //trim character 579 | for (int i = posBegin; i splitPairString(const std::string & str, const std::string & delimiter) 613 | { 614 | std::string::size_type pos = str.find(delimiter.c_str()); 615 | if (pos == std::string::npos) 616 | { 617 | return std::make_pair(str, ""); 618 | } 619 | return std::make_pair(str.substr(0, pos), str.substr(pos+delimiter.length())); 620 | } 621 | 622 | static bool parseConfigLine(const std::string& line, int curLineNum, std::string & key, std::map & outInfo) 623 | { 624 | std::pair kv = splitPairString(line, "="); 625 | if (kv.first.empty()) 626 | { 627 | return false; 628 | } 629 | 630 | trimLogConfig(kv.first); 631 | trimLogConfig(kv.second); 632 | if (kv.first.empty() || kv.first.at(0) == '#') 633 | { 634 | return true; 635 | } 636 | 637 | if (kv.first.at(0) == '[') 638 | { 639 | trimLogConfig(kv.first, "[]"); 640 | key = kv.first; 641 | { 642 | std::string tmpstr = kv.first; 643 | std::transform(tmpstr.begin(), tmpstr.end(), tmpstr.begin(), ::tolower); 644 | if (tmpstr == "main") 645 | { 646 | key = "Main"; 647 | } 648 | } 649 | std::map::iterator iter = outInfo.find(key); 650 | if (iter == outInfo.end()) 651 | { 652 | LoggerInfo li; 653 | li._enable = true; 654 | li._key = key; 655 | li._name = key; 656 | outInfo.insert(std::make_pair(li._key, li)); 657 | } 658 | else 659 | { 660 | printf("log4z configure warning: duplicate logger key:[%s] at line: %d \r\n", key.c_str(), curLineNum); 661 | } 662 | return true; 663 | } 664 | trimLogConfig(kv.first); 665 | trimLogConfig(kv.second); 666 | std::map::iterator iter = outInfo.find(key); 667 | if (iter == outInfo.end()) 668 | { 669 | printf("log4z configure warning: not found current logger name:[%s] at line:%d, key=%s, value=%s \r\n", 670 | key.c_str(), curLineNum, kv.first.c_str(), kv.second.c_str()); 671 | return true; 672 | } 673 | std::transform(kv.first.begin(), kv.first.end(), kv.first.begin(), ::tolower); 674 | //! path 675 | if (kv.first == "path") 676 | { 677 | iter->second._path = kv.second; 678 | return true; 679 | } 680 | else if (kv.first == "name") 681 | { 682 | iter->second._name = kv.second; 683 | return true; 684 | } 685 | std::transform(kv.second.begin(), kv.second.end(), kv.second.begin(), ::tolower); 686 | //! level 687 | if (kv.first == "level") 688 | { 689 | if (kv.second == "trace" || kv.second == "all") 690 | { 691 | iter->second._level = LOG_LEVEL_TRACE; 692 | } 693 | else if (kv.second == "debug") 694 | { 695 | iter->second._level = LOG_LEVEL_DEBUG; 696 | } 697 | else if (kv.second == "info") 698 | { 699 | iter->second._level = LOG_LEVEL_INFO; 700 | } 701 | else if (kv.second == "warn" || kv.second == "warning") 702 | { 703 | iter->second._level = LOG_LEVEL_WARN; 704 | } 705 | else if (kv.second == "error") 706 | { 707 | iter->second._level = LOG_LEVEL_ERROR; 708 | } 709 | else if (kv.second == "alarm") 710 | { 711 | iter->second._level = LOG_LEVEL_ALARM; 712 | } 713 | else if (kv.second == "fatal") 714 | { 715 | iter->second._level = LOG_LEVEL_FATAL; 716 | } 717 | } 718 | //! display 719 | else if (kv.first == "display") 720 | { 721 | if (kv.second == "false" || kv.second == "0") 722 | { 723 | iter->second._display = false; 724 | } 725 | else 726 | { 727 | iter->second._display = true; 728 | } 729 | } 730 | //! output to file 731 | else if (kv.first == "outfile") 732 | { 733 | if (kv.second == "false" || kv.second == "0") 734 | { 735 | iter->second._outfile = false; 736 | } 737 | else 738 | { 739 | iter->second._outfile = true; 740 | } 741 | } 742 | //! monthdir 743 | else if (kv.first == "monthdir") 744 | { 745 | if (kv.second == "false" || kv.second == "0") 746 | { 747 | iter->second._monthdir = false; 748 | } 749 | else 750 | { 751 | iter->second._monthdir = true; 752 | } 753 | } 754 | //! limit file size 755 | else if (kv.first == "limitsize") 756 | { 757 | iter->second._limitsize = atoi(kv.second.c_str()); 758 | } 759 | //! display log in file line 760 | else if (kv.first == "fileline") 761 | { 762 | if (kv.second == "false" || kv.second == "0") 763 | { 764 | iter->second._fileLine = false; 765 | } 766 | else 767 | { 768 | iter->second._fileLine = true; 769 | } 770 | } 771 | //! enable/disable one logger 772 | else if (kv.first == "enable") 773 | { 774 | if (kv.second == "false" || kv.second == "0") 775 | { 776 | iter->second._enable = false; 777 | } 778 | else 779 | { 780 | iter->second._enable = true; 781 | } 782 | } 783 | //! set reserve time 784 | else if (kv.first == "reserve") 785 | { 786 | iter->second._logReserveTime = atoi(kv.second.c_str()); 787 | } 788 | return true; 789 | } 790 | 791 | static bool parseConfigFromString(std::string content, std::map & outInfo) 792 | { 793 | 794 | std::string key; 795 | int curLine = 1; 796 | std::string line; 797 | std::string::size_type curPos = 0; 798 | if (content.empty()) 799 | { 800 | return true; 801 | } 802 | do 803 | { 804 | std::string::size_type pos = std::string::npos; 805 | for (std::string::size_type i = curPos; i < content.length(); ++i) 806 | { 807 | //support linux/unix/windows LRCF 808 | if (content[i] == '\r' || content[i] == '\n') 809 | { 810 | pos = i; 811 | break; 812 | } 813 | } 814 | line = content.substr(curPos, pos - curPos); 815 | parseConfigLine(line, curLine, key, outInfo); 816 | curLine++; 817 | 818 | if (pos == std::string::npos) 819 | { 820 | break; 821 | } 822 | else 823 | { 824 | curPos = pos+1; 825 | } 826 | } while (1); 827 | return true; 828 | } 829 | 830 | 831 | 832 | bool isDirectory(std::string path) 833 | { 834 | #ifdef WIN32 835 | return PathIsDirectoryA(path.c_str()) ? true : false; 836 | #else 837 | DIR * pdir = opendir(path.c_str()); 838 | if (pdir == NULL) 839 | { 840 | return false; 841 | } 842 | else 843 | { 844 | closedir(pdir); 845 | pdir = NULL; 846 | return true; 847 | } 848 | #endif 849 | } 850 | 851 | 852 | 853 | bool createRecursionDir(std::string path) 854 | { 855 | if (path.length() == 0) return true; 856 | std::string sub; 857 | fixPath(path); 858 | 859 | std::string::size_type pos = path.find('/'); 860 | while (pos != std::string::npos) 861 | { 862 | std::string cur = path.substr(0, pos-0); 863 | if (cur.length() > 0 && !isDirectory(cur)) 864 | { 865 | bool ret = false; 866 | #ifdef WIN32 867 | ret = CreateDirectoryA(cur.c_str(), NULL) ? true : false; 868 | #else 869 | ret = (mkdir(cur.c_str(), S_IRWXU|S_IRWXG|S_IRWXO) == 0); 870 | #endif 871 | if (!ret) 872 | { 873 | return false; 874 | } 875 | } 876 | pos = path.find('/', pos+1); 877 | } 878 | 879 | return true; 880 | } 881 | 882 | std::string getProcessID() 883 | { 884 | std::string pid = "0"; 885 | char buf[260] = {0}; 886 | #ifdef WIN32 887 | DWORD winPID = GetCurrentProcessId(); 888 | sprintf(buf, "%06u", winPID); 889 | pid = buf; 890 | #else 891 | sprintf(buf, "%06d", getpid()); 892 | pid = buf; 893 | #endif 894 | return pid; 895 | } 896 | 897 | 898 | std::string getProcessName() 899 | { 900 | std::string name = "process"; 901 | char buf[260] = {0}; 902 | #ifdef WIN32 903 | if (GetModuleFileNameA(NULL, buf, 259) > 0) 904 | { 905 | name = buf; 906 | } 907 | std::string::size_type pos = name.rfind("\\"); 908 | if (pos != std::string::npos) 909 | { 910 | name = name.substr(pos+1, std::string::npos); 911 | } 912 | pos = name.rfind("."); 913 | if (pos != std::string::npos) 914 | { 915 | name = name.substr(0, pos-0); 916 | } 917 | 918 | #elif defined(LOG4Z_HAVE_LIBPROC) 919 | proc_name(getpid(), buf, 260); 920 | name = buf; 921 | return name;; 922 | #else 923 | sprintf(buf, "/proc/%d/cmdline", (int)getpid()); 924 | Log4zFileHandler i; 925 | i.open(buf, "rb"); 926 | if (!i.isOpen()) 927 | { 928 | return name; 929 | } 930 | name = i.readLine(); 931 | i.close(); 932 | 933 | std::string::size_type pos = name.rfind("/"); 934 | if (pos != std::string::npos) 935 | { 936 | name = name.substr(pos+1, std::string::npos); 937 | } 938 | #endif 939 | 940 | 941 | return name; 942 | } 943 | 944 | 945 | 946 | 947 | 948 | 949 | ////////////////////////////////////////////////////////////////////////// 950 | // LockHelper 951 | ////////////////////////////////////////////////////////////////////////// 952 | LockHelper::LockHelper() 953 | { 954 | #ifdef WIN32 955 | InitializeCriticalSection(&_crit); 956 | #else 957 | //_crit = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; 958 | pthread_mutexattr_t attr; 959 | pthread_mutexattr_init(&attr); 960 | //pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_TIMED_NP); 961 | //pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 962 | pthread_mutex_init(&_crit, &attr); 963 | pthread_mutexattr_destroy(&attr); 964 | #endif 965 | } 966 | LockHelper::~LockHelper() 967 | { 968 | #ifdef WIN32 969 | DeleteCriticalSection(&_crit); 970 | #else 971 | pthread_mutex_destroy(&_crit); 972 | #endif 973 | } 974 | 975 | void LockHelper::lock() 976 | { 977 | #ifdef WIN32 978 | EnterCriticalSection(&_crit); 979 | #else 980 | pthread_mutex_lock(&_crit); 981 | #endif 982 | } 983 | void LockHelper::unLock() 984 | { 985 | #ifdef WIN32 986 | LeaveCriticalSection(&_crit); 987 | #else 988 | pthread_mutex_unlock(&_crit); 989 | #endif 990 | } 991 | ////////////////////////////////////////////////////////////////////////// 992 | // SemHelper 993 | ////////////////////////////////////////////////////////////////////////// 994 | SemHelper::SemHelper() 995 | { 996 | #ifdef WIN32 997 | _hSem = NULL; 998 | #elif defined(__APPLE__) 999 | _semid = NULL; 1000 | #else 1001 | _isCreate = false; 1002 | #endif 1003 | 1004 | } 1005 | SemHelper::~SemHelper() 1006 | { 1007 | #ifdef WIN32 1008 | if (_hSem != NULL) 1009 | { 1010 | CloseHandle(_hSem); 1011 | _hSem = NULL; 1012 | } 1013 | #elif defined(__APPLE__) 1014 | if (_semid) 1015 | { 1016 | dispatch_release(_semid); 1017 | _semid = NULL; 1018 | } 1019 | #else 1020 | if (_isCreate) 1021 | { 1022 | _isCreate = false; 1023 | sem_destroy(&_semid); 1024 | } 1025 | #endif 1026 | 1027 | } 1028 | 1029 | bool SemHelper::create(int initcount) 1030 | { 1031 | if (initcount < 0) 1032 | { 1033 | initcount = 0; 1034 | } 1035 | #ifdef WIN32 1036 | if (initcount > 64) 1037 | { 1038 | return false; 1039 | } 1040 | _hSem = CreateSemaphore(NULL, initcount, 64, NULL); 1041 | if (_hSem == NULL) 1042 | { 1043 | return false; 1044 | } 1045 | #elif defined(__APPLE__) 1046 | _semid = dispatch_semaphore_create(initcount); 1047 | if (!_semid) 1048 | { 1049 | return false; 1050 | } 1051 | #else 1052 | if (sem_init(&_semid, 0, initcount) != 0) 1053 | { 1054 | return false; 1055 | } 1056 | _isCreate = true; 1057 | #endif 1058 | 1059 | return true; 1060 | } 1061 | bool SemHelper::wait(int timeout) 1062 | { 1063 | #ifdef WIN32 1064 | if (timeout <= 0) 1065 | { 1066 | timeout = INFINITE; 1067 | } 1068 | if (WaitForSingleObject(_hSem, timeout) != WAIT_OBJECT_0) 1069 | { 1070 | return false; 1071 | } 1072 | #elif defined(__APPLE__) 1073 | if (dispatch_semaphore_wait(_semid, dispatch_time(DISPATCH_TIME_NOW, timeout*1000)) != 0) 1074 | { 1075 | return false; 1076 | } 1077 | #else 1078 | if (timeout <= 0) 1079 | { 1080 | return (sem_wait(&_semid) == 0); 1081 | } 1082 | else 1083 | { 1084 | struct timeval tm; 1085 | gettimeofday(&tm, NULL); 1086 | long long endtime = tm.tv_sec *1000 + tm.tv_usec/1000 + timeout; 1087 | do 1088 | { 1089 | sleepMillisecond(50); 1090 | int ret = sem_trywait(&_semid); 1091 | if (ret == 0) 1092 | { 1093 | return true; 1094 | } 1095 | struct timeval tv_cur; 1096 | gettimeofday(&tv_cur, NULL); 1097 | if (tv_cur.tv_sec*1000 + tv_cur.tv_usec/1000 > endtime) 1098 | { 1099 | return false; 1100 | } 1101 | 1102 | if (ret == -1 && errno == EAGAIN) 1103 | { 1104 | continue; 1105 | } 1106 | else 1107 | { 1108 | return false; 1109 | } 1110 | } while (true); 1111 | return false; 1112 | } 1113 | #endif 1114 | return true; 1115 | } 1116 | 1117 | bool SemHelper::post() 1118 | { 1119 | #ifdef WIN32 1120 | return ReleaseSemaphore(_hSem, 1, NULL) ? true : false; 1121 | #elif defined(__APPLE__) 1122 | return dispatch_semaphore_signal(_semid) == 0; 1123 | #else 1124 | return (sem_post(&_semid) == 0); 1125 | #endif 1126 | 1127 | } 1128 | 1129 | ////////////////////////////////////////////////////////////////////////// 1130 | //! ThreadHelper 1131 | ////////////////////////////////////////////////////////////////////////// 1132 | bool ThreadHelper::start() 1133 | { 1134 | #ifdef WIN32 1135 | unsigned long long ret = _beginthreadex(NULL, 0, threadProc, (void *) this, 0, NULL); 1136 | 1137 | if (ret == -1 || ret == 0) 1138 | { 1139 | printf("log4z: create log4z thread error! \r\n"); 1140 | return false; 1141 | } 1142 | _hThreadID = ret; 1143 | #else 1144 | int ret = pthread_create(&_phtreadID, NULL, threadProc, (void*)this); 1145 | if (ret != 0) 1146 | { 1147 | printf("log4z: create log4z thread error! \r\n"); 1148 | return false; 1149 | } 1150 | #endif 1151 | return true; 1152 | } 1153 | 1154 | bool ThreadHelper::wait() 1155 | { 1156 | #ifdef WIN32 1157 | if (WaitForSingleObject((HANDLE)_hThreadID, INFINITE) != WAIT_OBJECT_0) 1158 | { 1159 | return false; 1160 | } 1161 | #else 1162 | if (pthread_join(_phtreadID, NULL) != 0) 1163 | { 1164 | return false; 1165 | } 1166 | #endif 1167 | return true; 1168 | } 1169 | 1170 | ////////////////////////////////////////////////////////////////////////// 1171 | //! LogerManager 1172 | ////////////////////////////////////////////////////////////////////////// 1173 | LogerManager::LogerManager() 1174 | { 1175 | _runing = false; 1176 | _lastId = LOG4Z_MAIN_LOGGER_ID; 1177 | _hotUpdateInterval = 0; 1178 | 1179 | _ullStatusTotalPushLog = 0; 1180 | _ullStatusTotalPopLog = 0; 1181 | _ullStatusTotalWriteFileCount = 0; 1182 | _ullStatusTotalWriteFileBytes = 0; 1183 | 1184 | _pid = getProcessID(); 1185 | _proName = getProcessName(); 1186 | _loggers[LOG4Z_MAIN_LOGGER_ID]._enable = true; 1187 | _ids[LOG4Z_MAIN_LOGGER_KEY] = LOG4Z_MAIN_LOGGER_ID; 1188 | _loggers[LOG4Z_MAIN_LOGGER_ID]._key = LOG4Z_MAIN_LOGGER_KEY; 1189 | _loggers[LOG4Z_MAIN_LOGGER_ID]._name = LOG4Z_MAIN_LOGGER_KEY; 1190 | 1191 | _chunk1[0] = '\0'; 1192 | _chunk2[1] = '\0'; 1193 | _chunk3[2] = '\0'; 1194 | _chunk4[3] = '\0'; 1195 | } 1196 | LogerManager::~LogerManager() 1197 | { 1198 | stop(); 1199 | } 1200 | 1201 | 1202 | LogData * LogerManager::makeLogData(LoggerId id, int level) 1203 | { 1204 | LogData * pLog = NULL; 1205 | if (true) 1206 | { 1207 | if (!_freeLogDatas.empty()) 1208 | { 1209 | AutoLock l(_freeLock); 1210 | if (!_freeLogDatas.empty()) 1211 | { 1212 | pLog = _freeLogDatas.back(); 1213 | _freeLogDatas.pop_back(); 1214 | } 1215 | } 1216 | if (pLog == NULL) 1217 | { 1218 | pLog = new(malloc(sizeof(LogData) + LOG4Z_LOG_BUF_SIZE-1))LogData(); 1219 | } 1220 | } 1221 | //append precise time to log 1222 | if (true) 1223 | { 1224 | pLog->_id = id; 1225 | pLog->_level = level; 1226 | pLog->_type = LDT_GENERAL; 1227 | pLog->_typeval = 0; 1228 | pLog->_threadID = 0; 1229 | pLog->_contentLen = 0; 1230 | #ifdef WIN32 1231 | FILETIME ft; 1232 | GetSystemTimeAsFileTime(&ft); 1233 | unsigned long long now = ft.dwHighDateTime; 1234 | now <<= 32; 1235 | now |= ft.dwLowDateTime; 1236 | now /= 10; 1237 | now -= 11644473600000000ULL; 1238 | now /= 1000; 1239 | pLog->_time = now / 1000; 1240 | pLog->_precise = (unsigned int)(now % 1000); 1241 | #else 1242 | struct timeval tm; 1243 | gettimeofday(&tm, NULL); 1244 | pLog->_time = tm.tv_sec; 1245 | pLog->_precise = tm.tv_usec / 1000; 1246 | #endif 1247 | #ifdef WIN32 1248 | pLog->_threadID = GetCurrentThreadId(); 1249 | #elif defined(__APPLE__) 1250 | unsigned long long tid = 0; 1251 | pthread_threadid_np(NULL, &tid); 1252 | pLog->_threadID = (unsigned int) tid; 1253 | #else 1254 | pLog->_threadID = (unsigned int)syscall(SYS_gettid); 1255 | #endif 1256 | } 1257 | 1258 | //format log 1259 | if (true) 1260 | { 1261 | #ifdef WIN32 1262 | static __declspec(thread) tm g_tt = { 0 }; 1263 | static __declspec(thread) time_t g_curDayTime = 0 ; 1264 | #else 1265 | static __thread tm g_tt = { 0 }; 1266 | static __thread time_t g_curDayTime = 0; 1267 | #endif // WIN32 1268 | if (pLog->_time < g_curDayTime || pLog->_time >= g_curDayTime + 24*3600) 1269 | { 1270 | g_tt = timeToTm(pLog->_time); 1271 | g_tt.tm_hour = 0; 1272 | g_tt.tm_min = 0; 1273 | g_tt.tm_sec = 0; 1274 | g_curDayTime = mktime(&g_tt); 1275 | } 1276 | time_t sec = pLog->_time - g_curDayTime; 1277 | Log4zStream ls(pLog->_content, LOG4Z_LOG_BUF_SIZE); 1278 | ls.writeULongLong(g_tt.tm_year + 1900, 4); 1279 | ls.writeChar('-'); 1280 | ls.writeULongLong(g_tt.tm_mon + 1, 2); 1281 | ls.writeChar('-'); 1282 | ls.writeULongLong(g_tt.tm_mday, 2); 1283 | ls.writeChar(' '); 1284 | ls.writeULongLong(sec/3600, 2); 1285 | ls.writeChar(':'); 1286 | ls.writeULongLong((sec % 3600)/60 , 2); 1287 | ls.writeChar(':'); 1288 | ls.writeULongLong(sec % 60, 2); 1289 | ls.writeChar('.'); 1290 | ls.writeULongLong(pLog->_precise, 3); 1291 | ls.writeChar(' '); 1292 | ls.writeChar('['); 1293 | ls.writeULongLong(pLog->_threadID, 4); 1294 | ls.writeChar(']'); 1295 | 1296 | ls.writeChar(' '); 1297 | ls.writeString(LOG_STRING[pLog->_level], LOG_STRING_LEN[pLog->_level]); 1298 | ls.writeChar(' '); 1299 | pLog->_contentLen = ls.getCurrentLen(); 1300 | } 1301 | return pLog; 1302 | } 1303 | void LogerManager::freeLogData(LogData * log) 1304 | { 1305 | if (_freeLogDatas.size() < 200) 1306 | { 1307 | AutoLock l(_freeLock); 1308 | _freeLogDatas.push_back(log); 1309 | } 1310 | else 1311 | { 1312 | log->~LogData(); 1313 | free( log); 1314 | } 1315 | } 1316 | 1317 | void LogerManager::showColorText(const char *text, int level) 1318 | { 1319 | 1320 | #if defined(WIN32) && defined(LOG4Z_OEM_CONSOLE) 1321 | char oem[LOG4Z_LOG_BUF_SIZE] = { 0 }; 1322 | CharToOemBuffA(text, oem, LOG4Z_LOG_BUF_SIZE); 1323 | #endif 1324 | 1325 | if (level <= LOG_LEVEL_DEBUG || level > LOG_LEVEL_FATAL) 1326 | { 1327 | #if defined(WIN32) && defined(LOG4Z_OEM_CONSOLE) 1328 | printf("%s", oem); 1329 | #else 1330 | printf("%s", text); 1331 | #endif 1332 | return; 1333 | } 1334 | #ifndef WIN32 1335 | printf("%s%s\e[0m", LOG_COLOR[level], text); 1336 | #else 1337 | AutoLock l(_scLock); 1338 | HANDLE hStd = ::GetStdHandle(STD_OUTPUT_HANDLE); 1339 | if (hStd == INVALID_HANDLE_VALUE) return; 1340 | CONSOLE_SCREEN_BUFFER_INFO oldInfo; 1341 | if (!GetConsoleScreenBufferInfo(hStd, &oldInfo)) 1342 | { 1343 | return; 1344 | } 1345 | else 1346 | { 1347 | SetConsoleTextAttribute(hStd, LOG_COLOR[level]); 1348 | #ifdef LOG4Z_OEM_CONSOLE 1349 | printf("%s", oem); 1350 | #else 1351 | printf("%s", text); 1352 | #endif 1353 | SetConsoleTextAttribute(hStd, oldInfo.wAttributes); 1354 | } 1355 | #endif 1356 | return; 1357 | } 1358 | 1359 | bool LogerManager::configFromStringImpl(std::string content, bool isUpdate) 1360 | { 1361 | unsigned int sum = 0; 1362 | for (std::string::iterator iter = content.begin(); iter != content.end(); ++iter) 1363 | { 1364 | sum += (unsigned char)*iter; 1365 | } 1366 | if (sum == _checksum) 1367 | { 1368 | return true; 1369 | } 1370 | _checksum = sum; 1371 | 1372 | 1373 | std::map loggerMap; 1374 | if (!parseConfigFromString(content, loggerMap)) 1375 | { 1376 | printf(" !!! !!! !!! !!!\r\n"); 1377 | printf(" !!! !!! log4z load config file error \r\n"); 1378 | printf(" !!! !!! !!! !!!\r\n"); 1379 | return false; 1380 | } 1381 | for (std::map::iterator iter = loggerMap.begin(); iter != loggerMap.end(); ++iter) 1382 | { 1383 | LoggerId id = LOG4Z_INVALID_LOGGER_ID; 1384 | id = findLogger(iter->second._key.c_str()); 1385 | if (id == LOG4Z_INVALID_LOGGER_ID) 1386 | { 1387 | if (isUpdate) 1388 | { 1389 | continue; 1390 | } 1391 | else 1392 | { 1393 | id = createLogger(iter->second._key.c_str()); 1394 | if (id == LOG4Z_INVALID_LOGGER_ID) 1395 | { 1396 | continue; 1397 | } 1398 | } 1399 | } 1400 | enableLogger(id, iter->second._enable); 1401 | setLoggerName(id, iter->second._name.c_str()); 1402 | setLoggerPath(id, iter->second._path.c_str()); 1403 | setLoggerLevel(id, iter->second._level); 1404 | setLoggerFileLine(id, iter->second._fileLine); 1405 | setLoggerDisplay(id, iter->second._display); 1406 | setLoggerOutFile(id, iter->second._outfile); 1407 | setLoggerLimitsize(id, iter->second._limitsize); 1408 | setLoggerMonthdir(id, iter->second._monthdir); 1409 | } 1410 | return true; 1411 | } 1412 | 1413 | //! read configure and create with overwriting 1414 | bool LogerManager::config(const char* configPath) 1415 | { 1416 | if (!_configFile.empty()) 1417 | { 1418 | printf(" !!! !!! !!! !!!\r\n"); 1419 | printf(" !!! !!! log4z configure error: too many calls to Config. the old config file=%s, the new config file=%s !!! !!! \r\n" 1420 | , _configFile.c_str(), configPath); 1421 | printf(" !!! !!! !!! !!!\r\n"); 1422 | return false; 1423 | } 1424 | _configFile = configPath; 1425 | 1426 | Log4zFileHandler f; 1427 | f.open(_configFile.c_str(), "rb"); 1428 | if (!f.isOpen()) 1429 | { 1430 | printf(" !!! !!! !!! !!!\r\n"); 1431 | printf(" !!! !!! log4z load config file error. filename=%s !!! !!! \r\n", configPath); 1432 | printf(" !!! !!! !!! !!!\r\n"); 1433 | return false; 1434 | } 1435 | return configFromStringImpl(f.readContent().c_str(), false); 1436 | } 1437 | 1438 | //! read configure and create with overwriting 1439 | bool LogerManager::configFromString(const char* configContent) 1440 | { 1441 | return configFromStringImpl(configContent, false); 1442 | } 1443 | 1444 | //! create with overwriting 1445 | LoggerId LogerManager::createLogger(const char* key) 1446 | { 1447 | if (key == NULL) 1448 | { 1449 | return LOG4Z_INVALID_LOGGER_ID; 1450 | } 1451 | 1452 | std::string copyKey = key; 1453 | trimLogConfig(copyKey); 1454 | 1455 | LoggerId newID = LOG4Z_INVALID_LOGGER_ID; 1456 | { 1457 | std::map::iterator iter = _ids.find(copyKey); 1458 | if (iter != _ids.end()) 1459 | { 1460 | newID = iter->second; 1461 | } 1462 | } 1463 | if (newID == LOG4Z_INVALID_LOGGER_ID) 1464 | { 1465 | if (_lastId +1 >= LOG4Z_LOGGER_MAX) 1466 | { 1467 | showColorText("log4z: CreateLogger can not create|writeover, because loggerid need < LOGGER_MAX! \r\n", LOG_LEVEL_FATAL); 1468 | return LOG4Z_INVALID_LOGGER_ID; 1469 | } 1470 | newID = ++ _lastId; 1471 | _ids[copyKey] = newID; 1472 | _loggers[newID]._enable = true; 1473 | _loggers[newID]._key = copyKey; 1474 | _loggers[newID]._name = copyKey; 1475 | } 1476 | 1477 | return newID; 1478 | } 1479 | 1480 | 1481 | bool LogerManager::start() 1482 | { 1483 | if (_runing) 1484 | { 1485 | showColorText("log4z already start \r\n", LOG_LEVEL_FATAL); 1486 | return false; 1487 | } 1488 | _semaphore.create(0); 1489 | bool ret = ThreadHelper::start(); 1490 | return ret && _semaphore.wait(3000); 1491 | } 1492 | bool LogerManager::stop() 1493 | { 1494 | if (_runing) 1495 | { 1496 | showColorText("log4z stopping \r\n", LOG_LEVEL_FATAL); 1497 | _runing = false; 1498 | wait(); 1499 | while (!_freeLogDatas.empty()) 1500 | { 1501 | delete _freeLogDatas.back(); 1502 | _freeLogDatas.pop_back(); 1503 | } 1504 | return true; 1505 | } 1506 | return false; 1507 | } 1508 | bool LogerManager::prePushLog(LoggerId id, int level) 1509 | { 1510 | if (id < 0 || id > _lastId || !_runing || !_loggers[id]._enable) 1511 | { 1512 | return false; 1513 | } 1514 | if (level < _loggers[id]._level) 1515 | { 1516 | return false; 1517 | } 1518 | size_t count = _logs.size(); 1519 | 1520 | if (count > LOG4Z_LOG_QUEUE_LIMIT_SIZE) 1521 | { 1522 | size_t rate = (count - LOG4Z_LOG_QUEUE_LIMIT_SIZE) * 100 / LOG4Z_LOG_QUEUE_LIMIT_SIZE; 1523 | if (rate > 100) 1524 | { 1525 | rate = 100; 1526 | } 1527 | if ((size_t)rand() % 100 < rate) 1528 | { 1529 | if (rate > 50) 1530 | { 1531 | AutoLock l(_logLock); 1532 | count = _logs.size(); 1533 | } 1534 | if (count > LOG4Z_LOG_QUEUE_LIMIT_SIZE) 1535 | { 1536 | sleepMillisecond((unsigned int)(rate)); 1537 | } 1538 | } 1539 | } 1540 | return true; 1541 | } 1542 | bool LogerManager::pushLog(LogData * pLog, const char * file, int line) 1543 | { 1544 | // discard log 1545 | if (pLog->_id < 0 || pLog->_id > _lastId || !_runing || !_loggers[pLog->_id]._enable) 1546 | { 1547 | freeLogData(pLog); 1548 | return false; 1549 | } 1550 | 1551 | //filter log 1552 | if (pLog->_level < _loggers[pLog->_id]._level) 1553 | { 1554 | freeLogData(pLog); 1555 | return false; 1556 | } 1557 | if (_loggers[pLog->_id]._fileLine && file) 1558 | { 1559 | const char * pNameEnd = file + strlen(file); 1560 | const char * pNameBegin = pNameEnd; 1561 | do 1562 | { 1563 | if (*pNameBegin == '\\' || *pNameBegin == '/') { pNameBegin++; break; } 1564 | if (pNameBegin == file) { break; } 1565 | pNameBegin--; 1566 | } while (true); 1567 | zsummer::log4z::Log4zStream ss(pLog->_content + pLog->_contentLen, LOG4Z_LOG_BUF_SIZE - pLog->_contentLen); 1568 | ss.writeChar(' '); 1569 | ss.writeString(pNameBegin, pNameEnd - pNameBegin); 1570 | ss.writeChar(':'); 1571 | ss.writeULongLong((unsigned long long)line); 1572 | pLog->_contentLen += ss.getCurrentLen(); 1573 | } 1574 | 1575 | if (pLog->_contentLen +3 > LOG4Z_LOG_BUF_SIZE ) pLog->_contentLen = LOG4Z_LOG_BUF_SIZE - 3; 1576 | pLog->_content[pLog->_contentLen + 0] = '\r'; 1577 | pLog->_content[pLog->_contentLen + 1] = '\n'; 1578 | pLog->_content[pLog->_contentLen + 2] = '\0'; 1579 | pLog->_contentLen += 2; 1580 | 1581 | 1582 | if (_loggers[pLog->_id]._display && LOG4Z_ALL_SYNCHRONOUS_OUTPUT) 1583 | { 1584 | showColorText(pLog->_content, pLog->_level); 1585 | } 1586 | 1587 | if (LOG4Z_ALL_DEBUGOUTPUT_DISPLAY && LOG4Z_ALL_SYNCHRONOUS_OUTPUT) 1588 | { 1589 | #ifdef WIN32 1590 | OutputDebugStringA(pLog->_content); 1591 | #endif 1592 | } 1593 | 1594 | if (_loggers[pLog->_id]._outfile && LOG4Z_ALL_SYNCHRONOUS_OUTPUT) 1595 | { 1596 | AutoLock l(_logLock); 1597 | if (openLogger(pLog)) 1598 | { 1599 | _loggers[pLog->_id]._handle.write(pLog->_content, pLog->_contentLen); 1600 | _loggers[pLog->_id]._curWriteLen += (unsigned int)pLog->_contentLen; 1601 | closeLogger(pLog->_id); 1602 | _ullStatusTotalWriteFileCount++; 1603 | _ullStatusTotalWriteFileBytes += pLog->_contentLen; 1604 | } 1605 | } 1606 | 1607 | if (LOG4Z_ALL_SYNCHRONOUS_OUTPUT) 1608 | { 1609 | freeLogData(pLog); 1610 | return true; 1611 | } 1612 | 1613 | AutoLock l(_logLock); 1614 | _logs.push_back(pLog); 1615 | _ullStatusTotalPushLog ++; 1616 | return true; 1617 | } 1618 | 1619 | //! 查找ID 1620 | LoggerId LogerManager::findLogger(const char * key) 1621 | { 1622 | std::map::iterator iter; 1623 | iter = _ids.find(key); 1624 | if (iter != _ids.end()) 1625 | { 1626 | return iter->second; 1627 | } 1628 | return LOG4Z_INVALID_LOGGER_ID; 1629 | } 1630 | 1631 | bool LogerManager::hotChange(LoggerId id, LogDataType ldt, int num, const std::string & text) 1632 | { 1633 | if (id <0 || id > _lastId) return false; 1634 | if (text.length() >= LOG4Z_LOG_BUF_SIZE) return false; 1635 | if (!_runing || LOG4Z_ALL_SYNCHRONOUS_OUTPUT) 1636 | { 1637 | return onHotChange(id, ldt, num, text); 1638 | } 1639 | LogData * pLog = makeLogData(id, LOG4Z_DEFAULT_LEVEL); 1640 | pLog->_id = id; 1641 | pLog->_type = ldt; 1642 | pLog->_typeval = num; 1643 | memcpy(pLog->_content, text.c_str(), text.length()); 1644 | pLog->_contentLen = (int)text.length(); 1645 | AutoLock l(_logLock); 1646 | _logs.push_back(pLog); 1647 | return true; 1648 | } 1649 | 1650 | bool LogerManager::onHotChange(LoggerId id, LogDataType ldt, int num, const std::string & text) 1651 | { 1652 | if (id < LOG4Z_MAIN_LOGGER_ID || id > _lastId) 1653 | { 1654 | return false; 1655 | } 1656 | LoggerInfo & logger = _loggers[id]; 1657 | if (ldt == LDT_ENABLE_LOGGER) logger._enable = num != 0; 1658 | else if (ldt == LDT_SET_LOGGER_NAME) logger._name = text; 1659 | else if (ldt == LDT_SET_LOGGER_PATH) logger._path = text; 1660 | else if (ldt == LDT_SET_LOGGER_LEVEL) logger._level = num; 1661 | else if (ldt == LDT_SET_LOGGER_FILELINE) logger._fileLine = num != 0; 1662 | else if (ldt == LDT_SET_LOGGER_DISPLAY) logger._display = num != 0; 1663 | else if (ldt == LDT_SET_LOGGER_OUTFILE) logger._outfile = num != 0; 1664 | else if (ldt == LDT_SET_LOGGER_LIMITSIZE) logger._limitsize = num; 1665 | else if (ldt == LDT_SET_LOGGER_MONTHDIR) logger._monthdir = num != 0; 1666 | else if (ldt == LDT_SET_LOGGER_RESERVETIME) logger._logReserveTime = num >= 0 ? num : 0; 1667 | return true; 1668 | } 1669 | 1670 | bool LogerManager::enableLogger(LoggerId id, bool enable) 1671 | { 1672 | if (id < 0 || id > _lastId) return false; 1673 | if (enable) 1674 | { 1675 | _loggers[id]._enable = true; 1676 | return true; 1677 | } 1678 | return hotChange(id, LDT_ENABLE_LOGGER, false, ""); 1679 | } 1680 | bool LogerManager::setLoggerLevel(LoggerId id, int level) 1681 | { 1682 | if (id < 0 || id > _lastId) return false; 1683 | if (level <= _loggers[id]._level) 1684 | { 1685 | _loggers[id]._level = level; 1686 | return true; 1687 | } 1688 | return hotChange(id, LDT_SET_LOGGER_LEVEL, level, ""); 1689 | } 1690 | bool LogerManager::setLoggerDisplay(LoggerId id, bool enable) { return hotChange(id, LDT_SET_LOGGER_DISPLAY, enable, ""); } 1691 | bool LogerManager::setLoggerOutFile(LoggerId id, bool enable) { return hotChange(id, LDT_SET_LOGGER_OUTFILE, enable, ""); } 1692 | bool LogerManager::setLoggerMonthdir(LoggerId id, bool enable) { return hotChange(id, LDT_SET_LOGGER_MONTHDIR, enable, ""); } 1693 | bool LogerManager::setLoggerFileLine(LoggerId id, bool enable) { return hotChange(id, LDT_SET_LOGGER_FILELINE, enable, ""); } 1694 | bool LogerManager::setLoggerReserveTime(LoggerId id, time_t sec) { return hotChange(id, LDT_SET_LOGGER_RESERVETIME, (int)sec, ""); } 1695 | bool LogerManager::setLoggerLimitsize(LoggerId id, unsigned int limitsize) 1696 | { 1697 | if (limitsize == 0 ) {limitsize = (unsigned int)-1;} 1698 | return hotChange(id, LDT_SET_LOGGER_LIMITSIZE, limitsize, ""); 1699 | } 1700 | 1701 | bool LogerManager::setLoggerName(LoggerId id, const char * name) 1702 | { 1703 | if (id <0 || id > _lastId) return false; 1704 | //the name by main logger is the process name and it's can't change. 1705 | // if (id == LOG4Z_MAIN_LOGGER_ID) return false; 1706 | 1707 | if (name == NULL || strlen(name) == 0) 1708 | { 1709 | return false; 1710 | } 1711 | return hotChange(id, LDT_SET_LOGGER_NAME, 0, name); 1712 | } 1713 | 1714 | bool LogerManager::setLoggerPath(LoggerId id, const char * path) 1715 | { 1716 | if (id <0 || id > _lastId) return false; 1717 | if (path == NULL || strlen(path) == 0) return false; 1718 | std::string copyPath = path; 1719 | { 1720 | char ch = copyPath.at(copyPath.length() - 1); 1721 | if (ch != '\\' && ch != '/') 1722 | { 1723 | copyPath.append("/"); 1724 | } 1725 | } 1726 | return hotChange(id, LDT_SET_LOGGER_PATH, 0, copyPath); 1727 | } 1728 | bool LogerManager::setAutoUpdate(int interval) 1729 | { 1730 | _hotUpdateInterval = interval; 1731 | return true; 1732 | } 1733 | bool LogerManager::updateConfig() 1734 | { 1735 | if (_configFile.empty()) 1736 | { 1737 | //LOGW("log4z update config file error. filename is empty."); 1738 | return false; 1739 | } 1740 | Log4zFileHandler f; 1741 | f.open(_configFile.c_str(), "rb"); 1742 | if (!f.isOpen()) 1743 | { 1744 | printf(" !!! !!! !!! !!!\r\n"); 1745 | printf(" !!! !!! log4z load config file error. filename=%s !!! !!! \r\n", _configFile.c_str()); 1746 | printf(" !!! !!! !!! !!!\r\n"); 1747 | return false; 1748 | } 1749 | return configFromStringImpl(f.readContent().c_str(), true); 1750 | } 1751 | 1752 | bool LogerManager::isLoggerEnable(LoggerId id) 1753 | { 1754 | if (id <0 || id > _lastId) return false; 1755 | return _loggers[id]._enable; 1756 | } 1757 | 1758 | unsigned int LogerManager::getStatusActiveLoggers() 1759 | { 1760 | unsigned int actives = 0; 1761 | for (int i=0; i<= _lastId; i++) 1762 | { 1763 | if (_loggers[i]._enable) 1764 | { 1765 | actives ++; 1766 | } 1767 | } 1768 | return actives; 1769 | } 1770 | 1771 | 1772 | bool LogerManager::openLogger(LogData * pLog) 1773 | { 1774 | int id = pLog->_id; 1775 | if (id < 0 || id >_lastId) 1776 | { 1777 | showColorText("log4z: openLogger can not open, invalide logger id! \r\n", LOG_LEVEL_FATAL); 1778 | return false; 1779 | } 1780 | 1781 | LoggerInfo * pLogger = &_loggers[id]; 1782 | if (!pLogger->_enable || !pLogger->_outfile || pLog->_level < pLogger->_level) 1783 | { 1784 | return false; 1785 | } 1786 | 1787 | bool sameday = pLog->_time >= pLogger->_curFileCreateDay && pLog->_time - pLogger->_curFileCreateDay < 24*3600; 1788 | bool needChageFile = pLogger->_curWriteLen > pLogger->_limitsize * 1024 * 1024; 1789 | if (!sameday || needChageFile) 1790 | { 1791 | if (!sameday) 1792 | { 1793 | pLogger->_curFileIndex = 0; 1794 | } 1795 | else 1796 | { 1797 | pLogger->_curFileIndex++; 1798 | } 1799 | if (pLogger->_handle.isOpen()) 1800 | { 1801 | pLogger->_handle.close(); 1802 | } 1803 | } 1804 | if (!pLogger->_handle.isOpen()) 1805 | { 1806 | pLogger->_curFileCreateTime = pLog->_time; 1807 | pLogger->_curWriteLen = 0; 1808 | 1809 | tm t = timeToTm(pLogger->_curFileCreateTime); 1810 | if (true) //process day time 1811 | { 1812 | tm day = t; 1813 | day.tm_hour = 0; 1814 | day.tm_min = 0; 1815 | day.tm_sec = 0; 1816 | pLogger->_curFileCreateDay = mktime(&day); 1817 | } 1818 | 1819 | std::string name; 1820 | std::string path; 1821 | 1822 | name = pLogger->_name; 1823 | path = pLogger->_path; 1824 | 1825 | 1826 | char buf[500] = { 0 }; 1827 | if (pLogger->_monthdir) 1828 | { 1829 | sprintf(buf, "%04d_%02d/", t.tm_year + 1900, t.tm_mon + 1); 1830 | path += buf; 1831 | } 1832 | 1833 | if (!isDirectory(path)) 1834 | { 1835 | createRecursionDir(path); 1836 | } 1837 | if (LOG4Z_ALL_SYNCHRONOUS_OUTPUT) 1838 | { 1839 | sprintf(buf, "%s_%s_%04d%02d%02d%02d_%s_%03u.log", 1840 | _proName.c_str(), name.c_str(), t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, 1841 | t.tm_hour, _pid.c_str(), pLogger->_curFileIndex); 1842 | } 1843 | else 1844 | { 1845 | 1846 | sprintf(buf, "%s_%s_%04d%02d%02d%02d%02d_%s_%03u.log", 1847 | _proName.c_str(), name.c_str(), t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, 1848 | t.tm_hour, t.tm_min, _pid.c_str(), pLogger->_curFileIndex); 1849 | } 1850 | path += buf; 1851 | long curLen = pLogger->_handle.open(path.c_str(), "ab"); 1852 | if (!pLogger->_handle.isOpen() || curLen < 0) 1853 | { 1854 | sprintf(buf, "log4z: can not open log file %s. \r\n", path.c_str()); 1855 | showColorText("!!!!!!!!!!!!!!!!!!!!!!!!!! \r\n", LOG_LEVEL_FATAL); 1856 | showColorText(buf, LOG_LEVEL_FATAL); 1857 | showColorText("!!!!!!!!!!!!!!!!!!!!!!!!!! \r\n", LOG_LEVEL_FATAL); 1858 | pLogger->_outfile = false; 1859 | return false; 1860 | } 1861 | pLogger->_curWriteLen = (unsigned int)curLen; 1862 | 1863 | if (pLogger->_logReserveTime > 0 ) 1864 | { 1865 | if (pLogger->_historyLogs.size() > LOG4Z_FORCE_RESERVE_FILE_COUNT) 1866 | { 1867 | while (!pLogger->_historyLogs.empty() && pLogger->_historyLogs.front().first < time(NULL) - pLogger->_logReserveTime) 1868 | { 1869 | pLogger->_handle.removeFile(pLogger->_historyLogs.front().second.c_str()); 1870 | pLogger->_historyLogs.pop_front(); 1871 | } 1872 | } 1873 | if (pLogger->_historyLogs.empty() || pLogger->_historyLogs.back().second != path) 1874 | { 1875 | pLogger->_historyLogs.push_back(std::make_pair(time(NULL), path)); 1876 | } 1877 | } 1878 | return true; 1879 | } 1880 | return true; 1881 | } 1882 | bool LogerManager::closeLogger(LoggerId id) 1883 | { 1884 | if (id < 0 || id >_lastId) 1885 | { 1886 | showColorText("log4z: closeLogger can not close, invalide logger id! \r\n", LOG_LEVEL_FATAL); 1887 | return false; 1888 | } 1889 | LoggerInfo * pLogger = &_loggers[id]; 1890 | if (pLogger->_handle.isOpen()) 1891 | { 1892 | pLogger->_handle.close(); 1893 | return true; 1894 | } 1895 | return false; 1896 | } 1897 | bool LogerManager::popLog(LogData *& log) 1898 | { 1899 | if (_logsCache.empty()) 1900 | { 1901 | if (!_logs.empty()) 1902 | { 1903 | AutoLock l(_logLock); 1904 | if (_logs.empty()) 1905 | { 1906 | return false; 1907 | } 1908 | _logsCache.swap(_logs); 1909 | } 1910 | } 1911 | if (!_logsCache.empty()) 1912 | { 1913 | log = _logsCache.front(); 1914 | _logsCache.pop_front(); 1915 | return true; 1916 | } 1917 | return false; 1918 | } 1919 | 1920 | void LogerManager::run() 1921 | { 1922 | _runing = true; 1923 | LOGA("----------------- log4z thread started! ----------------------------"); 1924 | for (int i = 0; i <= _lastId; i++) 1925 | { 1926 | if (_loggers[i]._enable) 1927 | { 1928 | LOGA("logger id=" << i 1929 | << " key=" << _loggers[i]._key 1930 | << " name=" << _loggers[i]._name 1931 | << " path=" << _loggers[i]._path 1932 | << " level=" << _loggers[i]._level 1933 | << " display=" << _loggers[i]._display); 1934 | } 1935 | } 1936 | 1937 | _semaphore.post(); 1938 | 1939 | 1940 | LogData * pLog = NULL; 1941 | int needFlush[LOG4Z_LOGGER_MAX] = {0}; 1942 | time_t lastCheckUpdate = time(NULL); 1943 | 1944 | 1945 | while (true) 1946 | { 1947 | while(popLog(pLog)) 1948 | { 1949 | if (pLog->_id <0 || pLog->_id > _lastId) 1950 | { 1951 | freeLogData(pLog); 1952 | continue; 1953 | } 1954 | LoggerInfo & curLogger = _loggers[pLog->_id]; 1955 | 1956 | if (pLog->_type != LDT_GENERAL) 1957 | { 1958 | onHotChange(pLog->_id, (LogDataType)pLog->_type, pLog->_typeval, std::string(pLog->_content, pLog->_contentLen)); 1959 | curLogger._handle.close(); 1960 | freeLogData(pLog); 1961 | continue; 1962 | } 1963 | 1964 | // 1965 | _ullStatusTotalPopLog ++; 1966 | //discard 1967 | 1968 | if (!curLogger._enable || pLog->_level _content, pLog->_level); 1978 | } 1979 | if (LOG4Z_ALL_DEBUGOUTPUT_DISPLAY ) 1980 | { 1981 | #ifdef WIN32 1982 | OutputDebugStringA(pLog->_content); 1983 | #endif 1984 | } 1985 | 1986 | 1987 | if (curLogger._outfile ) 1988 | { 1989 | if (!openLogger(pLog)) 1990 | { 1991 | freeLogData(pLog); 1992 | continue; 1993 | } 1994 | 1995 | curLogger._handle.write(pLog->_content, pLog->_contentLen); 1996 | curLogger._curWriteLen += (unsigned int)pLog->_contentLen; 1997 | needFlush[pLog->_id] ++; 1998 | _ullStatusTotalWriteFileCount++; 1999 | _ullStatusTotalWriteFileBytes += pLog->_contentLen; 2000 | } 2001 | else 2002 | { 2003 | _ullStatusTotalWriteFileCount++; 2004 | _ullStatusTotalWriteFileBytes += pLog->_contentLen; 2005 | } 2006 | 2007 | freeLogData(pLog); 2008 | } 2009 | 2010 | for (int i=0; i<=_lastId; i++) 2011 | { 2012 | if (_loggers[i]._enable && needFlush[i] > 0) 2013 | { 2014 | _loggers[i]._handle.flush(); 2015 | needFlush[i] = 0; 2016 | } 2017 | if(!_loggers[i]._enable && _loggers[i]._handle.isOpen()) 2018 | { 2019 | _loggers[i]._handle.close(); 2020 | } 2021 | } 2022 | 2023 | //! delay. 2024 | sleepMillisecond(50); 2025 | 2026 | //! quit 2027 | if (!_runing && _logs.empty()) 2028 | { 2029 | break; 2030 | } 2031 | 2032 | if (_hotUpdateInterval != 0 && time(NULL) - lastCheckUpdate > _hotUpdateInterval) 2033 | { 2034 | updateConfig(); 2035 | lastCheckUpdate = time(NULL); 2036 | } 2037 | 2038 | 2039 | 2040 | } 2041 | 2042 | for (int i=0; i <= _lastId; i++) 2043 | { 2044 | if (_loggers[i]._enable) 2045 | { 2046 | _loggers[i]._enable = false; 2047 | closeLogger(i); 2048 | } 2049 | } 2050 | 2051 | } 2052 | 2053 | ////////////////////////////////////////////////////////////////////////// 2054 | //ILog4zManager::getInstance 2055 | ////////////////////////////////////////////////////////////////////////// 2056 | ILog4zManager * ILog4zManager::getInstance() 2057 | { 2058 | static LogerManager m; 2059 | return &m; 2060 | } 2061 | 2062 | 2063 | 2064 | _ZSUMMER_LOG4Z_END 2065 | _ZSUMMER_END 2066 | -------------------------------------------------------------------------------- /src/utils/log4z.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Log4z License 3 | * ----------- 4 | * 5 | * Log4z is licensed under the terms of the MIT license reproduced below. 6 | * This means that Log4z is free software and can be used for both academic 7 | * and commercial purposes at absolutely no cost. 8 | * 9 | * 10 | * =============================================================================== 11 | * 12 | * Copyright (C) 2010-2017 YaweiZhang . 13 | * 14 | * Permission is hereby granted, free of charge, to any person obtaining a copy 15 | * of this software and associated documentation files (the "Software"), to deal 16 | * in the Software without restriction, including without limitation the rights 17 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | * copies of the Software, and to permit persons to whom the Software is 19 | * furnished to do so, subject to the following conditions: 20 | * 21 | * The above copyright notice and this permission notice shall be included in 22 | * all copies or substantial portions of the Software. 23 | * 24 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 | * THE SOFTWARE. 31 | * 32 | * =============================================================================== 33 | * 34 | * (end of COPYRIGHT) 35 | */ 36 | 37 | 38 | /* 39 | * AUTHORS: YaweiZhang 40 | * VERSION: 3.5.0 41 | * PURPOSE: A lightweight library for error reporting and logging to file and screen . 42 | * CREATION: 2010.10.4 43 | * LCHANGE: 2017.08.20 44 | * LICENSE: Expat/MIT License, See Copyright Notice at the begin of this file. 45 | */ 46 | 47 | 48 | /* 49 | * contact me: 50 | * tencent qq group: 19811947 51 | * mail: yawei.zhang@foxmail.com 52 | */ 53 | 54 | 55 | /* 56 | * UPDATES LOG 57 | * 58 | * VERSION 0.1.0 59 | * create the first project. 60 | * It support put log to screen and files, 61 | * support log level, support one day one log file. 62 | * support multi-thread, cross-platform. 63 | * 64 | * VERSION .... 65 | * ... 66 | * 67 | * VERSION 0.9.0 68 | * support config files. 69 | * support color text in screen. 70 | * support multiple output to different files. 71 | * 72 | * VERSION 1.0.0 73 | * support comments in the config file. 74 | * add a advanced demo in the ./project 75 | * fix some details. 76 | * 77 | * VERSION 1.0.1 78 | * change and add some Comments in the log4z 79 | * simplify the 'fast_test' demo projects. 80 | * 81 | * VERSION 1.1.0 82 | * the method Start will wait for the logger thread started. 83 | * config and add method change. 84 | * namespace change. 85 | * 86 | * VERSION 1.1.1 87 | * add status info method. 88 | * optimize. 89 | * 90 | * VERSION 1.2.0 91 | * add stress test demo 92 | * rewrite Stream module,better performance. 93 | * 94 | * VERSION 1.2.1 95 | * fixed type name 'long' stream format on 64/32 operation system. 96 | * logger will not loss any log on process normal exit. 97 | * 98 | * VERSION 2.0.0 99 | * new interface: 100 | * merge some Main interface and Dynamic interface 101 | * add Change Logger Attribute method by thread-safe 102 | * new config design. 103 | * log file name append process id. 104 | * 105 | * VERSION 2.1 106 | * support binary text output 107 | * rewrite write file module, support vs2005 open Chinese characters path 108 | * 109 | * VERSION 2.2 110 | * optimized binary stream output view 111 | * support wchar * string. 112 | * 113 | * VERSION 2.3 114 | * adjust output file named. 115 | * support different month different directory. 116 | * adjust some detail. 117 | * 118 | * VERSION 2.4 119 | * support rolling log file. 120 | * support hot update configure 121 | * used precision time in log. 122 | * micro set default logger attribute 123 | * fix tls bug in windows xp dll 124 | * 125 | * VERSION 2.5 126 | * screen output can choice synchronous or not 127 | * fix sometimes color will disorder on windows. 128 | * eliminate some compiler warning 129 | * fix sem_timewait in linux 130 | * add format-style method at input log, cannot support vs2003 and VC6. 131 | * fix WCHAR String cannot output 132 | * optimize std::string, binary log input, and support std::wstring. 133 | * clean code, better readability 134 | * 135 | * VERSION 2.6 136 | * add PrePushLog 137 | * better performance when log is filter out. 138 | * interface replace std::string because it's in shared library is unsafe. 139 | * add log level 'trace' 140 | * 141 | * VERSION 2.6.1 142 | * fix bug from defined _MSC_VER 143 | * 144 | * VERSION 2.7 145 | * compatible mac machine, now log4z can working in linux/windows/mac. 146 | * 147 | * VERSION 2.8 148 | * support synchronous written to file and thread-safe 149 | * fix compatibility on MinGW. a constant value suffix. 150 | * ignore utf-8 file BOM when load configure file 151 | * use macro WIN32_LEAN_AND_MEAN replace head file winsock2.h 152 | * new naming notations 153 | * 154 | * VERSION 3.0 155 | * new naming notations 156 | * support for reading config from a string. 157 | * remove all TLS code, used dispatch_semaphore in apple OS. 158 | * support system: windows, linux, mac, iOS 159 | * 160 | * VERSION 3.1 161 | * add method enable/disable logger by specific logger id 162 | * add method enable/disable log suffix line number. 163 | * add method enable/disable log output to file. 164 | * 165 | * VERSION 3.2 166 | * add interface setLoggerName,setLoggerPath,setAutoUpdate 167 | * support auto update from configure file 168 | * 169 | * VERSION 3.3 170 | * support map vector list 171 | * support continuum via travis. 172 | * new hot change design, all change realize need via push log flow. 173 | * support oem string convert. 174 | * new method to read whole content of file. 175 | * check configure's checksum when auto update it. 176 | * some other optimize. 177 | * 178 | * VERSION 3.5 179 | * optimization 180 | * 181 | */ 182 | 183 | 184 | #pragma once 185 | #ifndef _ZSUMMER_LOG4Z_H_ 186 | #define _ZSUMMER_LOG4Z_H_ 187 | 188 | #include 189 | #include 190 | #include 191 | #include 192 | #include 193 | #include 194 | #include 195 | #ifdef WIN32 196 | #define WIN32_LEAN_AND_MEAN 197 | #include 198 | #endif 199 | #include 200 | #include 201 | #include 202 | #include 203 | #include 204 | 205 | 206 | //! logger ID type. DO NOT TOUCH 207 | typedef int LoggerId; 208 | 209 | //! the invalid logger id. DO NOT TOUCH 210 | const int LOG4Z_INVALID_LOGGER_ID = -1; 211 | 212 | //! the main logger id. DO NOT TOUCH 213 | //! can use this id to set the main logger's attribute. 214 | //! example: 215 | //! ILog4zManager::getPtr()->setLoggerLevel(LOG4Z_MAIN_LOGGER_ID, LOG_LEVEL_WARN); 216 | //! ILog4zManager::getPtr()->setLoggerDisplay(LOG4Z_MAIN_LOGGER_ID, false); 217 | const int LOG4Z_MAIN_LOGGER_ID = 0; 218 | 219 | //! the main logger name. DO NOT TOUCH 220 | const char*const LOG4Z_MAIN_LOGGER_KEY = "Main"; 221 | 222 | //! check VC VERSION. DO NOT TOUCH 223 | //! format micro cannot support VC6 or VS2003, please use stream input log, like LOGI, LOGD, LOG_DEBUG, LOG_STREAM ... 224 | #if _MSC_VER >= 1400 //MSVC >= VS2005 225 | #define LOG4Z_FORMAT_INPUT_ENABLE 226 | #endif 227 | 228 | #ifndef WIN32 229 | #define LOG4Z_FORMAT_INPUT_ENABLE 230 | #endif 231 | 232 | //! LOG Level 233 | enum ENUM_LOG_LEVEL 234 | { 235 | LOG_LEVEL_TRACE = 0, 236 | LOG_LEVEL_DEBUG, 237 | LOG_LEVEL_INFO, 238 | LOG_LEVEL_WARN, 239 | LOG_LEVEL_ERROR, 240 | LOG_LEVEL_ALARM, 241 | LOG_LEVEL_FATAL, 242 | }; 243 | 244 | ////////////////////////////////////////////////////////////////////////// 245 | //! -----------------default logger config, can change on this.----------- 246 | ////////////////////////////////////////////////////////////////////////// 247 | //! the max logger count. 248 | const int LOG4Z_LOGGER_MAX = 20; 249 | //! the max log content length. 250 | const int LOG4Z_LOG_BUF_SIZE = 1024 * 8; 251 | //! the max stl container depth. 252 | const int LOG4Z_LOG_CONTAINER_DEPTH = 5; 253 | //! the log queue length limit size. 254 | const int LOG4Z_LOG_QUEUE_LIMIT_SIZE = 20000; 255 | 256 | //! all logger synchronous output or not 257 | const bool LOG4Z_ALL_SYNCHRONOUS_OUTPUT = false; 258 | //! all logger synchronous display to the windows debug output 259 | const bool LOG4Z_ALL_DEBUGOUTPUT_DISPLAY = false; 260 | 261 | //! default logger output file. 262 | const char* const LOG4Z_DEFAULT_PATH = "./log/"; 263 | //! default log filter level 264 | const int LOG4Z_DEFAULT_LEVEL = LOG_LEVEL_DEBUG; 265 | //! default logger display 266 | const bool LOG4Z_DEFAULT_DISPLAY = true; 267 | //! default logger output to file 268 | const bool LOG4Z_DEFAULT_OUTFILE = true; 269 | //! default logger month dir used status 270 | const bool LOG4Z_DEFAULT_MONTHDIR = false; 271 | //! default logger output file limit size, unit M byte. 272 | const int LOG4Z_DEFAULT_LIMITSIZE = 100; 273 | //! default logger show suffix (file name and line number) 274 | const bool LOG4Z_DEFAULT_SHOWSUFFIX = true; 275 | //! support ANSI->OEM console conversion on Windows 276 | #undef LOG4Z_OEM_CONSOLE 277 | //! default logger force reserve log file count. 278 | const size_t LOG4Z_FORCE_RESERVE_FILE_COUNT = 7; 279 | 280 | /////////////////////////////////////////////////////////////////////////// 281 | //! ----------------------------------------------------------------------- 282 | ////////////////////////////////////////////////////////////////////////// 283 | 284 | #ifndef _ZSUMMER_BEGIN 285 | #define _ZSUMMER_BEGIN namespace zsummer { 286 | #endif 287 | #ifndef _ZSUMMER_LOG4Z_BEGIN 288 | #define _ZSUMMER_LOG4Z_BEGIN namespace log4z { 289 | #endif 290 | _ZSUMMER_BEGIN 291 | _ZSUMMER_LOG4Z_BEGIN 292 | 293 | 294 | struct LogData 295 | { 296 | LoggerId _id; //dest logger id 297 | int _type; //type. 298 | int _typeval; 299 | int _level; //log level 300 | time_t _time; //create time 301 | unsigned int _precise; //create time 302 | unsigned int _threadID; 303 | int _contentLen; 304 | char _content[1]; //content 305 | }; 306 | 307 | //! log4z class 308 | class ILog4zManager 309 | { 310 | public: 311 | ILog4zManager(){}; 312 | virtual ~ILog4zManager(){}; 313 | 314 | //! Log4z Singleton 315 | 316 | static ILog4zManager * getInstance(); 317 | inline static ILog4zManager & getRef(){return *getInstance();} 318 | inline static ILog4zManager * getPtr(){return getInstance();} 319 | 320 | //! Config or overwrite configure 321 | //! Needs to be called before ILog4zManager::Start,, OR Do not call. 322 | virtual bool config(const char * configPath) = 0; 323 | virtual bool configFromString(const char * configContent) = 0; 324 | 325 | //! Create or overwrite logger. 326 | //! Needs to be called before ILog4zManager::Start, OR Do not call. 327 | virtual LoggerId createLogger(const char* key) = 0; 328 | 329 | //! Start Log Thread. This method can only be called once by one process. 330 | virtual bool start() = 0; 331 | 332 | //! Default the method will be calling at process exit auto. 333 | //! Default no need to call and no recommended. 334 | virtual bool stop() = 0; 335 | 336 | //! Find logger. thread safe. 337 | virtual LoggerId findLogger(const char* key) =0; 338 | 339 | //pre-check the log filter. if filter out return false. 340 | virtual bool prePushLog(LoggerId id, int level) = 0; 341 | //! Push log, thread safe. 342 | virtual bool pushLog(LogData * pLog, const char * file = NULL, int line = 0) = 0; 343 | 344 | //! set logger's attribute, thread safe. 345 | virtual bool enableLogger(LoggerId id, bool enable) = 0; // immediately when enable, and queue up when disable. 346 | virtual bool setLoggerName(LoggerId id, const char * name) = 0; 347 | virtual bool setLoggerPath(LoggerId id, const char * path) = 0; 348 | virtual bool setLoggerLevel(LoggerId id, int nLevel) = 0; // immediately when enable, and queue up when disable. 349 | virtual bool setLoggerFileLine(LoggerId id, bool enable) = 0; 350 | virtual bool setLoggerDisplay(LoggerId id, bool enable) = 0; 351 | virtual bool setLoggerOutFile(LoggerId id, bool enable) = 0; 352 | virtual bool setLoggerLimitsize(LoggerId id, unsigned int limitsize) = 0; 353 | virtual bool setLoggerMonthdir(LoggerId id, bool enable) = 0; 354 | virtual bool setLoggerReserveTime(LoggerId id, time_t sec) = 0; 355 | 356 | 357 | //! Update logger's attribute from config file, thread safe. 358 | virtual bool setAutoUpdate(int interval/*per second, 0 is disable auto update*/) = 0; 359 | virtual bool updateConfig() = 0; 360 | 361 | //! Log4z status statistics, thread safe. 362 | virtual bool isLoggerEnable(LoggerId id) = 0; 363 | virtual unsigned long long getStatusTotalWriteCount() = 0; 364 | virtual unsigned long long getStatusTotalWriteBytes() = 0; 365 | virtual unsigned long long getStatusTotalPushQueue() = 0; 366 | virtual unsigned long long getStatusTotalPopQueue() = 0; 367 | virtual unsigned int getStatusActiveLoggers() = 0; 368 | 369 | virtual LogData * makeLogData(LoggerId id, int level) = 0; 370 | virtual void freeLogData(LogData * log) = 0; 371 | }; 372 | 373 | class Log4zStream; 374 | class Log4zBinary; 375 | 376 | #ifndef _ZSUMMER_END 377 | #define _ZSUMMER_END } 378 | #endif 379 | #ifndef _ZSUMMER_LOG4Z_END 380 | #define _ZSUMMER_LOG4Z_END } 381 | #endif 382 | 383 | _ZSUMMER_LOG4Z_END 384 | _ZSUMMER_END 385 | 386 | 387 | 388 | //! base macro. 389 | #define LOG_STREAM(id, level, file, line, log)\ 390 | do{\ 391 | if (zsummer::log4z::ILog4zManager::getPtr()->prePushLog(id,level)) \ 392 | {\ 393 | zsummer::log4z::LogData * __pLog = zsummer::log4z::ILog4zManager::getPtr()->makeLogData(id, level); \ 394 | zsummer::log4z::Log4zStream __ss(__pLog->_content + __pLog->_contentLen, LOG4Z_LOG_BUF_SIZE - __pLog->_contentLen);\ 395 | __ss << log;\ 396 | __pLog->_contentLen += __ss.getCurrentLen(); \ 397 | zsummer::log4z::ILog4zManager::getPtr()->pushLog(__pLog, file, line);\ 398 | }\ 399 | } while (0) 400 | 401 | 402 | //! fast macro 403 | #define LOG_TRACE(id, log) LOG_STREAM(id, LOG_LEVEL_TRACE, __FILE__, __LINE__, log) 404 | #define LOG_DEBUG(id, log) LOG_STREAM(id, LOG_LEVEL_DEBUG, __FILE__, __LINE__, log) 405 | #define LOG_INFO(id, log) LOG_STREAM(id, LOG_LEVEL_INFO, __FILE__, __LINE__, log) 406 | #define LOG_WARN(id, log) LOG_STREAM(id, LOG_LEVEL_WARN, __FILE__, __LINE__, log) 407 | #define LOG_ERROR(id, log) LOG_STREAM(id, LOG_LEVEL_ERROR, __FILE__, __LINE__, log) 408 | #define LOG_ALARM(id, log) LOG_STREAM(id, LOG_LEVEL_ALARM, __FILE__, __LINE__, log) 409 | #define LOG_FATAL(id, log) LOG_STREAM(id, LOG_LEVEL_FATAL, __FILE__, __LINE__, log) 410 | 411 | //! super macro. 412 | #define LOGT( log ) LOG_TRACE(LOG4Z_MAIN_LOGGER_ID, log ) 413 | #define LOGD( log ) LOG_DEBUG(LOG4Z_MAIN_LOGGER_ID, log ) 414 | #define LOGI( log ) LOG_INFO(LOG4Z_MAIN_LOGGER_ID, log ) 415 | #define LOGW( log ) LOG_WARN(LOG4Z_MAIN_LOGGER_ID, log ) 416 | #define LOGE( log ) LOG_ERROR(LOG4Z_MAIN_LOGGER_ID, log ) 417 | #define LOGA( log ) LOG_ALARM(LOG4Z_MAIN_LOGGER_ID, log ) 418 | #define LOGF( log ) LOG_FATAL(LOG4Z_MAIN_LOGGER_ID, log ) 419 | 420 | 421 | //! format input log. 422 | #ifdef LOG4Z_FORMAT_INPUT_ENABLE 423 | #ifdef WIN32 424 | #define LOG_FORMAT(id, level, file, line, logformat, ...) \ 425 | do{ \ 426 | if (zsummer::log4z::ILog4zManager::getPtr()->prePushLog(id,level)) \ 427 | {\ 428 | zsummer::log4z::LogData * __pLog = zsummer::log4z::ILog4zManager::getPtr()->makeLogData(id, level); \ 429 | int __logLen = _snprintf_s(__pLog->_content + __pLog->_contentLen, LOG4Z_LOG_BUF_SIZE - __pLog->_contentLen, _TRUNCATE, logformat, ##__VA_ARGS__); \ 430 | if (__logLen < 0) __logLen = LOG4Z_LOG_BUF_SIZE - __pLog->_contentLen; \ 431 | __pLog->_contentLen += __logLen; \ 432 | zsummer::log4z::ILog4zManager::getPtr()->pushLog(__pLog, file, line); \ 433 | }\ 434 | } while (0) 435 | #else 436 | #define LOG_FORMAT(id, level, file, line, logformat, ...) \ 437 | do{ \ 438 | if (zsummer::log4z::ILog4zManager::getPtr()->prePushLog(id,level)) \ 439 | {\ 440 | zsummer::log4z::LogData * __pLog = zsummer::log4z::ILog4zManager::getPtr()->makeLogData(id, level); \ 441 | int __logLen = snprintf(__pLog->_content + __pLog->_contentLen, LOG4Z_LOG_BUF_SIZE - __pLog->_contentLen,logformat, ##__VA_ARGS__); \ 442 | if (__logLen < 0) __logLen = 0; \ 443 | if (__logLen > LOG4Z_LOG_BUF_SIZE - __pLog->_contentLen) __logLen = LOG4Z_LOG_BUF_SIZE - __pLog->_contentLen; \ 444 | __pLog->_contentLen += __logLen; \ 445 | zsummer::log4z::ILog4zManager::getPtr()->pushLog(__pLog, file, line); \ 446 | } \ 447 | }while(0) 448 | #endif 449 | //!format string 450 | #define LOGFMT_TRACE(id, fmt, ...) LOG_FORMAT(id, LOG_LEVEL_TRACE, __FILE__, __LINE__, fmt, ##__VA_ARGS__) 451 | #define LOGFMT_DEBUG(id, fmt, ...) LOG_FORMAT(id, LOG_LEVEL_DEBUG, __FILE__, __LINE__, fmt, ##__VA_ARGS__) 452 | #define LOGFMT_INFO(id, fmt, ...) LOG_FORMAT(id, LOG_LEVEL_INFO, __FILE__, __LINE__, fmt, ##__VA_ARGS__) 453 | #define LOGFMT_WARN(id, fmt, ...) LOG_FORMAT(id, LOG_LEVEL_WARN, __FILE__, __LINE__, fmt, ##__VA_ARGS__) 454 | #define LOGFMT_ERROR(id, fmt, ...) LOG_FORMAT(id, LOG_LEVEL_ERROR, __FILE__, __LINE__, fmt, ##__VA_ARGS__) 455 | #define LOGFMT_ALARM(id, fmt, ...) LOG_FORMAT(id, LOG_LEVEL_ALARM, __FILE__, __LINE__, fmt, ##__VA_ARGS__) 456 | #define LOGFMT_FATAL(id, fmt, ...) LOG_FORMAT(id, LOG_LEVEL_FATAL, __FILE__, __LINE__, fmt, ##__VA_ARGS__) 457 | #define LOGFMTT( fmt, ...) LOGFMT_TRACE(LOG4Z_MAIN_LOGGER_ID, fmt, ##__VA_ARGS__) 458 | #define LOGFMTD( fmt, ...) LOGFMT_DEBUG(LOG4Z_MAIN_LOGGER_ID, fmt, ##__VA_ARGS__) 459 | #define LOGFMTI( fmt, ...) LOGFMT_INFO(LOG4Z_MAIN_LOGGER_ID, fmt, ##__VA_ARGS__) 460 | #define LOGFMTW( fmt, ...) LOGFMT_WARN(LOG4Z_MAIN_LOGGER_ID, fmt, ##__VA_ARGS__) 461 | #define LOGFMTE( fmt, ...) LOGFMT_ERROR(LOG4Z_MAIN_LOGGER_ID, fmt, ##__VA_ARGS__) 462 | #define LOGFMTA( fmt, ...) LOGFMT_ALARM(LOG4Z_MAIN_LOGGER_ID, fmt, ##__VA_ARGS__) 463 | #define LOGFMTF( fmt, ...) LOGFMT_FATAL(LOG4Z_MAIN_LOGGER_ID, fmt, ##__VA_ARGS__) 464 | #else 465 | inline void empty_log_format_function1(LoggerId id, const char*, ...){} 466 | inline void empty_log_format_function2(const char*, ...){} 467 | #define LOGFMT_TRACE empty_log_format_function1 468 | #define LOGFMT_DEBUG LOGFMT_TRACE 469 | #define LOGFMT_INFO LOGFMT_TRACE 470 | #define LOGFMT_WARN LOGFMT_TRACE 471 | #define LOGFMT_ERROR LOGFMT_TRACE 472 | #define LOGFMT_ALARM LOGFMT_TRACE 473 | #define LOGFMT_FATAL LOGFMT_TRACE 474 | #define LOGFMTT empty_log_format_function2 475 | #define LOGFMTD LOGFMTT 476 | #define LOGFMTI LOGFMTT 477 | #define LOGFMTW LOGFMTT 478 | #define LOGFMTE LOGFMTT 479 | #define LOGFMTA LOGFMTT 480 | #define LOGFMTF LOGFMTT 481 | #endif 482 | 483 | 484 | _ZSUMMER_BEGIN 485 | _ZSUMMER_LOG4Z_BEGIN 486 | 487 | //! optimze from std::stringstream to Log4zStream 488 | #ifdef WIN32 489 | #pragma warning(push) 490 | #pragma warning(disable:4996) 491 | #endif 492 | class Log4zBinary 493 | { 494 | public: 495 | Log4zBinary(const void * buf, size_t len) 496 | { 497 | this->buf = (const char *)buf; 498 | this->len = len; 499 | } 500 | const char * buf; 501 | size_t len; 502 | }; 503 | 504 | class Log4zString 505 | { 506 | public: 507 | Log4zString(const char * buf, size_t len) 508 | { 509 | this->buf = (const char *)buf; 510 | this->len = len; 511 | } 512 | const char * buf; 513 | size_t len; 514 | }; 515 | 516 | class Log4zStream 517 | { 518 | public: 519 | inline Log4zStream(char * buf, int len); 520 | inline int getCurrentLen(){return (int)(_cur - _begin);} 521 | public: 522 | inline Log4zStream & writeLongLong(long long t, int width = 0, int dec = 10); 523 | inline Log4zStream & writeULongLong(unsigned long long t, int width = 0, int dec = 10); 524 | inline Log4zStream & writeDouble(double t, bool isSimple); 525 | inline Log4zStream & writePointer(const void * t); 526 | inline Log4zStream & writeString(const char * t) { return writeString(t, strlen(t)); }; 527 | inline Log4zStream & writeString(const char * t, size_t len); 528 | inline Log4zStream & writeChar(char ch); 529 | inline Log4zStream & writeBinary(const Log4zBinary & t); 530 | public: 531 | inline Log4zStream & operator <<(const void * t){ return writePointer(t); } 532 | 533 | inline Log4zStream & operator <<(const char * t){return writeString(t);} 534 | 535 | inline Log4zStream & operator <<(bool t){ return (t ? writeString("true", 4) : writeString("false", 5));} 536 | 537 | inline Log4zStream & operator <<(char t){return writeChar(t);} 538 | 539 | inline Log4zStream & operator <<(unsigned char t){return writeULongLong(t);} 540 | 541 | inline Log4zStream & operator <<(short t){ return writeLongLong(t); } 542 | 543 | inline Log4zStream & operator <<(unsigned short t){ return writeULongLong(t); } 544 | 545 | inline Log4zStream & operator <<(int t){return writeLongLong(t);} 546 | 547 | inline Log4zStream & operator <<(unsigned int t){return writeULongLong(t);} 548 | 549 | inline Log4zStream & operator <<(long t) { return writeLongLong(t); } 550 | 551 | inline Log4zStream & operator <<(unsigned long t){ return writeULongLong(t); } 552 | 553 | inline Log4zStream & operator <<(long long t) { return writeLongLong(t); } 554 | 555 | inline Log4zStream & operator <<(unsigned long long t){ return writeULongLong(t); } 556 | 557 | inline Log4zStream & operator <<(float t){return writeDouble(t, true);} 558 | 559 | inline Log4zStream & operator <<(double t){return writeDouble(t, false);} 560 | 561 | template //support std::string, std::wstring 562 | inline Log4zStream & operator <<(const std::basic_string<_Elem, _Traits, _Alloc> & t){ return writeString(t.c_str(), t.length()); } 563 | 564 | inline Log4zStream & operator << (const zsummer::log4z::Log4zBinary & binary) { return writeBinary(binary); } 565 | 566 | inline Log4zStream & operator << (const zsummer::log4z::Log4zString & str) { return writeString(str.buf, str.len); } 567 | 568 | template 569 | inline Log4zStream & operator <<(const std::pair<_Ty1, _Ty2> & t){ return *this << "pair(" << t.first << ":" << t.second << ")"; } 570 | 571 | template 572 | inline Log4zStream & operator <<(const std::vector<_Elem, _Alloc> & t) 573 | { 574 | *this << "vector(" << t.size() << ")["; 575 | int inputCount = 0; 576 | for (typename std::vector<_Elem, _Alloc>::const_iterator iter = t.begin(); iter != t.end(); iter++) 577 | { 578 | inputCount++; 579 | if (inputCount > LOG4Z_LOG_CONTAINER_DEPTH) 580 | { 581 | *this << "..., "; 582 | break; 583 | } 584 | *this << *iter << ", "; 585 | } 586 | if (!t.empty()) 587 | { 588 | _cur -= 2; 589 | } 590 | return *this << "]"; 591 | } 592 | template 593 | inline Log4zStream & operator <<(const std::list<_Elem, _Alloc> & t) 594 | { 595 | *this << "list(" << t.size() << ")["; 596 | int inputCount = 0; 597 | for (typename std::list<_Elem, _Alloc>::const_iterator iter = t.begin(); iter != t.end(); iter++) 598 | { 599 | inputCount++; 600 | if (inputCount > LOG4Z_LOG_CONTAINER_DEPTH) 601 | { 602 | *this << "..., "; 603 | break; 604 | } 605 | *this << *iter << ", "; 606 | } 607 | if (!t.empty()) 608 | { 609 | _cur -= 2; 610 | } 611 | return *this << "]"; 612 | } 613 | template 614 | inline Log4zStream & operator <<(const std::deque<_Elem, _Alloc> & t) 615 | { 616 | *this << "deque(" << t.size() << ")["; 617 | int inputCount = 0; 618 | for (typename std::deque<_Elem, _Alloc>::const_iterator iter = t.begin(); iter != t.end(); iter++) 619 | { 620 | inputCount++; 621 | if (inputCount > LOG4Z_LOG_CONTAINER_DEPTH) 622 | { 623 | *this << "..., "; 624 | break; 625 | } 626 | *this << *iter << ", "; 627 | } 628 | if (!t.empty()) 629 | { 630 | _cur -= 2; 631 | } 632 | return *this << "]"; 633 | } 634 | template 635 | inline Log4zStream & operator <<(const std::queue<_Elem, _Alloc> & t) 636 | { 637 | *this << "queue(" << t.size() << ")["; 638 | int inputCount = 0; 639 | for (typename std::queue<_Elem, _Alloc>::const_iterator iter = t.begin(); iter != t.end(); iter++) 640 | { 641 | inputCount++; 642 | if (inputCount > LOG4Z_LOG_CONTAINER_DEPTH) 643 | { 644 | *this << "..., "; 645 | break; 646 | } 647 | *this << *iter << ", "; 648 | } 649 | if (!t.empty()) 650 | { 651 | _cur -= 2; 652 | } 653 | return *this << "]"; 654 | } 655 | template 656 | inline Log4zStream & operator <<(const std::map<_K, _V, _Pr, _Alloc> & t) 657 | { 658 | *this << "map(" << t.size() << ")["; 659 | int inputCount = 0; 660 | for (typename std::map < _K, _V, _Pr, _Alloc>::const_iterator iter = t.begin(); iter != t.end(); iter++) 661 | { 662 | inputCount++; 663 | if (inputCount > LOG4Z_LOG_CONTAINER_DEPTH) 664 | { 665 | *this << "..., "; 666 | break; 667 | } 668 | *this << *iter << ", "; 669 | } 670 | if (!t.empty()) 671 | { 672 | _cur -= 2; 673 | } 674 | return *this << "]"; 675 | } 676 | 677 | private: 678 | Log4zStream(){} 679 | Log4zStream(Log4zStream &){} 680 | char * _begin; 681 | char * _end; 682 | char * _cur; 683 | }; 684 | 685 | inline Log4zStream::Log4zStream(char * buf, int len) 686 | { 687 | _begin = buf; 688 | _end = buf + len; 689 | _cur = _begin; 690 | } 691 | 692 | 693 | 694 | inline Log4zStream & Log4zStream::writeLongLong(long long t, int width, int dec) 695 | { 696 | if (t < 0 ) 697 | { 698 | t = -t; 699 | writeChar('-'); 700 | } 701 | writeULongLong((unsigned long long)t, width, dec); 702 | return *this; 703 | } 704 | 705 | inline Log4zStream & Log4zStream::writeULongLong(unsigned long long t, int width, int dec) 706 | { 707 | static const char * lut = 708 | "0123456789abcdef"; 709 | 710 | static const char *lutDec = 711 | "00010203040506070809" 712 | "10111213141516171819" 713 | "20212223242526272829" 714 | "30313233343536373839" 715 | "40414243444546474849" 716 | "50515253545556575859" 717 | "60616263646566676869" 718 | "70717273747576777879" 719 | "80818283848586878889" 720 | "90919293949596979899"; 721 | 722 | static const char *lutHex = 723 | "000102030405060708090A0B0C0D0E0F" 724 | "101112131415161718191A1B1C1D1E1F" 725 | "202122232425262728292A2B2C2D2E2F" 726 | "303132333435363738393A3B3C3D3E3F" 727 | "404142434445464748494A4B4C4D4E4F" 728 | "505152535455565758595A5B5C5D5E5F" 729 | "606162636465666768696A6B6C6D6E6F" 730 | "707172737475767778797A7B7C7D7E7F" 731 | "808182838485868788898A8B8C8D8E8F" 732 | "909192939495969798999A9B9C9D9E9F" 733 | "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF" 734 | "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF" 735 | "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF" 736 | "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF" 737 | "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF" 738 | "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"; 739 | 740 | const unsigned long long cacheSize = 64; 741 | 742 | if ((unsigned long long)(_end - _cur) > cacheSize) 743 | { 744 | char buf[cacheSize]; 745 | unsigned long long val = t; 746 | unsigned long long i = cacheSize; 747 | unsigned long long digit = 0; 748 | 749 | 750 | 751 | if (dec == 10) 752 | { 753 | do 754 | { 755 | const unsigned long long m2 = (unsigned long long)((val % 100) * 2); 756 | *(buf + i - 1) = lutDec[m2 + 1]; 757 | *(buf + i - 2) = lutDec[m2]; 758 | i -= 2; 759 | val /= 100; 760 | digit += 2; 761 | } while (val && i >= 2); 762 | if (digit >= 2 && buf[cacheSize - digit] == '0') 763 | { 764 | digit--; 765 | } 766 | } 767 | else if (dec == 16) 768 | { 769 | do 770 | { 771 | const unsigned long long m2 = (unsigned long long)((val % 256) * 2); 772 | *(buf + i - 1) = lutHex[m2 + 1]; 773 | *(buf + i - 2) = lutHex[m2]; 774 | i -= 2; 775 | val /= 256; 776 | digit += 2; 777 | } while (val && i >= 2); 778 | if (digit >= 2 && buf[cacheSize - digit] == '0') 779 | { 780 | digit--; 781 | } 782 | } 783 | else 784 | { 785 | do 786 | { 787 | buf[--i] = lut[val % dec]; 788 | val /= dec; 789 | digit++; 790 | } while (val && i > 0); 791 | } 792 | 793 | while (digit < (unsigned long long)width) 794 | { 795 | digit++; 796 | buf[cacheSize - digit] = '0'; 797 | } 798 | 799 | writeString(buf + (cacheSize - digit), (size_t)digit); 800 | } 801 | return *this; 802 | } 803 | inline Log4zStream & Log4zStream::writeDouble(double t, bool isSimple) 804 | { 805 | 806 | #if __cplusplus >= 201103L 807 | using std::isnan; 808 | using std::isinf; 809 | #endif 810 | if (isnan(t)) 811 | { 812 | writeString("nan", 3); 813 | return *this; 814 | } 815 | else if (isinf(t)) 816 | { 817 | writeString("inf", 3); 818 | return *this; 819 | } 820 | 821 | 822 | 823 | size_t count = _end - _cur; 824 | double fabst = fabs(t); 825 | if (count > 30) 826 | { 827 | if ( fabst < 0.0001 || (!isSimple && fabst > 4503599627370495ULL) || (isSimple && fabst > 8388607)) 828 | { 829 | gcvt(t, isSimple ? 7 : 16, _cur); 830 | size_t len = strlen(_cur); 831 | if (len > count) len = count; 832 | _cur += len; 833 | return *this; 834 | } 835 | else 836 | { 837 | if (t < 0.0) 838 | { 839 | writeChar('-'); 840 | } 841 | double intpart = 0; 842 | unsigned long long fractpart = (unsigned long long)(modf(fabst, &intpart) * 10000); 843 | writeULongLong((unsigned long long)intpart); 844 | if (fractpart > 0) 845 | { 846 | writeChar('.'); 847 | writeULongLong(fractpart, 4); 848 | } 849 | } 850 | } 851 | 852 | return *this; 853 | } 854 | 855 | inline Log4zStream & Log4zStream::writePointer(const void * t) 856 | { 857 | sizeof(t) == 8 ? writeULongLong((unsigned long long)t, 16, 16): writeULongLong((unsigned long long)t, 8, 16); 858 | return *this; 859 | } 860 | 861 | inline Log4zStream & Log4zStream::writeBinary(const Log4zBinary & t) 862 | { 863 | writeString("\r\n\t["); 864 | for (size_t i=0; i<(t.len / 32)+1; i++) 865 | { 866 | writeString("\r\n\t"); 867 | *this << (void*)(t.buf + i*32); 868 | writeString(": "); 869 | for (size_t j = i * 32; j < (i + 1) * 32 && j < t.len; j++) 870 | { 871 | if (isprint((unsigned char)t.buf[j])) 872 | { 873 | writeChar(' '); 874 | writeChar(t.buf[j]); 875 | writeChar(' '); 876 | } 877 | else 878 | { 879 | *this << " . "; 880 | } 881 | } 882 | writeString("\r\n\t"); 883 | *this << (void*)(t.buf + i * 32); 884 | writeString(": "); 885 | for (size_t j = i * 32; j < (i + 1) * 32 && j < t.len; j++) 886 | { 887 | writeULongLong((unsigned long long)(unsigned char)t.buf[j], 2, 16); 888 | writeChar(' '); 889 | } 890 | } 891 | 892 | writeString("\r\n\t]\r\n\t"); 893 | return *this; 894 | } 895 | inline Log4zStream & zsummer::log4z::Log4zStream::writeChar(char ch) 896 | { 897 | if (_end - _cur > 1) 898 | { 899 | _cur[0] = ch; 900 | _cur++; 901 | } 902 | return *this; 903 | } 904 | 905 | inline Log4zStream & zsummer::log4z::Log4zStream::writeString(const char * t, size_t len) 906 | { 907 | size_t count = _end - _cur; 908 | if (len > count) 909 | { 910 | len = count; 911 | } 912 | if (len > 0) 913 | { 914 | memcpy(_cur, t, len); 915 | _cur += len; 916 | } 917 | 918 | return *this; 919 | } 920 | 921 | 922 | 923 | 924 | #ifdef WIN32 925 | #pragma warning(pop) 926 | #endif 927 | 928 | _ZSUMMER_LOG4Z_END 929 | _ZSUMMER_END 930 | 931 | #endif 932 | --------------------------------------------------------------------------------