├── .gitignore ├── Build.bat ├── Build.lst ├── Copying.txt ├── License.txt ├── LoggingUtil.rcx ├── LoggingUtil.sln ├── LoggingUtil.vcxproj ├── LoggingUtil.vcxproj.filters ├── ReadMe.txt ├── etc ├── 7za.exe └── date.exe └── src ├── InputReader.cpp ├── InputReader.h ├── LogProcessor.cpp ├── LogProcessor.h ├── LoggingUtil.cpp └── Version.h /.gitignore: -------------------------------------------------------------------------------- 1 | /tmp 2 | /Win32 3 | /out 4 | *.suo 5 | *.opensdf 6 | *.sdf 7 | *.user -------------------------------------------------------------------------------- /Build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM /////////////////////////////////////////////////////////////////////////// 3 | REM // Set Paths 4 | REM /////////////////////////////////////////////////////////////////////////// 5 | set "MSVC_PATH=D:\Microsoft Visual Studio 11.0\VC" 6 | set "QTVC_PATH=D:\Qt\4.8.4" 7 | set "UPX3_PATH=D:\UPX" 8 | 9 | REM ############################################### 10 | REM # DO NOT MODIFY ANY LINES BELOW THIS LINE !!! # 11 | REM ############################################### 12 | 13 | 14 | REM /////////////////////////////////////////////////////////////////////////// 15 | REM // Setup environment 16 | REM /////////////////////////////////////////////////////////////////////////// 17 | if exist "%QTVC_PATH%\bin\qtvars.bat" ( call "%QTVC_PATH%\bin\qtvars.bat" ) 18 | if exist "%QTVC_PATH%\bin\qtenv2.bat" ( call "%QTVC_PATH%\bin\qtenv2.bat" ) 19 | call "%MSVC_PATH%\vcvarsall.bat" x86 20 | 21 | REM /////////////////////////////////////////////////////////////////////////// 22 | REM // Check environment 23 | REM /////////////////////////////////////////////////////////////////////////// 24 | if "%VCINSTALLDIR%"=="" ( 25 | echo %%VCINSTALLDIR%% not specified. Please check your MSVC_PATH var! 26 | goto BuildError 27 | ) 28 | if "%QTDIR%"=="" ( 29 | echo %%QTDIR%% not specified. Please check your MSVC_PATH var! 30 | goto BuildError 31 | ) 32 | if not exist "%VCINSTALLDIR%\bin\cl.exe" ( 33 | echo C++ compiler not found. Please check your MSVC_PATH var! 34 | goto BuildError 35 | ) 36 | if not exist "%QTDIR%\bin\moc.exe" ( 37 | echo Qt meta compiler not found. Please check your QTVC_PATH var! 38 | goto BuildError 39 | ) 40 | 41 | REM /////////////////////////////////////////////////////////////////////////// 42 | REM // Get current date and time (in ISO format) 43 | REM /////////////////////////////////////////////////////////////////////////// 44 | set "ISO_DATE=" 45 | set "ISO_TIME=" 46 | if not exist "%~dp0\etc\date.exe" goto BuildError 47 | for /F "tokens=1,2 delims=:" %%a in ('"%~dp0\etc\date.exe" +ISODATE:%%Y-%%m-%%d') do ( 48 | if "%%a"=="ISODATE" set "ISO_DATE=%%b" 49 | ) 50 | for /F "tokens=1,2,3,4 delims=:" %%a in ('"%~dp0\etc\date.exe" +ISOTIME:%%T') do ( 51 | if "%%a"=="ISOTIME" set "ISO_TIME=%%b:%%c:%%d" 52 | ) 53 | if "%ISO_DATE%"=="" goto BuildError 54 | if "%ISO_TIME%"=="" goto BuildError 55 | 56 | if exist "%~dp0\out\Logger.%ISO_DATE%.zip" ( 57 | echo %~dp0\out\Logger.%ISO_DATE%.zip already exists !!! 58 | goto BuildError 59 | ) 60 | 61 | REM /////////////////////////////////////////////////////////////////////////// 62 | REM // Build the binaries 63 | REM /////////////////////////////////////////////////////////////////////////// 64 | echo --------------------------------------------------------------------- 65 | echo BEGIN BUILD 66 | echo --------------------------------------------------------------------- 67 | MSBuild.exe /property:Configuration=Release_Static /target:clean "%~dp0\LoggingUtil.sln" 68 | if not "%ERRORLEVEL%"=="0" goto BuildError 69 | MSBuild.exe /property:Configuration=Release_Static /target:rebuild "%~dp0\LoggingUtil.sln" 70 | if not "%ERRORLEVEL%"=="0" goto BuildError 71 | 72 | REM /////////////////////////////////////////////////////////////////////////// 73 | REM // Packge fiiles 74 | REM /////////////////////////////////////////////////////////////////////////// 75 | echo --------------------------------------------------------------------- 76 | echo PACKAGE FILES 77 | echo --------------------------------------------------------------------- 78 | "%UPX3_PATH%\UPX.exe" --brute "%~dp0\Win32\Release_Static\*.exe" 79 | echo %ISO_DATE% %ISO_TIME% > "%~dp0\Win32\Release_Static\BUILD.tag" 80 | "%~dp0\etc\7za.exe" a -tzip "%~dp0\out\Logger.%ISO_DATE%.zip" "@%~dp0\Build.lst" 81 | attrib +R "%~dp0\out\Logger.%ISO_DATE%.zip" 82 | del "%~dp0\Win32\Release_Static\BUILD.tag" 83 | 84 | REM /////////////////////////////////////////////////////////////////////////// 85 | REM // COMPLETE 86 | REM /////////////////////////////////////////////////////////////////////////// 87 | echo. 88 | echo Build completed. 89 | echo. 90 | pause 91 | goto:eof 92 | 93 | REM /////////////////////////////////////////////////////////////////////////// 94 | REM // FAILED 95 | REM /////////////////////////////////////////////////////////////////////////// 96 | :BuildError 97 | echo. 98 | echo Build has failed !!! 99 | echo. 100 | pause 101 | -------------------------------------------------------------------------------- /Build.lst: -------------------------------------------------------------------------------- 1 | .\Win32\Release_Static\LoggingUtil.exe 2 | .\Win32\Release_Static\BUILD.tag 3 | .\ReadMe.txt 4 | .\Copying.txt 5 | .\License.txt 6 | -------------------------------------------------------------------------------- /Copying.txt: -------------------------------------------------------------------------------- 1 | Logging Utility was created from the scratch by LoRd_MuldeR and is distributed under the terms of the GNU General Public License ('License.txt'). 2 | 3 | The Qt GUI Toolkit is Copyright (C) 2012 Digia Finland Ltd and/or its subsidiary(-ies). You may use, distribute and copy the Qt GUI Toolkit under the terms of GNU General Public License version 3. 4 | 5 | x264 is Copyright (C) 2003-2012 'x264 project' and is distributed under the terms of GNU General Public License. 6 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | 342 | 343 | -------------------------------------------------------------------------------- /LoggingUtil.rcx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lordmulder/LoggingUtil/11dedf7b8c8d6173d8308dd9411c16f4a29e3d94/LoggingUtil.rcx -------------------------------------------------------------------------------- /LoggingUtil.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LoggingUtil", "LoggingUtil.vcxproj", "{999BC5FA-9DF1-4E8C-AC71-978ECAD95CCD}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release_Static|Win32 = Release_Static|Win32 10 | Release|Win32 = Release|Win32 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {999BC5FA-9DF1-4E8C-AC71-978ECAD95CCD}.Debug|Win32.ActiveCfg = Debug|Win32 14 | {999BC5FA-9DF1-4E8C-AC71-978ECAD95CCD}.Debug|Win32.Build.0 = Debug|Win32 15 | {999BC5FA-9DF1-4E8C-AC71-978ECAD95CCD}.Release_Static|Win32.ActiveCfg = Release_Static|Win32 16 | {999BC5FA-9DF1-4E8C-AC71-978ECAD95CCD}.Release_Static|Win32.Build.0 = Release_Static|Win32 17 | {999BC5FA-9DF1-4E8C-AC71-978ECAD95CCD}.Release|Win32.ActiveCfg = Release|Win32 18 | {999BC5FA-9DF1-4E8C-AC71-978ECAD95CCD}.Release|Win32.Build.0 = Release|Win32 19 | EndGlobalSection 20 | GlobalSection(SolutionProperties) = preSolution 21 | HideSolutionNode = FALSE 22 | EndGlobalSection 23 | EndGlobal 24 | -------------------------------------------------------------------------------- /LoggingUtil.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release_Static 10 | Win32 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | "$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp" "%(FullPath)" 27 | MOC "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp" 28 | $(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp;%(Outputs) 29 | "$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp" "%(FullPath)" 30 | "$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp" "%(FullPath)" 31 | MOC "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp" 32 | MOC "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp" 33 | $(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp;%(Outputs) 34 | $(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp;%(Outputs) 35 | 36 | 37 | 38 | 39 | Document 40 | 41 | 42 | 43 | 44 | "$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp" "%(FullPath)" 45 | "$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp" "%(FullPath)" 46 | "$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp" "%(FullPath)" 47 | MOC "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp" 48 | MOC "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp" 49 | MOC "$(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp" 50 | $(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp;%(Outputs) 51 | $(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp;%(Outputs) 52 | $(SolutionDir)\tmp\Common\moc\MOC_%(Filename).cpp;%(Outputs) 53 | 54 | 55 | 56 | 57 | {999BC5FA-9DF1-4E8C-AC71-978ECAD95CCD} 58 | Win32Proj 59 | LoggingUtil 60 | 61 | 62 | 63 | Application 64 | true 65 | v110_xp 66 | Unicode 67 | 68 | 69 | Application 70 | false 71 | v110_xp 72 | true 73 | Unicode 74 | 75 | 76 | Application 77 | false 78 | v110_xp 79 | true 80 | Unicode 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | true 97 | $(SolutionDir)\$(PlatformName)\$(Configuration)\ 98 | $(SolutionDir)\tmp\$(PlatformName)\$(Configuration)\obj\ 99 | 100 | 101 | false 102 | $(SolutionDir)\$(PlatformName)\$(Configuration)\ 103 | $(SolutionDir)\tmp\$(PlatformName)\$(Configuration)\obj\ 104 | 105 | 106 | false 107 | $(SolutionDir)\$(PlatformName)\$(Configuration)\ 108 | $(SolutionDir)\tmp\$(PlatformName)\$(Configuration)\obj\ 109 | 110 | 111 | 112 | 113 | 114 | Level3 115 | Disabled 116 | WIN32;_CONSOLE;QT_LARGEFILE_SUPPORT;QT_CORE_LIB;QT_THREAD_SUPPORT;QT_DEBUG;QT_DLL;%(PreprocessorDefinitions) 117 | $(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;%(AdditionalIncludeDirectories) 118 | 119 | 120 | Console 121 | true 122 | 123 | 124 | 125 | 126 | Level3 127 | NotUsing 128 | Full 129 | true 130 | true 131 | WIN32;NDEBUG;_CONSOLE;QT_LARGEFILE_SUPPORT;QT_CORE_LIB;QT_THREAD_SUPPORT;QT_NO_DEBUG;QT_DLL;%(PreprocessorDefinitions) 132 | $(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;%(AdditionalIncludeDirectories) 133 | 134 | 135 | AnySuitable 136 | Speed 137 | true 138 | true 139 | MultiThreadedDLL 140 | false 141 | true 142 | NoExtensions 143 | Fast 144 | false 145 | 146 | 147 | Console 148 | false 149 | true 150 | true 151 | QtCore4.lib;%(AdditionalDependencies) 152 | $(QTDIR)\lib;%(AdditionalLibraryDirectories) 153 | UseLinkTimeCodeGeneration 154 | 155 | 156 | copy /y /b "$(QTDIR)\bin\QtCore4.dll" "$(OutDir)" 157 | 158 | 159 | 160 | 161 | Level3 162 | NotUsing 163 | Full 164 | true 165 | true 166 | WIN32;NDEBUG;_CONSOLE;QT_LARGEFILE_SUPPORT;QT_CORE_LIB;QT_THREAD_SUPPORT;QT_NO_DEBUG;QT_NODLL;%(PreprocessorDefinitions) 167 | $(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;%(AdditionalIncludeDirectories) 168 | 169 | 170 | AnySuitable 171 | Speed 172 | true 173 | true 174 | MultiThreaded 175 | false 176 | true 177 | NoExtensions 178 | Fast 179 | false 180 | 181 | 182 | Console 183 | false 184 | true 185 | true 186 | QtCore.lib;Ws2_32.lib;%(AdditionalDependencies) 187 | $(SolutionDir)..\LameXP_Qt\LameXP\etc\Prerequisites\qt4_static\lib\;%(AdditionalLibraryDirectories) 188 | UseLinkTimeCodeGeneration 189 | 5.01 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /LoggingUtil.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {9f2be553-195c-4a96-a4c4-b365e910d011} 18 | 19 | 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files\Generated 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files\Generated 35 | 36 | 37 | 38 | 39 | Header Files 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | Header Files 48 | 49 | 50 | Header Files 51 | 52 | 53 | -------------------------------------------------------------------------------- /ReadMe.txt: -------------------------------------------------------------------------------- 1 | StdOut/StdErr Logging Utility 2 | Created by LoRd_MuldeR 3 | http://www.muldersoft.com/ 4 | 5 | 6 | Synopsis 7 | ======== 8 | 9 | Usage Mode #1: 10 | LoggingUtil.exe SomeProgram.exe [program parameters] 11 | LoggingUtil.exe [logging options] : SomeProgram.exe [program parameters] 12 | 13 | Usage Mode #2: 14 | SomeProgram.exe [parameters] | LoggingUtil.exe [options] : #STDIN# 15 | SomeProgram.exe [parameters] 2>&1 | LoggingUtil.exe [options] : #STDIN# 16 | 17 | Logging Options: 18 | --logfile Specifies the output log file (appends if file exists) 19 | --only-stdout Capture only output from STDOUT, ignores STDERR 20 | --only-stderr Capture only output from STDERR, ignores STDOUT 21 | --no-simplify Do NOT simplify/trimm the logged strings (default: on) 22 | --no-append Do NOT append, i.e. any existing log content is lost 23 | --plain-output Create less verbose logging output 24 | --html-output Create HTML logging output, implies NO append 25 | --regexp-keep Keep ONLY strings that match the given RegExp 26 | --regexp-skip Skip all the strings that match the given RegExp 27 | --codec-in Setup the input text encoding (default: "UTF-8") 28 | --codec-out Setup the output text encoding (default: "UTF-8") 29 | 30 | Examples: 31 | LoggingUtil.exe --logfile x264_log.txt : x264.exe -o output.mkv input.avs 32 | x264.exe -o output.mkv input.avs 2>&1 | LoggingUtil.exe : #STDIN# 33 | 34 | License 35 | ======= 36 | 37 | Copyright (C) 2010-2013 LoRd_MuldeR 38 | http://www.muldersoft.com/ 39 | 40 | This program is free software; you can redistribute it and/or modify 41 | it under the terms of the GNU General Public License as published by 42 | the Free Software Foundation; either version 2 of the License, or 43 | (at your option) any later version. 44 | 45 | This program is distributed in the hope that it will be useful, 46 | but WITHOUT ANY WARRANTY; without even the implied warranty of 47 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 48 | GNU General Public License for more details. 49 | 50 | You should have received a copy of the GNU General Public License along 51 | with this program; if not, write to the Free Software Foundation, Inc., 52 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 53 | 54 | http://www.gnu.org/licenses/gpl-2.0.txt 55 | -------------------------------------------------------------------------------- /etc/7za.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lordmulder/LoggingUtil/11dedf7b8c8d6173d8308dd9411c16f4a29e3d94/etc/7za.exe -------------------------------------------------------------------------------- /etc/date.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lordmulder/LoggingUtil/11dedf7b8c8d6173d8308dd9411c16f4a29e3d94/etc/date.exe -------------------------------------------------------------------------------- /src/InputReader.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // Logging Utility 3 | // Copyright (C) 2010-2013 LoRd_MuldeR 4 | // 5 | // This program is free software; you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation; either version 2 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along 16 | // with this program; if not, write to the Free Software Foundation, Inc., 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | // http://www.gnu.org/licenses/gpl-2.0.txt 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "InputReader.h" 23 | 24 | //Windows 25 | #define WIN32_LEAN_AND_MEAN 26 | #include 27 | 28 | //Qt 29 | #include 30 | #include 31 | 32 | /* 33 | * Constructor 34 | */ 35 | CInputReader::CInputReader(void) 36 | : 37 | m_aborted(false), 38 | m_threadHandle(INVALID_HANDLE_VALUE), 39 | m_cancelSyncIo(NULL) 40 | { 41 | m_dataLock = new QMutex(); 42 | m_data = new QByteArray(); 43 | 44 | if(HMODULE krnl32 = GetModuleHandleA("Kernel32.dll")) 45 | { 46 | m_cancelSyncIo = (FunCancelSynchronousIo) GetProcAddress(krnl32, "CancelSynchronousIo"); 47 | } 48 | } 49 | 50 | /* 51 | * Destructor 52 | */ 53 | CInputReader::~CInputReader(void) 54 | { 55 | delete m_data; 56 | delete m_dataLock; 57 | 58 | if(m_threadHandle != INVALID_HANDLE_VALUE) 59 | { 60 | CloseHandle(m_threadHandle); 61 | } 62 | } 63 | 64 | /* 65 | * Start thread 66 | */ 67 | void CInputReader::start(Priority priority) 68 | { 69 | m_aborted = false; 70 | QThread::start(priority); 71 | } 72 | 73 | /* 74 | * Abort Thread 75 | */ 76 | void CInputReader::abort(void) 77 | { 78 | m_aborted = true; 79 | if(m_cancelSyncIo && (m_threadHandle != INVALID_HANDLE_VALUE)) 80 | { 81 | m_cancelSyncIo(m_threadHandle); 82 | } 83 | } 84 | 85 | /* 86 | * Thread entry point 87 | */ 88 | void CInputReader::run(void) 89 | { 90 | //Setup thread handle 91 | if(!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &m_threadHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) 92 | { 93 | m_threadHandle = INVALID_HANDLE_VALUE; 94 | } 95 | 96 | //Setup local variables 97 | BYTE buffer[1024]; 98 | HANDLE h = GetStdHandle(STD_INPUT_HANDLE); 99 | DWORD bytesRead = 0; 100 | 101 | //Main processing loop 102 | while(!m_aborted) 103 | { 104 | if(ReadFile(h, buffer, 1024, &bytesRead, NULL)) 105 | { 106 | if(bytesRead > 0) 107 | { 108 | QMutexLocker lock(m_dataLock); 109 | m_data->append(reinterpret_cast(buffer), bytesRead); 110 | lock.unlock(); 111 | emit dataAvailable(bytesRead); 112 | continue; 113 | } 114 | } 115 | break; 116 | } 117 | } 118 | 119 | /* 120 | * Read all data currently available 121 | */ 122 | size_t CInputReader::readAllData(QByteArray &output) 123 | { 124 | QMutexLocker lock(m_dataLock); 125 | const size_t bytes = m_data->size(); 126 | output.append(m_data->constData(), bytes); 127 | m_data->clear(); 128 | return bytes; 129 | } 130 | -------------------------------------------------------------------------------- /src/InputReader.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // Logging Utility 3 | // Copyright (C) 2010-2013 LoRd_MuldeR 4 | // 5 | // This program is free software; you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation; either version 2 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along 16 | // with this program; if not, write to the Free Software Foundation, Inc., 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | // http://www.gnu.org/licenses/gpl-2.0.txt 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include 25 | 26 | //Forward declartion 27 | class QMutex; 28 | 29 | //Typedef 30 | typedef int (__stdcall *FunCancelSynchronousIo)(void *hThread); 31 | 32 | //Class CInputReader 33 | class CInputReader : public QThread 34 | { 35 | Q_OBJECT; 36 | 37 | public: 38 | CInputReader(void); 39 | ~CInputReader(void); 40 | 41 | size_t readAllData(QByteArray &output); 42 | void abort(void); 43 | 44 | signals: 45 | void dataAvailable(quint32 newBytes); 46 | 47 | public slots: 48 | void start(Priority priority = InheritPriority); 49 | 50 | protected: 51 | virtual void run(void); 52 | 53 | volatile bool m_aborted; 54 | QByteArray *m_data; 55 | QMutex *m_dataLock; 56 | 57 | FunCancelSynchronousIo m_cancelSyncIo; 58 | void *m_threadHandle; 59 | }; 60 | -------------------------------------------------------------------------------- /src/LogProcessor.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // Logging Utility 3 | // Copyright (C) 2010-2013 LoRd_MuldeR 4 | // 5 | // This program is free software; you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation; either version 2 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along 16 | // with this program; if not, write to the Free Software Foundation, Inc., 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | // http://www.gnu.org/licenses/gpl-2.0.txt 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #include "LogProcessor.h" 23 | 24 | //Windows 25 | #define WIN32_LEAN_AND_MEAN 26 | #include 27 | 28 | //Qt 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | //Internal 38 | #include "InputReader.h" 39 | 40 | //Const 41 | static const int CHANNEL_STDOUT = 1; 42 | static const int CHANNEL_STDERR = 2; 43 | static const int CHANNEL_STDINP = 4; 44 | static const int CHANNEL_SYSMSG = 8; 45 | 46 | //Helper 47 | #define SAFE_DEL(X) do { if(X) { delete (X); X = NULL; } } while (0) 48 | 49 | // =================================================== 50 | // Constructor & Destructor 51 | // =================================================== 52 | 53 | /* 54 | * Constructor 55 | */ 56 | CLogProcessor::CLogProcessor(QFile &logFile) 57 | : 58 | m_logStdout(true), 59 | m_logStderr(true), 60 | m_simplify(true), 61 | m_logFormat(LOG_FORMAT_VERBOSE), 62 | m_logInitialized(false), 63 | m_logFinished(false), 64 | m_logIsEmpty(logFile.size() == 0), 65 | m_exitCode(-1) 66 | { 67 | //Sanity check 68 | if(!(logFile.isOpen() && logFile.isWritable())) 69 | { 70 | throw "Log file not open for writing!"; 71 | } 72 | 73 | //Create process 74 | m_process = new QProcess(); 75 | 76 | //Setup process 77 | m_process->setProcessChannelMode(QProcess::SeparateChannels); 78 | connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readFromStdout())); 79 | connect(m_process, SIGNAL(readyReadStandardError()), this, SLOT(readFromStderr())); 80 | connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished(int))); 81 | 82 | //Setup STDIN reader 83 | m_stdinReader = new CInputReader(); 84 | connect(m_stdinReader, SIGNAL(dataAvailable(quint32)), this, SLOT(readFromStdinp(void)), Qt::QueuedConnection); 85 | connect(m_stdinReader, SIGNAL(finished()), this, SLOT(readerFinished(void)), Qt::QueuedConnection); 86 | 87 | //Create default decoder 88 | QTextCodec *codec = QTextCodec::codecForName("UTF-8"); 89 | m_codecStdout = new QTextDecoder(codec); 90 | m_codecStderr = new QTextDecoder(codec); 91 | m_codecStdinp = new QTextDecoder(codec); 92 | 93 | //Setup regular exporession 94 | m_regExpEOL = new QRegExp("(\\f|\\n|\\r|\\v)"); 95 | m_regExpKeep = m_regExpSkip = NULL; 96 | 97 | //Assign the log file 98 | m_logFile = new QTextStream(&logFile); 99 | m_logFile->setCodec(QTextCodec::codecForName("UTF-8")); 100 | m_logFile->setGenerateByteOrderMark(m_logIsEmpty); 101 | 102 | //Create event loop 103 | m_eventLoop = new QEventLoop(); 104 | } 105 | 106 | /* 107 | * Destructor 108 | */ 109 | CLogProcessor::~CLogProcessor(void) 110 | { 111 | //Make sure, we are not still running 112 | forceQuit(true); 113 | 114 | //Clean up all heap objects 115 | SAFE_DEL(m_process); 116 | SAFE_DEL(m_stdinReader); 117 | SAFE_DEL(m_regExpEOL); 118 | SAFE_DEL(m_regExpKeep); 119 | SAFE_DEL(m_regExpSkip); 120 | SAFE_DEL(m_eventLoop); 121 | SAFE_DEL(m_logFile); 122 | SAFE_DEL(m_codecStdout); 123 | SAFE_DEL(m_codecStderr); 124 | SAFE_DEL(m_codecStdinp); 125 | } 126 | 127 | // =================================================== 128 | // Public Methods 129 | // =================================================== 130 | 131 | /* 132 | * Start the process 133 | */ 134 | bool CLogProcessor::startProcess(const QString &program, const QStringList &arguments) 135 | { 136 | if(m_process->state() != QProcess::NotRunning) 137 | { 138 | return false; 139 | } 140 | 141 | initializeLog(); 142 | logString(QString("Creating new process: %1 [%2]").arg(program, arguments.join("; ")), CHANNEL_SYSMSG); 143 | 144 | m_process->start(program, arguments); 145 | 146 | if(!m_process->waitForStarted()) 147 | { 148 | logString(QString("Process creation failed: %1").arg(m_process->errorString()) , CHANNEL_SYSMSG); 149 | m_process->kill(); 150 | return false; 151 | } 152 | 153 | logString(QString().sprintf("Process created successfully (PID: 0x%08X)", m_process->pid()->hProcess), CHANNEL_SYSMSG); 154 | return true; 155 | } 156 | 157 | /* 158 | * Start reading from Stdin 159 | */ 160 | bool CLogProcessor::startStdinProcessing(void) 161 | { 162 | if(m_stdinReader->isRunning()) 163 | { 164 | return false; 165 | } 166 | 167 | initializeLog(); 168 | logString("Started logging from STDIN stream...", CHANNEL_SYSMSG); 169 | 170 | m_stdinReader->start(); 171 | return true; 172 | } 173 | 174 | /* 175 | * Event processing 176 | */ 177 | int CLogProcessor::exec(void) 178 | { 179 | if(m_process->state() == QProcess::Running || m_stdinReader->isRunning()) 180 | { 181 | //Make sure we will read immediately 182 | QTimer::singleShot(0, this, SLOT(readFromStdout())); 183 | QTimer::singleShot(0, this, SLOT(readFromStderr())); 184 | QTimer::singleShot(0, this, SLOT(readFromStdinp())); 185 | 186 | //Event processing 187 | return m_eventLoop->exec(); 188 | } 189 | else 190 | { 191 | //Read any pending data (might be that we already finished!) 192 | readFromStdout(); 193 | readFromStderr(); 194 | readFromStdinp(); 195 | 196 | //Flush buffer contents 197 | flushBuffers(); 198 | 199 | //Return last exit code 200 | return m_exitCode; 201 | } 202 | } 203 | 204 | // =================================================== 205 | // Slots 206 | // =================================================== 207 | /* 208 | * Force process to quit ASAP 209 | */ 210 | void CLogProcessor::forceQuit(const bool silent) 211 | { 212 | if(!silent) 213 | { 214 | logString("Aborted by user! (Ctrl+C)", CHANNEL_SYSMSG); 215 | } 216 | 217 | if(m_process) 218 | { 219 | if(m_process->state() != QProcess::NotRunning) 220 | { 221 | if(m_process->state() == QProcess::Starting) 222 | { 223 | m_process->waitForStarted(); 224 | } 225 | m_process->kill(); 226 | m_process->waitForFinished(); 227 | } 228 | } 229 | 230 | if(m_stdinReader) 231 | { 232 | if(m_stdinReader->isRunning()) 233 | { 234 | m_stdinReader->abort(); 235 | if(!m_stdinReader->wait(5000)) 236 | { 237 | m_stdinReader->terminate(); 238 | m_stdinReader->wait(); 239 | } 240 | } 241 | } 242 | } 243 | 244 | /* 245 | * Read from StdOut 246 | */ 247 | void CLogProcessor::readFromStdout(void) 248 | { 249 | const QByteArray data = m_process->readAllStandardOutput(); 250 | 251 | if(data.length() > 0) 252 | { 253 | fwrite(data.constData(), 1, data.length(), stdout); 254 | fflush(stdout); 255 | if(m_logStdout) processData(data, CHANNEL_STDOUT); 256 | } 257 | } 258 | 259 | /* 260 | * Read from StdErr 261 | */ 262 | void CLogProcessor::readFromStderr(void) 263 | { 264 | const QByteArray data = m_process->readAllStandardError(); 265 | 266 | if(data.length() > 0) 267 | { 268 | fwrite(data.constData(), 1, data.length(), stderr); 269 | fflush(stderr); 270 | if(m_logStderr) processData(data, CHANNEL_STDERR); 271 | } 272 | } 273 | 274 | /* 275 | * Read from StdIn 276 | */ 277 | void CLogProcessor::readFromStdinp(void) 278 | { 279 | QByteArray data; 280 | m_stdinReader->readAllData(data); 281 | 282 | if(data.length() > 0) 283 | { 284 | fwrite(data.constData(), 1, data.length(), stderr); 285 | fflush(stderr); 286 | processData(data, CHANNEL_STDINP); 287 | } 288 | } 289 | 290 | /* 291 | * Process has finished 292 | */ 293 | void CLogProcessor::processFinished(int exitCode) 294 | { 295 | //Just to be sure (?) 296 | m_process->waitForFinished(); 297 | 298 | //Process pending outputs 299 | readFromStdout(); 300 | readFromStderr(); 301 | 302 | //Flush buffer contents 303 | flushBuffers(); 304 | 305 | //Now return the exit code 306 | m_exitCode = exitCode; 307 | logString(QString().sprintf("Process has terminated (exit code: 0x%08X)", exitCode), CHANNEL_SYSMSG); 308 | finishLog(); 309 | 310 | m_eventLoop->exit(m_exitCode); 311 | } 312 | 313 | /* 314 | * STDIN reader has finished 315 | */ 316 | void CLogProcessor::readerFinished(void) 317 | { 318 | //Process pending outputs 319 | readFromStdinp(); 320 | 321 | //Flush buffer contents 322 | flushBuffers(); 323 | 324 | //Now return the exit code 325 | logString("No more data available from STDIN (process has terminated)", CHANNEL_SYSMSG); 326 | finishLog(); 327 | 328 | m_eventLoop->exit(0); 329 | } 330 | 331 | // =================================================== 332 | // Private Methods 333 | // =================================================== 334 | 335 | /* 336 | * FLush any pending data from buffer 337 | */ 338 | void CLogProcessor::flushBuffers(void) 339 | { 340 | if(m_logStdout && (!m_bufferStdout.isEmpty())) 341 | { 342 | logString(m_simplify ? m_bufferStdout.simplified() : m_bufferStdout, CHANNEL_STDOUT); 343 | m_bufferStdout.clear(); 344 | } 345 | 346 | if(m_logStderr && (!m_bufferStderr.isEmpty())) 347 | { 348 | logString(m_simplify ? m_bufferStderr.simplified() : m_bufferStderr, CHANNEL_STDERR); 349 | m_bufferStderr.clear(); 350 | } 351 | 352 | if(!m_bufferStdinp.isEmpty()) 353 | { 354 | logString(m_simplify ? m_bufferStdinp.simplified() : m_bufferStdinp, CHANNEL_STDOUT); 355 | m_bufferStdinp.clear(); 356 | } 357 | } 358 | 359 | /* 360 | * Process data (decode and tokenize) 361 | */ 362 | void CLogProcessor::processData(const QByteArray &data, const int channel) 363 | { 364 | QString *buffer = NULL; 365 | QTextDecoder *decoder = NULL; 366 | 367 | switch(channel) 368 | { 369 | case CHANNEL_STDOUT: 370 | buffer = &m_bufferStdout; 371 | decoder = m_codecStdout; 372 | break; 373 | case CHANNEL_STDERR: 374 | buffer = &m_bufferStderr; 375 | decoder = m_codecStderr; 376 | break; 377 | case CHANNEL_STDINP: 378 | buffer = &m_bufferStdinp; 379 | decoder = m_codecStdinp; 380 | break; 381 | default: 382 | throw "Bad selection!"; 383 | } 384 | 385 | buffer->append(decoder->toUnicode(data).replace(QChar('\b'), QChar('\r'))); 386 | 387 | int pos = m_regExpEOL->indexIn(*buffer); 388 | while(pos >= 0) 389 | { 390 | if(pos > 0) 391 | { 392 | logString(m_simplify ? buffer->left(pos).simplified() : buffer->left(pos), channel); 393 | } 394 | buffer->remove(0, pos + 1); 395 | pos = m_regExpEOL->indexIn(*buffer); 396 | } 397 | } 398 | 399 | /* 400 | * Append string to log file 401 | */ 402 | void CLogProcessor::logString(const QString &data, const int channel) 403 | { 404 | //No logging if not ready 405 | if((!m_logInitialized) || m_logFinished) 406 | { 407 | return; 408 | } 409 | 410 | //Do not log any empty strings! 411 | if(data.isEmpty() || ((m_logFormat == LOG_FORMAT_PLAIN) && (channel == CHANNEL_SYSMSG))) 412 | { 413 | return; 414 | } 415 | 416 | //Filter out strings 417 | if(channel != CHANNEL_SYSMSG) 418 | { 419 | if(m_regExpKeep) 420 | { 421 | if(m_regExpKeep->indexIn(data) < 0) return; 422 | } 423 | if(m_regExpSkip) 424 | { 425 | if(m_regExpSkip->indexIn(data) >= 0) return; 426 | } 427 | } 428 | 429 | QChar chanId; 430 | 431 | switch(channel) 432 | { 433 | case CHANNEL_STDOUT: 434 | chanId = 'O'; 435 | break; 436 | case CHANNEL_STDERR: 437 | chanId = 'E'; 438 | break; 439 | case CHANNEL_STDINP: 440 | chanId = 'I'; 441 | break; 442 | case CHANNEL_SYSMSG: 443 | chanId = 'S'; 444 | break; 445 | default: 446 | throw "Bad selection!"; 447 | } 448 | 449 | static const QString format_date("yyyy-MM-dd"), format_time("hh:mm:ss"); 450 | QDateTime time = (m_logFormat == LOG_FORMAT_PLAIN) ? QDateTime() : QDateTime::currentDateTime(); 451 | 452 | switch(m_logFormat) 453 | { 454 | case LOG_FORMAT_VERBOSE: 455 | m_logFile->operator<<(QString("[%1] [%2] [%3] %4\r\n").arg(chanId, time.toString(format_date), time.toString(format_time), data)); 456 | break; 457 | case LOG_FORMAT_PLAIN: 458 | m_logFile->operator<<(QString("%1\r\n").arg(data)); 459 | break; 460 | case LOG_FORMAT_HTML: 461 | m_logFile->operator<<(QString("%1%2%3%4\r\n").arg(chanId, time.toString(format_date), time.toString(format_time), escape(data))); 462 | break; 463 | default: 464 | throw "Bad selection!"; 465 | } 466 | } 467 | 468 | /* 469 | * Initialize log file 470 | */ 471 | void CLogProcessor::initializeLog(void) 472 | { 473 | if(m_logInitialized) 474 | { 475 | return; 476 | } 477 | 478 | if((m_logFormat == LOG_FORMAT_HTML) && m_logIsEmpty) 479 | { 480 | m_logFile->operator<<("\r\n"); 481 | m_logFile->operator<<("Log File\r\n"); 482 | m_logFile->operator<<("\r\n"); 483 | } 484 | if((m_logFormat == LOG_FORMAT_VERBOSE) && (!m_logIsEmpty)) 485 | { 486 | m_logFile->operator<<("---------------------------\r\n"); 487 | } 488 | 489 | m_logInitialized = true; 490 | } 491 | 492 | /* 493 | * Finish log file 494 | */ 495 | void CLogProcessor::finishLog(void) 496 | { 497 | if((!m_logInitialized) || m_logFinished) 498 | { 499 | return; 500 | } 501 | 502 | if((m_logFormat == LOG_FORMAT_HTML) && m_logIsEmpty) 503 | { 504 | m_logFile->operator<<("
 DateTimeLog Message
\r\n"); 505 | } 506 | 507 | m_logFinished = true; 508 | } 509 | 510 | // =================================================== 511 | // Setter methods 512 | // =================================================== 513 | 514 | /* 515 | * Set which streams to capture 516 | */ 517 | void CLogProcessor::setCaptureStreams(const bool captureStdout, const bool captureStderr) 518 | { 519 | m_logStdout = captureStdout; 520 | m_logStderr = captureStderr; 521 | } 522 | 523 | /* 524 | * Set whether strings are simplified/trimmed 525 | */ 526 | void CLogProcessor::setSimplifyStrings(const bool simplify) 527 | { 528 | m_simplify = simplify; 529 | } 530 | 531 | /* 532 | * Set verbose logging mode 533 | */ 534 | void CLogProcessor::setOutputFormat(const Format format) 535 | { 536 | m_logFormat = format; 537 | } 538 | 539 | /* 540 | * Set regular expressions for filtering 541 | */ 542 | void CLogProcessor::setFilterStrings(const QString ®ExpKeep, const QString ®ExpSkip) 543 | { 544 | if(!regExpKeep.isEmpty()) 545 | { 546 | SAFE_DEL(m_regExpKeep); 547 | m_regExpKeep = new QRegExp(regExpKeep); 548 | } 549 | 550 | if(!regExpSkip.isEmpty()) 551 | { 552 | SAFE_DEL(m_regExpSkip); 553 | m_regExpSkip = new QRegExp(regExpSkip); 554 | } 555 | } 556 | 557 | /* 558 | * Set text encodings 559 | */ 560 | bool CLogProcessor::setTextCodecs(const char *inputCodec, const char *outputCodec) 561 | { 562 | if(inputCodec) 563 | { 564 | QTextCodec *codec = QTextCodec::codecForName(inputCodec); 565 | if(codec) 566 | { 567 | SAFE_DEL(m_codecStdout); m_codecStdout = new QTextDecoder(codec); 568 | SAFE_DEL(m_codecStderr); m_codecStderr = new QTextDecoder(codec); 569 | } 570 | else 571 | { 572 | return false; 573 | } 574 | } 575 | 576 | if(outputCodec) 577 | { 578 | QTextCodec *codec = QTextCodec::codecForName(outputCodec); 579 | if(codec) 580 | { 581 | m_logFile->setCodec(codec); 582 | } 583 | else 584 | { 585 | return false; 586 | } 587 | } 588 | 589 | return true; 590 | } 591 | 592 | // =================================================== 593 | // Misc Stuff 594 | // =================================================== 595 | 596 | /* 597 | * Escape (some) HTML characters 598 | */ 599 | QString CLogProcessor::escape(const QString &text) 600 | { 601 | QString escaped(text); 602 | 603 | escaped.replace('<', "<"); 604 | escaped.replace('>', ">"); 605 | escaped.replace('&', "&"); 606 | escaped.replace('"', """); 607 | escaped.replace(' ', " "); 608 | 609 | return escaped; 610 | } 611 | -------------------------------------------------------------------------------- /src/LogProcessor.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // Logging Utility 3 | // Copyright (C) 2010-2013 LoRd_MuldeR 4 | // 5 | // This program is free software; you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation; either version 2 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along 16 | // with this program; if not, write to the Free Software Foundation, Inc., 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | // http://www.gnu.org/licenses/gpl-2.0.txt 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #pragma once 23 | 24 | #include 25 | 26 | //Forward declaration 27 | class QProcess; 28 | class QTextDecoder; 29 | class QStringList; 30 | class QTextStream; 31 | class QFile; 32 | class QEventLoop; 33 | class CInputReader; 34 | 35 | //Class CLogProcessor 36 | class CLogProcessor : public QObject 37 | { 38 | Q_OBJECT 39 | 40 | public: 41 | CLogProcessor(QFile &logFile); 42 | ~CLogProcessor(void); 43 | 44 | //Start logging 45 | bool startProcess(const QString &program, const QStringList &arguments); 46 | bool startStdinProcessing(void); 47 | 48 | //Event processing 49 | int exec(void); 50 | 51 | //Types 52 | typedef enum 53 | { 54 | LOG_FORMAT_PLAIN = 0, 55 | LOG_FORMAT_VERBOSE = 1, 56 | LOG_FORMAT_HTML = 2 57 | } 58 | Format; 59 | 60 | //Setter methods 61 | void setCaptureStreams(const bool captureStdout, const bool captureStderr); 62 | void setSimplifyStrings(const bool simplify); 63 | void setFilterStrings(const QString ®ExpKeep, const QString ®ExpSkip); 64 | bool setTextCodecs(const char *inputCodec, const char *outputCodec); 65 | void setOutputFormat(const Format format); 66 | 67 | public slots: 68 | void forceQuit(const bool silent = false); 69 | 70 | 71 | private slots: 72 | void readFromStdout(void); 73 | void readFromStderr(void); 74 | void readFromStdinp(void); 75 | 76 | void processFinished(int exitCode); 77 | void readerFinished(void); 78 | 79 | private: 80 | void flushBuffers(void); 81 | void processData(const QByteArray &data, const int channel); 82 | void logString(const QString &data, const int channel); 83 | void initializeLog(void); 84 | void finishLog(void); 85 | 86 | static QString escape(const QString &text); 87 | 88 | QProcess *m_process; 89 | CInputReader *m_stdinReader; 90 | 91 | bool m_logStdout; 92 | bool m_logStderr; 93 | bool m_simplify; 94 | 95 | const bool m_logIsEmpty; 96 | 97 | Format m_logFormat; 98 | 99 | QTextDecoder *m_codecStdout; 100 | QTextDecoder *m_codecStderr; 101 | QTextDecoder *m_codecStdinp; 102 | 103 | QString m_bufferStdout; 104 | QString m_bufferStderr; 105 | QString m_bufferStdinp; 106 | 107 | QRegExp *m_regExpEOL; 108 | QRegExp *m_regExpSkip; 109 | QRegExp *m_regExpKeep; 110 | 111 | QTextStream *m_logFile; 112 | QEventLoop *m_eventLoop; 113 | 114 | bool m_logInitialized; 115 | bool m_logFinished; 116 | 117 | int m_exitCode; 118 | }; 119 | -------------------------------------------------------------------------------- /src/LoggingUtil.cpp: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // Logging Utility 3 | // Copyright (C) 2010-2013 LoRd_MuldeR 4 | // 5 | // This program is free software; you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation; either version 2 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along 16 | // with this program; if not, write to the Free Software Foundation, Inc., 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | // http://www.gnu.org/licenses/gpl-2.0.txt 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | //CRT 23 | #include 24 | #include 25 | #include 26 | 27 | //Stdlib 28 | #include 29 | 30 | //Windows 31 | #define WIN32_LEAN_AND_MEAN 32 | #include 33 | 34 | //Qt 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | //Internal 47 | #include "Version.h" 48 | #include "LogProcessor.h" 49 | 50 | //Version tags 51 | static const int VERSION_MAJOR = VER_LOGGER_MAJOR; 52 | static const int VERSION_MINOR = (10 * VER_LOGGER_MINOR_HI) + VER_LOGGER_MINOR_LO; 53 | 54 | //Parameters 55 | class parameters_t 56 | { 57 | public: 58 | bool printHelp; 59 | QString childProgram; 60 | QStringList childArgs; 61 | QString logFile; 62 | bool captureStdout; 63 | bool captureStderr; 64 | bool enableSimplify; 65 | bool appendLogFile; 66 | CLogProcessor::Format format; 67 | QString regExpKeep; 68 | QString regExpSkip; 69 | QString codecInp; 70 | QString codecOut; 71 | }; 72 | 73 | //Helper 74 | #define SAFE_DEL(X) do { if(X) { delete (X); X = NULL; } } while (0) 75 | #define QSTR2STR(X) ((X).isEmpty() ? NULL : (X).toLatin1().constData()) 76 | 77 | //Forward declarations 78 | static bool parseArguments(int argc, wchar_t* argv[], parameters_t *parameters); 79 | static void printUsage(void); 80 | static void printHeader(void); 81 | static QByteArray supportedCodecs(void); 82 | 83 | //Global variables 84 | QMutex giantLock; 85 | QCoreApplication *application = NULL; 86 | CLogProcessor *processor = NULL; 87 | 88 | //Const 89 | const char *STDIN_MARKER = "#STDIN#"; 90 | 91 | /* 92 | * The Main function 93 | */ 94 | static int logging_util_main(int argc, wchar_t* argv[]) 95 | { 96 | int dummy_argc = 1; 97 | char *dummy_argv[] = { "program.exe", NULL }; 98 | 99 | _setmode(_fileno(stdin ), _O_BINARY); 100 | _setmode(_fileno(stdout), _O_BINARY); 101 | _setmode(_fileno(stderr), _O_BINARY); 102 | 103 | //Check the Qt version 104 | if(_stricmp(qVersion(), QT_VERSION_STR)) 105 | { 106 | printHeader(); 107 | fprintf(stderr, "FATAL: Compiled with Qt v%s, but running on Qt v%s!\n\n", QT_VERSION_STR, qVersion()); 108 | return -1; 109 | } 110 | 111 | //Parse the CLI parameters 112 | parameters_t parameters; 113 | if(!parseArguments(argc, argv, ¶meters)) 114 | { 115 | return -1; 116 | } 117 | 118 | //Print help screen 119 | if(parameters.printHelp) 120 | { 121 | printUsage(); 122 | return 0; 123 | } 124 | 125 | //Does program file exist? 126 | if(parameters.childProgram.compare(STDIN_MARKER, Qt::CaseInsensitive)) 127 | { 128 | QFileInfo program(parameters.childProgram); 129 | 130 | //Check for existence 131 | if(!(program.exists() && program.isFile())) 132 | { 133 | printHeader(); 134 | fprintf(stderr, "ERROR: The specified program file does not exist!\n\n"); 135 | fprintf(stderr, "Path that could not be found:\n%s\n\n", QFileInfo(parameters.childProgram).absoluteFilePath().toUtf8().constData()); 136 | return -1; 137 | } 138 | 139 | //Make absoloute path 140 | parameters.childProgram = program.canonicalFilePath(); 141 | } 142 | 143 | //Open the log file 144 | QFile logFile(parameters.logFile); 145 | QIODevice::OpenMode openFlags = (parameters.appendLogFile) ? QIODevice::Append : (QIODevice::WriteOnly | QIODevice::Truncate); 146 | if(!logFile.open(openFlags)) 147 | { 148 | printHeader(); 149 | fprintf(stderr, "ERROR: Failed to open log file for writing!\n\n"); 150 | fprintf(stderr, "Path that failed to open is:\n%s\n\n", logFile.fileName().toUtf8().constData()); 151 | return -1; 152 | } 153 | 154 | //Create application 155 | application = new QCoreApplication(dummy_argc, dummy_argv); 156 | 157 | //Create processor 158 | QMutexLocker lock(&giantLock); 159 | processor = new CLogProcessor(logFile); 160 | lock.unlock(); 161 | 162 | //Setup parameters 163 | processor->setCaptureStreams(parameters.captureStdout, parameters.captureStderr); 164 | processor->setSimplifyStrings(parameters.enableSimplify); 165 | processor->setFilterStrings(parameters.regExpKeep, parameters.regExpSkip); 166 | processor->setOutputFormat(parameters.format); 167 | 168 | //Setup text encoding 169 | if(!processor->setTextCodecs(QSTR2STR(parameters.codecInp), QSTR2STR(parameters.codecOut))) 170 | { 171 | printHeader(); 172 | fprintf(stderr, "ERROR: The selected text Codec is invalid!\n\n"); 173 | fprintf(stderr, "Supported text codecs:\n%s\n\n", supportedCodecs().constData()); 174 | logFile.close(); 175 | delete processor; 176 | delete application; 177 | return -1; 178 | } 179 | 180 | //Try to start the child process (or STDIN reader) 181 | if(parameters.childProgram.compare(STDIN_MARKER, Qt::CaseInsensitive)) 182 | { 183 | if(!processor->startProcess(parameters.childProgram, parameters.childArgs)) 184 | { 185 | printHeader(); 186 | fprintf(stderr, "ERROR: The process failed to start!\n\n"); 187 | fprintf(stderr, "Command that failed is:\n%s\n\n", parameters.childProgram.toUtf8().constData()); 188 | logFile.close(); 189 | delete processor; 190 | delete application; 191 | return -1; 192 | } 193 | } 194 | else 195 | { 196 | if(!processor->startStdinProcessing()) 197 | { 198 | printHeader(); 199 | fprintf(stderr, "ERROR: The process failed to start!\n\n"); 200 | fprintf(stderr, "Command that failed is:\n%s\n\n", parameters.childProgram.toUtf8().constData()); 201 | logFile.close(); 202 | delete processor; 203 | delete application; 204 | return -1; 205 | } 206 | } 207 | 208 | //Now run event loop 209 | int retval = processor->exec(); 210 | 211 | //Clean up 212 | lock.relock(); 213 | SAFE_DEL(processor); 214 | SAFE_DEL(application); 215 | lock.unlock(); 216 | 217 | //Close log 218 | logFile.close(); 219 | 220 | return retval; 221 | } 222 | 223 | /* 224 | * Make sure there is one more argument 225 | */ 226 | #define CHECK_NEXT_ARGUMENT(LST, ARG) do \ 227 | { \ 228 | if((LST).isEmpty() || (!(LST).first().compare(OPTION_MARKER, Qt::CaseInsensitive))) \ 229 | { \ 230 | printHeader(); \ 231 | fprintf(stderr, "ERROR: Argument for option '%s' is missing!\n\n", (ARG)); \ 232 | fprintf(stderr, "Please type \"LoggingUtil.exe --help :\" for details...\n\n"); \ 233 | return false; \ 234 | } \ 235 | } \ 236 | while(0) 237 | 238 | /* 239 | * Parse the CLI args 240 | */ 241 | static bool parseArguments(int argc, wchar_t* argv[], parameters_t *parameters) 242 | { 243 | //Setup defaults 244 | parameters->printHelp = false; 245 | parameters->childProgram.clear(); 246 | parameters->childArgs.clear(); 247 | parameters->logFile.clear(); 248 | parameters->captureStdout = true; 249 | parameters->captureStderr = true; 250 | parameters->enableSimplify = true; 251 | parameters->appendLogFile = true; 252 | parameters->format = CLogProcessor::LOG_FORMAT_VERBOSE; 253 | parameters->regExpKeep.clear(); 254 | parameters->regExpSkip.clear(); 255 | parameters->codecInp.clear(); 256 | parameters->codecOut.clear(); 257 | 258 | //Make sure user has set parameters 259 | if(argc < 2) 260 | { 261 | parameters->printHelp = true; 262 | return true; 263 | } 264 | 265 | //Convert all parameters to QString's 266 | QStringList list; 267 | for(int i = 1; i < argc; i++) 268 | { 269 | list << QString::fromUtf16(reinterpret_cast(argv[i])).trimmed(); 270 | } 271 | 272 | const QString OPTION_MARKER = ":"; 273 | 274 | //Have logger options? 275 | bool bHaveOptions = false; 276 | for(QStringList::ConstIterator iter = list.constBegin(); iter != list.constEnd(); iter++) 277 | { 278 | if(!(*iter).compare(OPTION_MARKER, Qt::CaseInsensitive)) 279 | { 280 | bHaveOptions = true; 281 | break; 282 | } 283 | } 284 | 285 | //Help screen requested? 286 | if(bHaveOptions) 287 | { 288 | static const char *help[] = { "--help", "-help", "/?" }; 289 | 290 | for(QStringList::ConstIterator iter = list.constBegin(); iter != list.constEnd(); iter++) 291 | { 292 | if(!(*iter).compare(OPTION_MARKER, Qt::CaseInsensitive)) 293 | { 294 | break; 295 | } 296 | 297 | for(int i = 0; i < 3; i++) 298 | { 299 | if(!(*iter).compare(QString::fromLatin1(help[i]), Qt::CaseInsensitive)) 300 | { 301 | parameters->printHelp = true; 302 | return true; 303 | } 304 | } 305 | } 306 | } 307 | 308 | //Parse logger options 309 | while(bHaveOptions && (!list.isEmpty())) 310 | { 311 | const QString current = list.takeFirst().simplified(); 312 | 313 | //End of logger options? 314 | if(!current.compare(OPTION_MARKER, Qt::CaseInsensitive)) 315 | { 316 | break; 317 | } 318 | 319 | //Ignore alle empty strings 320 | if(current.isEmpty()) 321 | { 322 | continue; 323 | } 324 | 325 | //Parse parameters 326 | if(!current.compare("--logfile", Qt::CaseInsensitive)) 327 | { 328 | CHECK_NEXT_ARGUMENT(list, "--logfile"); 329 | parameters->logFile = list.takeFirst(); 330 | } 331 | else if(!current.compare("--only-stdout", Qt::CaseInsensitive)) 332 | { 333 | parameters->captureStdout = true; 334 | parameters->captureStderr = false; 335 | } 336 | else if(!current.compare("--only-stderr", Qt::CaseInsensitive)) 337 | { 338 | parameters->captureStdout = false; 339 | parameters->captureStderr = true; 340 | } 341 | else if(!current.compare("--no-simplify", Qt::CaseInsensitive)) 342 | { 343 | parameters->enableSimplify = false; 344 | } 345 | else if(!current.compare("--plain-output", Qt::CaseInsensitive)) 346 | { 347 | parameters->format = CLogProcessor::LOG_FORMAT_PLAIN; 348 | } 349 | else if(!current.compare("--html-output", Qt::CaseInsensitive)) 350 | { 351 | parameters->format = CLogProcessor::LOG_FORMAT_HTML; 352 | parameters->appendLogFile = false; 353 | } 354 | else if(!current.compare("--no-append", Qt::CaseInsensitive)) 355 | { 356 | parameters->appendLogFile = false; 357 | } 358 | else if(!current.compare("--regexp-keep", Qt::CaseInsensitive)) 359 | { 360 | CHECK_NEXT_ARGUMENT(list, "--regexp-keep"); 361 | parameters->regExpKeep = list.takeFirst(); 362 | } 363 | else if(!current.compare("--regexp-skip", Qt::CaseInsensitive)) 364 | { 365 | CHECK_NEXT_ARGUMENT(list, "--regexp-skip"); 366 | parameters->regExpSkip = list.takeFirst(); 367 | } 368 | else if(!current.compare("--codec-in", Qt::CaseInsensitive)) 369 | { 370 | CHECK_NEXT_ARGUMENT(list, "--codec-in"); 371 | parameters->codecInp = list.takeFirst(); 372 | } 373 | else if(!current.compare("--codec-out", Qt::CaseInsensitive)) 374 | { 375 | CHECK_NEXT_ARGUMENT(list, "--codec-out"); 376 | parameters->codecOut = list.takeFirst(); 377 | } 378 | else 379 | { 380 | printHeader(); 381 | fprintf(stderr, "ERROR: Option '%s' is unknown!\n\n", current.toLatin1().constData()); 382 | fprintf(stderr, "Please type \"LoggingUtil.exe --help :\" for details...\n\n"); \ 383 | return false; 384 | } 385 | } 386 | 387 | //Check child process program name 388 | if(list.isEmpty() || list.first().isEmpty()) 389 | { 390 | printHeader(); 391 | fprintf(stderr, "ERROR: Program to execute has not been specified!\n\n"); 392 | fprintf(stderr, "Please type \"LoggingUtil.exe --help :\" for details...\n\n"); \ 393 | return false; 394 | } 395 | 396 | //Set child process program name and parameters 397 | parameters->childProgram = list.takeFirst(); 398 | while(!list.isEmpty()) 399 | { 400 | parameters->childArgs << list.takeFirst(); 401 | } 402 | 403 | //Generate log file name 404 | if(parameters->logFile.isEmpty()) 405 | { 406 | const QString ext = (parameters->format == CLogProcessor::LOG_FORMAT_HTML) ? "htm" : "log"; 407 | if(parameters->childProgram.compare(STDIN_MARKER, Qt::CaseInsensitive)) 408 | { 409 | QFileInfo info(parameters->childProgram); 410 | QRegExp rx("[^a-zA-Z0-9_]"); 411 | parameters->logFile = QString("%1.%2.%3").arg(info.completeBaseName().replace(rx, "_"), QDateTime::currentDateTime().toString("yyyy-MM-dd"), ext); 412 | } 413 | else 414 | { 415 | parameters->logFile = QString("STDIN.%1.%2").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd"), ext); 416 | } 417 | } 418 | 419 | return true; 420 | } 421 | 422 | /* 423 | * Print the CLI header 424 | */ 425 | static void printHeader(void) 426 | { 427 | fprintf(stderr, "\nLogging Utility v%d.%02d, built %s %s (using Qt v%s)\n", VERSION_MAJOR, VERSION_MINOR, __DATE__, __TIME__, QT_VERSION_STR); 428 | fprintf(stderr, "Copyright (c) 2010-2013 LoRd_MuldeR . Some rights reserved.\n"); 429 | fprintf(stderr, "Please visit http://www.muldersoft.com/ for news and updates!\n\n"); 430 | fprintf(stderr, "This program is free software: you can redistribute it and/or modify\n"); 431 | fprintf(stderr, "it under the terms of the GNU General Public License .\n"); 432 | fprintf(stderr, "Note that this program is distributed with ABSOLUTELY NO WARRANTY.\n\n"); 433 | } 434 | 435 | /* 436 | * Print the CLI help 437 | */ 438 | static void printUsage(void) 439 | { 440 | printHeader(); 441 | fprintf(stderr, "Usage Mode #1:\n"); 442 | fprintf(stderr, " LoggingUtil.exe SomeProgram.exe [program parameters]\n"); 443 | fprintf(stderr, " LoggingUtil.exe [logging options] : SomeProgram.exe [program parameters]\n"); 444 | fprintf(stderr, "\n"); 445 | fprintf(stderr, "Usage Mode #2:\n"); 446 | fprintf(stderr, " SomeProgram.exe [parameters] | LoggingUtil.exe [options] : #STDIN#\n"); 447 | fprintf(stderr, " SomeProgram.exe [parameters] 2>&1 | LoggingUtil.exe [options] : #STDIN#\n"); 448 | fprintf(stderr, "\n"); 449 | fprintf(stderr, "Logging Options:\n"); 450 | fprintf(stderr, " --logfile Specifies the output log file (appends if file exists)\n"); 451 | fprintf(stderr, " --only-stdout Capture only output from STDOUT, ignores STDERR\n"); 452 | fprintf(stderr, " --only-stderr Capture only output from STDERR, ignores STDOUT\n"); 453 | fprintf(stderr, " --no-simplify Do NOT simplify/trimm the logged strings (default: on)\n"); 454 | fprintf(stderr, " --no-append Do NOT append, i.e. any existing log content is lost\n"); 455 | fprintf(stderr, " --plain-output Create less verbose logging output\n"); 456 | fprintf(stderr, " --html-output Create HTML logging output, implies NO append\n"); 457 | fprintf(stderr, " --regexp-keep Keep ONLY strings that match the given RegExp\n"); 458 | fprintf(stderr, " --regexp-skip Skip all the strings that match the given RegExp\n"); 459 | fprintf(stderr, " --codec-in Setup the input text encoding (default: \"UTF-8\")\n"); 460 | fprintf(stderr, " --codec-out Setup the output text encoding (default: \"UTF-8\")\n"); 461 | fprintf(stderr, "\n"); 462 | fprintf(stderr, "Examples:\n"); 463 | fprintf(stderr, " LoggingUtil.exe --logfile x264_log.txt : x264.exe -o output.mkv input.avs\n"); 464 | fprintf(stderr, " x264.exe -o output.mkv input.avs 2>&1 | LoggingUtil.exe : #STDIN#\n"); 465 | fprintf(stderr, "\n"); 466 | } 467 | 468 | /* 469 | * Get list of all supported Codec names 470 | */ 471 | static QByteArray supportedCodecs(void) 472 | { 473 | QStringList list; 474 | QList codecs = QTextCodec::availableCodecs(); 475 | foreach(const QByteArray &c, codecs) list << QString::fromLatin1(c); 476 | return list.join(", ").toLatin1(); 477 | } 478 | 479 | /* 480 | * Ctrl+C handler routine 481 | */ 482 | static BOOL WINAPI ctrlHandlerRoutine(DWORD dwCtrlType) 483 | { 484 | QMutexLocker lock(&giantLock); 485 | 486 | if(processor) 487 | { 488 | QTimer::singleShot(0, processor, SLOT(forceQuit())); 489 | } 490 | 491 | return TRUE; 492 | } 493 | 494 | /* 495 | * Crash handler routine 496 | */ 497 | #pragma intrinsic(_InterlockedExchange) 498 | static LONG WINAPI exceptionHandlerRoutine(struct _EXCEPTION_POINTERS *ExceptionInfo) 499 | { 500 | static volatile long bFatalFlag = 0L; 501 | 502 | if(_InterlockedExchange(&bFatalFlag, 1L) == 0L) 503 | { 504 | __try 505 | { 506 | fprintf(stderr, "\n\nFATAL ERROR: Oups, some slunks have sneaked into your system and broke it :-(\n\n"); 507 | fflush(stderr); 508 | } 509 | __except(1) 510 | { 511 | TerminateProcess(GetCurrentProcess(), DWORD(-1)); 512 | return EXCEPTION_EXECUTE_HANDLER; 513 | } 514 | } 515 | 516 | TerminateProcess(GetCurrentProcess(), DWORD(-1)); 517 | return EXCEPTION_EXECUTE_HANDLER; 518 | } 519 | 520 | /* 521 | * Application entry point 522 | */ 523 | int wmain(int argc, wchar_t* argv[]) 524 | { 525 | __try 526 | { 527 | SetUnhandledExceptionFilter(exceptionHandlerRoutine); 528 | SetConsoleCtrlHandler(ctrlHandlerRoutine, TRUE); 529 | logging_util_main(argc, argv); 530 | } 531 | __except(1) 532 | { 533 | exceptionHandlerRoutine(NULL); 534 | return -1; 535 | } 536 | } 537 | -------------------------------------------------------------------------------- /src/Version.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // Logging Utility 3 | // Copyright (C) 2010-2013 LoRd_MuldeR 4 | // 5 | // This program is free software; you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation; either version 2 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along 16 | // with this program; if not, write to the Free Software Foundation, Inc., 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | // 19 | // http://www.gnu.org/licenses/gpl-2.0.txt 20 | /////////////////////////////////////////////////////////////////////////////// 21 | 22 | #define VER_LOGGER_MAJOR 2 23 | #define VER_LOGGER_MINOR_HI 0 24 | #define VER_LOGGER_MINOR_LO 3 25 | --------------------------------------------------------------------------------