Compare commits

...

734 Commits

Author SHA1 Message Date
Kjell Hedström
38dbddc707
Botantony/cmake fix (#548)
* Fix build for CMake >= 4.0.0

Signed-off-by: botantony <antonsm21@gmail.com>

* updating minor version for hotfix
* removed accidental inclusion from way back

---------

Signed-off-by: botantony <antonsm21@gmail.com>
Co-authored-by: botantony <antonsm21@gmail.com>
2025-06-10 08:30:15 -06:00
ellipsis-dev[bot]
14db492d9d
[Ellipsis] chore: update CMake minimum version to 3.5 (#546)
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-06-09 09:43:07 -06:00
Kjell Hedström
cec84ba592
Update README.md (#543) with code scanning insights. 2025-03-03 17:10:46 -07:00
ablangy
96023dbffd
Issue #541 Linux: access to siginfo_t (#542)
By using some informations located in siginfo_t for tracing,
it remain accessible to be inspected by debugger even if the
code compiled with optimisation flags (typically -O2).
2025-01-17 14:43:47 -07:00
Kjell Hedström
1dc74351ff
dummy test to validate updated ci (#539)
disable ci/action ubuntu as it's redundant with the matrix runs
2024-08-27 22:42:30 -06:00
Kjell Hedström
5a4a1094d8
Remove redundant CI tests (appveyor, circleci) and rely only on github actions matrix windows/macos/ubuntu (#538)
* Update README.md
* Delete appveyor.yml
* Delete .circleci/config.yml
2024-08-27 21:52:55 -06:00
Kjell Hedström
37cfffce91
Update Build.cmake (#536) 2024-08-27 21:42:27 -06:00
Kjell Hedström
1a1d2a12ea
Update ctest.yml 2024-08-27 21:23:51 -06:00
Kjell Hedström
943487f29a
Update ctest.yml (#537) 2024-08-27 21:15:19 -06:00
Kjell Hedström
c1dd801e42
Update mkdocs.yml - removed test trigger (#530) 2024-05-23 19:05:35 -06:00
Kjell
e3d85a58c2 squashed many small commit messages for documentation and matrix/ci improvements 2024-05-23 13:18:22 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
095ed1cdf6
Update README.md 2024-03-22 06:18:55 -06:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
850eb0dd07
Update README.md 2024-03-22 06:18:34 -06:00
Kjell Hedstrom
ff8e284326 fixed visual studio debug 2024-02-19 11:49:34 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
326fef95ac
dummy pr to check CI (#517)
Updated checkout version to v3 to move to node20 (node16 end of life)
* updated to v3
2024-02-05 10:32:06 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
45ca1f6b6e
Update API.md 2024-02-03 15:39:46 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
9a8c0fc854
Windows path for gitactions? (#516)
* Update ctest.yml and add Windows to CI pipeline gitactions.
2024-02-03 15:37:06 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
f2b9f9b62c
Update README.md 2024-02-03 15:29:23 -07:00
Kjell Hedstrom
540f2711af .DS store gone 2023-12-07 11:54:20 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
4c1194720a
adding default container extensions (#514) 2023-12-06 20:23:58 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
5980182db0
Versioning (#515)
* making sure that git checkout of tags, doesn't get incrementing numbers when master gets more commits
2023-12-06 20:14:22 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
626191a62d
Mostly a refactor of tests (#513) 2023-12-05 23:33:03 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
055f5e4d21
updated docs (#512)
* updated docs for API and added sequence diagrams.
2023-12-05 21:57:13 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
bba825815a
refactor fatal call (#511)
* refactor fatal handling
2023-12-05 21:04:01 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
d70ae50ee3
gitignore (#510)
* gitingore
2023-12-05 20:02:08 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
f26b058d16
Update PULL_REQUEST_TEMPLATE.md 2023-11-30 16:22:17 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
cf91227966
adding consistent and easy formatting (#508)
*  clang format configuration file replaces sublime Astyleformatter
* instructions added to pull request template
* code base re-formatted to be consistent throughout.
2023-11-30 16:17:45 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
0708f5aeb4
Update README.md 2023-11-28 08:37:15 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
59fdb4e2c8
Update README.md 2023-11-27 21:08:21 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
c2661853d0
Codespaces tryout (#507)
* adding example vs code launch file
2023-11-27 21:07:23 -07:00
Kjell Hedström - seeking Senior Engineering roles as well as contract opportunities
c3a46e6043
trying out codespaces (#506)
* trying out codespaces
2023-11-27 19:13:07 -07:00
Kjell Hedström - looking for a challenge contract or full-time
f1036e62ac
Update README.md (#505) 2023-11-25 14:48:09 -07:00
Kjell Hedström - looking for a challenge contract or full-time
c41c82e032
Update README.md (#504) 2023-11-25 11:12:58 -07:00
Sean -Kjell- Hedström
63f3272703
clarify c++ version support (#502) 2023-11-12 14:42:52 -07:00
Kjell Hedström
b24d4a4523
update doc for default flush (#499) 2023-08-17 16:55:24 -06:00
CryptoManiac
7817fd3a94
Update loglevels.hpp (#496) 2023-05-20 07:16:32 -06:00
Dmitry Tsarevich
bad9c58e60
Fix found by PVS-Studio issues (#490)
Small changes, essentially cleanup, with no actual code logic change. 
* Ensure symbol_buffer aligned same as SYMBOL_INFO
* Use constexpr for compile-time constant
* Use = default for ctor bodies to allow compiler optimize them
* Pass string by reference to prevent copying, other smaller types we can  avoid passing by reference as the type is cheaper to copy.
2023-05-15 07:59:44 -06:00
SzGaa
cc0fb7c1ea
constexpr LEVELS for easier custom level usage (#483)
Usage of C++20's new constexpr functionalities for easier usage of custom LEVELS!

Modified:
* With C++20 LEVELS's constructor can have a constexpr specifier
* const LEVELS can be replaced to be constexpr's instead
2023-05-03 21:50:48 -06:00
Kjell Hedström
b249fb6c6c
Update appveyor.yml to use Visual Studio 2022 (17) (#487) 2023-04-19 22:39:32 -06:00
GergoTot
5323480780
Avoid pending of containerized applications in case of aborting (#481)
Improvement for Docker run C++ applications with g3log 

* This addresses the case when a PID1 process crashes and the signal handling, goes into multiple or even infinite loops due to subsequent crashes. The PR makes sure to restore all signal handlers to the original signal handling after the first crash is detected. For
2023-03-07 17:30:58 -07:00
Kjell Hedström
4f1224b9d5
Fix filesink drop messages improved (#479)
* Fix FileSink dropping messages introduced by 'optionable buffer to x messages' feature
Commit 6c6122fafc79e92fc94a851b3ff83f87e8b80398 introduced a bug where 99 out of 100 logs were actually dumped

* Updated unit tests to trigger sink flush bug
---------

Co-authored-by: Ryan Ammoury <ryan.ammoury@squadrone-system.com>
2023-02-20 06:16:34 -07:00
Kjell Hedström
43f5eddcdd
updated version to 2.2 (#476) 2023-02-04 04:45:29 -07:00
Grzegorz Głowacki
09317e3573
Parse OSX stack dump format in order to demangle it correctly (#473)
* Parse OSX format  mangled stack trace correctly
Co-authored-by: Grzegorz Glowacki <grzegorz.glowacki@avid.com>
2023-02-04 04:40:56 -07:00
Kjell Hedström
16bb6f7e04
force check of stackdump (#475) 2023-02-04 04:37:13 -07:00
Kjell Hedström
6c6122fafc
optionable to buffer x messages before writing to file, default to 100 which will really boost performance (#471) 2022-12-08 22:08:28 -07:00
Kjell Hedström
dbd3d74a39
__SIGFUNC__ no longer default for Windows. __PRETTY__FUNCTION no longer default for gcc/clang (#470)
* __SIGFUNC__ no longer default for Windows, It has to be explicitly picked through CMAKE option
* __PRETTY_FUNCTION__ no longer default for gcc/clang, It has to be explicitly picked through CMAKE option
2022-11-29 22:16:35 -07:00
Kjell Hedström
881e6da439
__func__ doesn't make sense (#469)
__func__ doesn't make sense since we have left c++11 in the dust
2022-11-29 09:00:46 -07:00
Kjell Hedström
6f6da0ed2a
Update CMakeLists.txt 2022-11-10 09:34:52 -07:00
ablangy
0c09462e4d
exitWithDefaultSignalHandler() should block until signal handler returns (#464)
raise() system call does the same as kill() system call in a
single-threaded program.
In a multithreaded program, it does the same as pthread_kill() which
ensures that if the signal causes a handler to be called, raise() will
return only after the signal handler has returned.
2022-11-10 09:34:07 -07:00
Kjell Hedström
21195751be
corrected version 2022-11-08 09:31:37 -07:00
bmagistro
ed91b899f0
Resolve noexcept warnings on lambdas (#463)
When running with additional warnings enabled, a couple lambdas produce
a warning that they should be declared with noexcept. This addresses the
lambdas that had been identified while building.

Signed-off-by: Ben Magistro <koncept1@gmail.com>
2022-09-14 14:04:34 -06:00
神楽坂帕琪
5adecb5ad9
Fix typo in README (#460) 2022-08-17 01:04:44 -06:00
Reece Watson
a0c7e5e0e1
Fix typo in README.md (#458) 2022-07-29 06:38:21 -06:00
zjeffer
1ee2cd0de6
fix(cmake): fixes #413 (#457) 2022-06-11 06:17:32 -06:00
Kjell Hedström
7758aa7913
Update README.md (#456)
* Update README.md and PULL_REQUEST_TEMPLATE.md
2022-05-29 04:24:55 -06:00
Kjell Hedström. We are hiring @ Ganaz
ccf6b97054
Mkdocs (#455)
* adding header/footer navigation links
2022-05-28 23:37:48 -06:00
Kjell Hedström. We are hiring @ Ganaz
429047e815
Mkdocs (#453)
* adding back README
2022-05-28 23:29:03 -06:00
Kjell Hedström. We are hiring @ Ganaz
eaf3f7b312
Create .ciignore (#454) 2022-05-28 23:24:45 -06:00
Kjell Hedström. We are hiring @ Ganaz
359ca69774
Set theme jekyll-theme-cayman 2022-05-28 22:27:35 -06:00
Kjell Hedström. We are hiring @ Ganaz
f370e32346
Update mkdocs.yml 2022-05-28 22:11:11 -06:00
Kjell Hedström. We are hiring @ Ganaz
4ade209945
Update mkdocs.yml 2022-05-28 22:02:25 -06:00
Kjell Hedström. We are hiring @ Ganaz
eb82e25958
Rename publish_docs.yml to docs.yml 2022-05-28 22:00:40 -06:00
Kjell Hedström. We are hiring @ Ganaz
f4fa1cad94
Update index.md 2022-05-28 21:50:00 -06:00
Kjell Hedström. We are hiring @ Ganaz
808b787b60
Mkdocs (#452)
* removed obseolted README.mkd
2022-05-28 21:45:59 -06:00
Kjell Hedström. We are hiring @ Ganaz
fec09b2bba
Mkdocs (#451)
* updating for mkdocs generation
* updated look
2022-05-28 21:38:45 -06:00
Kjell Hedström. We are hiring @ Ganaz
0e3fef50bb
Update publish_docs.yml 2022-05-28 21:36:58 -06:00
Kjell Hedström. We are hiring @ Ganaz
f72f47e533
Update publish_docs.yml 2022-05-28 21:23:51 -06:00
Kjell Hedstrom
fc2af1ddc2 updating for mkdocs generation 2022-05-28 21:13:54 -06:00
Kjell Hedstrom
c52de9e1cf updating for mkdocs generation 2022-05-28 21:13:54 -06:00
Kjell Hedström. We are hiring @ Ganaz
83a1ce24d9 Update index.md 2022-05-24 17:52:03 -06:00
Kjell Hedström. We are hiring @ Ganaz
6c956e5fc8
Update publish_docs.yml 2022-05-24 17:51:24 -06:00
Kjell Hedström. We are hiring @ Ganaz
d057e0a9d5 Update mkdocs.yml 2022-05-24 17:43:32 -06:00
Kjell Hedström. We are hiring @ Ganaz
a1efe3b4a4 Update index.md 2022-05-24 17:39:35 -06:00
Kjell Hedström. We are hiring @ Ganaz
9190b37706 Update API.md 2022-05-24 17:34:39 -06:00
Kjell Hedström. We are hiring @ Ganaz
f9a19c5fe7
Update buildAndRunTests.yml 2022-05-24 17:29:47 -06:00
Kjell Hedström. We are hiring @ Ganaz
d51fe70f96
Update codeql-analysis.yml 2022-05-24 17:29:28 -06:00
Kjell Hedström. We are hiring @ Ganaz
20100be78e
Update ctest.yml 2022-05-24 17:29:00 -06:00
Kjell Hedström. We are hiring @ Ganaz
4584d1ed10
Create .ciignore 2022-05-24 17:15:18 -06:00
Kjell Hedström. We are hiring @ Ganaz
4de1e9f5cf
Create API.md 2022-05-24 17:12:08 -06:00
Kjell Hedström. We are hiring @ Ganaz
9bdd710907
Update mkdocs.yml 2022-05-24 17:11:20 -06:00
Kjell Hedström. We are hiring @ Ganaz
cf8ef87c95
Update publish_docs.yml 2022-05-24 17:03:53 -06:00
Kjell Hedström. We are hiring @ Ganaz
9119a63062
test file to be removed 2022-05-24 14:22:54 -06:00
Kjell Hedström. We are hiring @ Ganaz
e48d46332d
Update publish_docs.yml 2022-05-24 14:21:05 -06:00
Kjell Hedström. We are hiring @ Ganaz
5b114c4f39
Update ctest.yml 2022-05-24 14:19:27 -06:00
Kjell Hedström. We are hiring @ Ganaz
8afd63dd86
Update buildAndRunTests.yml 2022-05-24 14:18:11 -06:00
Kjell Hedström. We are hiring @ Ganaz
9c71dfd783
Update ctest.yml 2022-05-24 14:16:31 -06:00
Kjell Hedström. We are hiring @ Ganaz
0bfff72ea2
Update ctest.yml 2022-05-23 17:44:56 -06:00
Kjell Hedström. We are hiring @ Ganaz
b3b75bfc43
Update buildAndRunTests.yml 2022-05-23 17:44:39 -06:00
Kjell Hedström. We are hiring @ Ganaz
4c3b65e631
Update ctest.yml 2022-05-23 17:43:29 -06:00
Kjell Hedström. We are hiring @ Ganaz
4175efea31
Update buildAndRunTests.yml 2022-05-23 17:42:39 -06:00
Kjell Hedström. We are hiring @ Ganaz
5cde8ed2ce
Update buildAndRunTests.yml 2022-05-23 17:41:51 -06:00
Kjell Hedström. We are hiring @ Ganaz
512be84bcb
Update publish_docs.yml 2022-05-23 17:30:25 -06:00
Kjell Hedström. We are hiring @ Ganaz
e79979767d
Rename docs/mkdocs.yml to mkdocs.yml 2022-05-23 17:29:41 -06:00
Kjell Hedström. We are hiring @ Ganaz
c5052998e3 Create index.md 2022-05-23 17:23:42 -06:00
Kjell Hedström. We are hiring @ Ganaz
fd47f6d731 Update mkdocs.yml 2022-05-23 17:23:42 -06:00
Kjell Hedström. We are hiring @ Ganaz
79ac87a7ec Create mkdocs.yml 2022-05-23 17:23:42 -06:00
Kjell Hedström. We are hiring @ Ganaz
f6394711e4 Update publish_docs.yml 2022-05-23 17:23:42 -06:00
Kjell Hedström. We are hiring @ Ganaz
1e82c5c957 Create publish_docs.yml
Example from: https://github.com/mhausenblas/mkdocs-template and https://github.com/marketplace/actions/deploy-mkdocs
2022-05-23 17:23:42 -06:00
Kjell Hedström. We are hiring @ Ganaz
485bf57fa8 Readme improvement 2022-04-28 23:14:19 -06:00
Kjell Hedström. We are hiring @ Ganaz
52af38396f
Update PULL_REQUEST_TEMPLATE.md (#440)
* Update PULL_REQUEST_TEMPLATE.md so it's easier to understand what a decent PR should look like
2022-03-19 00:43:35 -06:00
Kjell Hedström. We are hiring @ Ganaz
234b4ed70f
Update cmake.yml (#437)
* Renamed ci action files 
* added matrix setup for runs with both macos-latest and ubuntu-latest.
2022-03-08 20:42:02 -07:00
Kjell Hedström. We are hiring @ Ganaz
4fa7a72953
Updated CI configurations and README that explained them (#436)
* Update config.yml
* Update README.markdown
2022-03-07 21:44:22 -07:00
Kjell Hedström. We are hiring @ Ganaz
cebe73492f
Update cpp.yml 2022-03-07 20:47:15 -07:00
Kjell Hedström. We are hiring @ Ganaz
54c5c0110a
Update cpp.yml 2022-03-07 20:46:22 -07:00
Kjell Hedström. We are hiring @ Ganaz
de706a905b
Update cmake.yml 2022-03-07 20:44:29 -07:00
Kjell Hedström. We are hiring @ Ganaz
e29226bd58
Delete .travis.yml (#435) 2022-03-07 19:51:10 -07:00
Kjell Hedström. We are hiring @ Ganaz
a248f6a930
dummy circle-ci (#434)
* Create config.yml

* Updated config.yml
2022-03-07 19:20:19 -07:00
Kjell Hedström. We are hiring @ Ganaz
22f8d8cb99
Create cpp.yml 2022-03-07 18:07:42 -07:00
DlubalSmidJaroslav
a7192f2b1c
Fixes #428: memory leak in g3::internal::createLogFile (#430)
Co-authored-by: Jaroslav Smid <smidjar2.reg@email.cz>
2022-01-10 20:49:59 -07:00
landwehrj
9bb36eb7e5
Fix pretty function magic constant overwriting (#424)
* Fix bug with __PRETTY_FUNCTION__ being always overwritten.

* Fix unit test to reflect new pretty function.
2021-12-19 20:45:12 -07:00
Szekely Gyorgy
c51128f051
Unblock faulting thread signal handler after log flush is complete (#419) 2021-11-22 08:39:53 -07:00
Kjell Hedström : Engineering Leadership
9009e109e9
update gtest zip URL (#417) 2021-11-16 10:11:37 -07:00
Kjell Hedström : Engineering Leadership
df1fd3a5c2 Update issue templates 2021-07-07 16:11:36 -06:00
Kjell Hedström : Engineering Leadership
68aff4dabd Update issue templates 2021-07-07 16:10:21 -06:00
Kjell Hedström : Engineering Leadership
8dcda0ed69
Create CODE_OF_CONDUCT.md (#411) 2021-07-07 15:55:50 -06:00
Kjell Hedström : Engineering Leadership
53cb214a6d
Update README.markdown 2021-07-07 15:55:28 -06:00
Kjell Hedström : Engineering Leadership
d56589e649 Update issue templates 2021-07-07 15:34:59 -06:00
Kjell Hedström : Engineering Leadership
3d08371fc6
Create CONTRIBUTING.md 2021-07-07 15:30:43 -06:00
Kjell Hedström : Engineering Leadership
b5d37b2953
Update cmake.yml 2021-04-08 22:21:02 -06:00
Kjell Hedström : Engineering Leadership
cc6582ab99
Update cmake.yml 2021-04-08 22:17:37 -06:00
Kjell Hedström : Engineering Leadership
afaec74e4a
Update cmake.yml 2021-04-08 22:09:00 -06:00
Kjell Hedström : Engineering Leadership
f75c65af2b
Create cmake.yml 2021-04-08 21:53:46 -06:00
Kjell Hedström : Engineering Leadership
95291b5190
fix version (#404) 2021-04-08 21:44:33 -06:00
Shachar Shemesh
c769b76715
Make SONAME less volatile (#402) 2021-04-08 21:29:40 -06:00
Kjell Hedström : Engineering Leadership
0a5a962679
Create codeql-analysis.yml 2021-04-08 21:28:14 -06:00
Kjell Hedström : Engineering Leadership
663050dc52
release version and cmake coded version sync 2021-04-08 21:13:18 -06:00
Chad Engler
d3f2d11ae6
Fix ARM compilation for windows. (#401) 2021-04-07 21:33:40 -06:00
lukeocamden
61f3f6e3db
Avoid copying LOGLEVELS for g3::logLevel call (#399)
* Avoid copy-constructing LEVELS for logLevel call
2021-01-26 12:49:10 -07:00
FriendlyFire
e28f559d32
C++20 compatability -- std::result_of with std::invoke_result (#392)
* Replaced result_of with invoke_result_t.
* Fixed a few compile errors and updated CMakeLists.
* Updated Cloud CI
2020-12-16 06:51:26 -07:00
Alvin
2fca06ff6d
Fix compiler warnings and condition check improvements (#390)
* fix compiler warnings

- loglevels.cpp - warns about double return if dynamic logging is on

- crash handler_unix.cpp - warns about unused variable
2020-11-23 21:23:13 -07:00
Alvin
c0ae589024
Alvin/minor fixes and improvements (#389)
* Fix typos
* Fix build for MinGW
- MinGW g++ doesn't recoganize `-rdynamic`
2020-11-17 20:40:26 -07:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
f1eff42b91
Update README.markdown 2020-08-08 08:40:17 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
9c6879226b
Update README.markdown 2020-08-07 23:10:58 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
3e1534eb81
Update API.markdown 2020-08-07 10:48:51 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
e32cee6c01
Update API.markdown 2020-08-07 10:48:07 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
dd4bb0f62c
Update API.markdown 2020-08-07 10:45:29 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
a4abb8b521
Update loglevels.hpp 2020-08-07 10:22:18 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
c2b1ff6475
Update loglevels.hpp 2020-08-05 12:30:09 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
e55c270753
Update loglevels.hpp 2020-08-05 12:28:17 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
b93e96ebf7
Update loglevels.hpp 2020-08-05 12:27:05 -06:00
Tian Xiao
5dd714b626
Fix some minor errors in API doc (#378)
* Typo in API doc

`SIGILL` and `SIGSEGV` were duplicated

* Fix the link to logrotate

Co-authored-by: Tian Xiao <tian.xiao@antelopetechnology.com>
2020-08-05 04:59:39 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
83737bbb8f
cpack version number (#376)
* cpack version number. Build number must be set since it's used by CPACK
2020-07-09 07:33:25 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
69a0be4c9c
play/tryout: It is confusing to name the target g3logger. KISS --> g3log (#372)
* It is confusing to name the target g3logger. KISS --> g3log. This MIGHT break installations for some but it's a needed correction. 

* Updated version number to 2.1.x
2020-07-08 22:42:55 -06:00
shiyuge
8e79dd6554
bug fix: vsnprintf_s return value 0 isn't error (#373)
Conforming with vsnprintf_s
2020-07-06 21:21:28 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
cdceb28deb
Update logworker.hpp (#369) 2020-06-29 11:58:01 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
a5f0158abd
speed up build (#367) by downloading gtest zip and avoiding cloning 2020-06-28 07:54:53 -06:00
shiyuge
e639f6d800
fix typo in logworker.hpp (#365) 2020-06-24 07:31:26 -06:00
shiyuge
2206cea309
fix typo in shared_queue.hpp exampel -> example (#363) 2020-06-23 06:53:33 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
5ef196eed5
Manual addition of sink removal functionality from C++11 branch (#361)
* Added sink removal
* improved build script
2020-06-19 13:49:30 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
e0e03ed105
Update PULL_REQUEST_TEMPLATE.md 2020-06-19 13:48:32 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
a67711a2df
Update PULL_REQUEST_TEMPLATE.md 2020-06-19 13:45:39 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
f9005d13bf
Update PULL_REQUEST_TEMPLATE.md 2020-06-19 13:36:48 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
7f3159e17f
Pull request template is improved 2020-06-19 12:02:48 -06:00
xgdgsc
6d0eb32ddb
dead link ,header name, format (#359) 2020-06-19 07:53:24 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
e21f93944e
Update README.markdown 2020-06-06 16:40:36 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
f9ac8f5e08
improved documentation (#358) 2020-06-06 16:39:27 -06:00
Murat Kilivan
68f3b174d9
Use CMake to download GoogleTest as part of build (#355)
Having GoogleTest source in the project means we are likely using a stale version of test. This change is to use CMake to download GoogleTest as part of the build's configuration step.
2020-06-03 15:37:46 -06:00
Murat Kilivan
639bfd7452
Use the correct namespace to call shutDownLogging() (#353)
This commit is to align the example source code in README with the source code.
2020-05-31 14:50:15 -06:00
Roman Popov
751330bb41
Allow throwing from exit handler (#349)
For example for unit testing purposes we may want to replace SIGABRT with
throwing an exception, so that unit tests for CHECK()s can be written.
2020-05-08 20:13:25 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
aab25a4091
one more comment fix 2020-05-08 14:33:50 -06:00
Kjell Hedström : Available for new Engineering Leadership and Engineering Opportunities
62162e8613
updated code comments since SIGABRT is used with default fatal handler instead of a throw 2020-05-08 14:30:52 -06:00
Kjell Hedström
6810f060f6
update travis, don't bog down the log file (#340) 2020-04-11 15:07:40 -06:00
Kjell Hedström
8dbd784922 Update issue templates 2020-04-02 21:32:39 -06:00
Kjell Hedström
960d48d726 Update issue templates 2020-04-02 21:31:28 -06:00
JoelStienlet
4000c5c899
remove std::move in return : std::future can only be moved anyway (#336)
Co-authored-by: Joel Stienlet <stienlet@localhost.localdomain>
2020-03-06 07:55:36 -07:00
Nicholas Lederer
9fb3e61e89
fix issue with stacktrace_windows not allocating sufficient memory for SYMBOL_INFO struct (#334) 2020-02-25 07:15:09 -07:00
bmagistro
3ffc36a3a2
add option to disable installing g3log for project embedding (#333) 2020-02-14 15:24:48 -07:00
Kjell Hedström
3a905ed83d
Update README.markdown 2019-12-16 15:43:32 -07:00
myd7349
29fb209b08 Update README.markdown (#329) 2019-12-14 06:51:10 -07:00
Jean-Charles Quillet
9b5527d773 Set link to local files as relative (#328) 2019-11-20 10:30:02 -07:00
Paul Smith
f149179178 Ensure LOG* and CHECK* macros are statement-safe (#320)
The LOG and LOGF macros had been modified to be statement-safe, but the
LOG_IF, CHECK, LOGF_IF, CHECKF, and CHECK_F macros were all still
unsafe in face of code where single-statement blocks were not enclosed
in {}.

For example code like this:

  if (!foobar)
      CHECKF(goodness, "badness detected!");
  else
      handle_foobar(foobar);

would fail in subtle and possibly dangerous ways.

Fix this by combining multiple if-statements into a single conditional
and inverting the conditions, then adding an empty then-block and moving
the log statement to the else-block.
2019-07-28 16:07:16 -06:00
myd7349
5cb5371e0e Fix CMake interface include directories (#321) 2019-07-28 15:55:57 -06:00
myd7349
376c417ad1 Improve CMake module file (#312)
* Improve CMake module file
* Fix packaging on Win32
* appveyor: Test install and package target
* Travis-CI: Test install and package target
* Update documentation for working with CMake
* Simplify g3loggerConfig.cmake
* Add Doc Prerequisites section
2019-05-13 22:42:15 -06:00
Kjell Hedström
9aecd55051
Update README.markdown (#316) 2019-05-02 15:32:13 -06:00
mobileben
9c5e7f3bcb #309 properly pass through ENABLE_FATAL_SIGNALHANDLING for the various iOS slices (#310) 2019-03-22 17:12:23 -06:00
mobileben
bc358e7436 Add arm64e support (#307) 2019-03-14 22:10:58 -06:00
Kjell Hedström
cb4a94da7d
Cloud CI: updated for travis OSX + Ubuntu. Simplified setup (#301)
* updated for travis OSX + Ubuntu. Simplified setup

* more robust script for test
2019-02-18 21:01:30 -07:00
Benjamin Beichler
e8a07f25b5 Fix several CMake Issues (#294)
* Restructure Build.cmake to use "modern" Cmake

Since it is deprecated to modify the global compiler flags and similar options, the Build.cmake is converted to use only per target operations.

Additionally, the checks for backtrace and Pthread lib is converted to use the in cmake included functions. Also the check for the cxa_demangle function should be more robust now.

* fixed option for performance test

* use CMAKE_CURRENT_SOURCE_DIR in git cmd-lines to get current version, for better integration as cmake subdirectory

* bump required cmake version to 3.2 and use target_compile_feature to fix OSX compiler recognition and c++14 compiler flags
2019-02-18 12:43:04 -07:00
Michael Gratton
e08e933f3e Create an IMPORT target in g3loggerConfig.cmake (#299) 2019-02-18 10:52:02 -07:00
Kjell Hedström
1eb0408347
Simplified travis setup with ubuntu xenail (#300)
* test in progress

* improved PR instructions

* revert back
2019-02-18 10:50:37 -07:00
Kjell Hedström
e7b70f3138
Update README.markdown 2019-02-16 16:02:12 -07:00
Aleksey Dobrunov
1a010de2f6 Mingw parse error (#293)
* fix 'Failure to successfully parse the message' on mingw

* removed redundant checks
2019-01-15 12:27:53 -07:00
Aleksey Dobrunov
502bf318a4 add option G3_SHARED_RUNTIME (#292) 2019-01-15 12:25:51 -07:00
Christos
cf36852238 Wrap gnu::format around #if to avoid msvc warnings (#291)
* Wrap gnu::format around #if to avoid msvc warnings

* Fix compilation issue
2018-12-17 20:08:02 -07:00
Nils Gladitz
048b23d38c Use C++11 generic attribute syntax to avoid issue #282 (#283) 2018-11-19 15:25:14 -07:00
Kjell Hedström
de870694d5
Revert "add /MT for MSVC static lib (#278)" (#279)
This reverts commit ab76fc32c02f063f9f8d0daaefc41c28f5a1e69a.
2018-07-15 14:01:56 -06:00
AlexP11223
ab76fc32c0 add /MT for MSVC static lib (#278) 2018-07-14 08:59:36 -06:00
ccvca
39526ce9d2 Fix: VS 2015 logmessage.cpp(167): error C2437: "_file" already initialized (#277) 2018-07-13 05:59:11 -06:00
Kjell Hedström
3c9a590a76
Improved readme for Windows 64 bit (#276)
* Improved readme for Windows 64 bit 

This clarifies that Windows users have to check the CMake documentation

* Spell check
2018-07-12 21:40:03 -06:00
outkontroll
a6788f89be VS2013 missing include (#273) 2018-06-21 15:39:26 -06:00
Max Savenkov
5ffb360e2f export generated defines directory so that the library can be used via add_subdirectory from another CMake-based project (#268) 2018-06-12 14:59:15 -06:00
mobileben
86c04cf729 Support defining the minimum deployment since newer Xcode defines minimum target of 10.0 for 32-bit devices (#272) 2018-06-06 07:21:23 -06:00
Kjell Hedström
b1beccc3a7
Update API.markdown 2018-05-24 17:12:47 -06:00
Kjell Hedström
f2c331f14c
Added description for FATAL hook function 2018-05-24 17:10:53 -06:00
Kjell Hedström
90065889b6
Added description for overriding the default signal handling 2018-05-24 17:06:28 -06:00
Kjell Hedström
01be7d4a0e
Added information for PID1 fatal signal handling 2018-05-24 16:57:44 -06:00
Kjell Hedström
2a21914c07
Update API.markdown
Added description: disable fatal signal handling
2018-05-24 16:50:55 -06:00
Julien Lecomte
e58c8d1ddf Add missing STATUS keyword following commit 82df2168aaa for #190 (#267) 2018-05-15 05:49:41 -06:00
Andreas Schönle
7b0414f76f Use defective stlpatch_future.hpp only for VS2013 (#266) 2018-05-14 06:43:05 -06:00
Eli (Codekrafter)
e8fe9d8b38 fixed warning about whitespace (#265) 2018-05-09 10:54:48 -06:00
John Farrier
69f21e3513 Fixed ambiguous constructor error. (#262) 2018-04-26 20:30:26 -06:00
Thomas Khyn
b6220b9174 MinGW / Windows fixes (#260)
* Add MINGW_HAS_SECURE_API flag for mingw compiler

* Use cmd rather than powershell to get GIT_VERSION on windows

powershell causes cmake to hang
2018-04-22 10:26:28 -06:00
DerekJuba-NIST
7f25b004cf Update loglevels.hpp (#259)
Fixed typo DEBUG -> DBUG
2018-04-12 09:55:42 -06:00
Kjell Hedström
ee742752e1
Update PULL_REQUEST_TEMPLATE.md 2018-03-30 21:20:39 -06:00
Kjell Hedström
9f4023c0cb
Create PULL_REQUEST_TEMPLATE.md 2018-03-30 21:20:12 -06:00
Kjell Hedström
8112f75dcf
improved runalltests (#255) 2018-03-25 23:35:52 -06:00
Jeff Ebert
408061280f restore original sigaction in restoreSignalHandler (#254)
* restore original sigaction in restoreSignalHandler

- Save original sigactions in a map called gSavedSigActions
- In restoreSignalHandler, do nothing if there is no saved sigaction.
  If there is a saved sigaction, then re-install it.
- Fixes issue #253

* fix bug found in code review of PR #254

* add functions for reporting sigaction errors

- Factor out reportSigactionError functions from functions that
  call sigaction to allow unit testing.
- Use strsignal libc function to convert from signal number to name
  to eliminate chance of not finding the name in {g,k}Signals maps.

* cleanup. perror doesn't need a wrapper. put code under test
2018-03-25 21:43:49 -06:00
Kjell Hedström
14db37ad23
G3log placeholder thread ID formatting (#248)
* Added thread ID configurable through API calls. Left to do g3sinks, documentation and some corner test cases for CHECK, LOG(FATAL) and FATAL signal

* improve test script, break if error

* easier to use API. Api docs added

* Update API.markdown

* Update API.markdown

* Update API.markdown

* updated readme with details for overriding default for "full details"

* updated custom sink with custom formatting example
2018-03-08 09:16:12 -07:00
Kjell Hedström
f2b860a2b4
Addressing the std2 concern raised in https://github.com/KjellKod/g3log/issues/212 (#246) 2018-02-20 22:02:19 -07:00
Петр Шургалин
217f52fb12 CMake: CMAKE_INSTALL_PREFIX for Linux (#243)
* CMake: CMAKE_INSTALL_PREFIX for Linux

If on Linux system CMAKE_INSTALL_PREFIX is set it overrides
CPACK_PACKAGING_INSTALL_PREFIX key.

* Readme: readme for MinGW building and installation

* Update README.markdown
2018-01-08 21:22:08 -07:00
Петр Шургалин
11f9f06f5c CMake: add install rule (#241)
* CMake: add MinGW install rule

* CMake: relative packaging paths
2017-12-27 13:09:40 -07:00
Kjell Hedström
c79695c387
Update CMakeLists.txt 2017-12-20 12:24:00 -07:00
Kjell Hedström
287bfc11cb
Update CMakeLists.txt 2017-12-20 12:09:41 -07:00
Петр Шургалин
a2ed65600b CMake: fix CMake version check on windows (#240)
CMake was telling that my version 3.10.1 is lesser thar 3.4
2017-12-20 10:32:36 -07:00
maj-tom
0ddfd6dccc Fix dangling else in LOG and LOGF macros (#231)
* Fix dangling else in LOG and LOGF macros
Closes #224

* added unit test
2017-12-06 21:31:55 -07:00
PeasantCodeFarmer
e7d3b9d7b1 Comment change for issue #232 (#237)
* Fixing some English/typos and a cyclical header include.

* Comment fix for issue# 232
2017-12-04 18:24:55 -07:00
Jean-Christophe Fillion-Robin
0005e14a9c cmake: Avoid extra recompilation updating generated_definitions.hpp only if needed (#235)
This commit updates the build system to ensure the generated_definitions
header is updated only if its content changed. This will avoid recompilation
if the re-configured without changing any options.
2017-12-02 17:21:56 -07:00
PeasantCodeFarmer
b4be5a0f00 Fixing some English/typos and a cyclical header include. (#234) 2017-11-22 07:41:35 -07:00
Matt Patterson
b3cb1ba057 atomicbool.hpp needs EOF outside of comment to build on VS15 (#229) 2017-10-26 18:37:37 -06:00
spinorx
28105e08d7 Support full filenames in logs. (#226)
This is helpful for doing cut and paste of filenames when opening.
Also fixed couple of macro parentheses.
2017-10-11 12:59:46 -06:00
mobileben
833b22d23b iOS Support (#183) (#198) 2017-09-26 21:33:08 -06:00
Kjell Hedsröm
96d6cda239 fixed comparison warning 2017-09-23 19:16:51 -06:00
mobileben
93c05406d8 Add in support for configurable kMaxMessageValue #203 (#208)
* Add in support for configurable kMaxMessageValue #203

* Add in documentation for USE_G3_DYNAMIC_MAX_MESSAGE_SIZE
2017-09-08 22:51:46 -06:00
maj-tom
97c6cf45b3 Update filesink.cpp (#216) 2017-07-19 13:16:50 -06:00
Thomas ten Cate
2a8ebca2d7 Remove double flushed from example (#214)
It's gone since e31c204
2017-07-13 07:01:00 -06:00
Andreas Schönle
f42611d2a1 fixed windows timestamp (#200)
* fixed windows timestamp

* ficing linux time

* Fix to_system_time

* fix last review issue.

* fixed formatting.

* Comment added to to_system_time() functiuon.:wq
2017-06-04 07:47:29 -06:00
Andreas Schönle
82df2168aa CMake messages changed to message( STATUS "..." ) (#190) 2017-05-17 14:31:19 -06:00
Andreas Schönle
ac37076327 Cross-compiling: Version readout fixed (#189)
* Cross-comoiling: Version readout fixed
Test.cmake: Path handling consistent

* ".x" syntax in variable checking removed

* Use G3LOG_DEBUG also in linux-specific code

* Fixed error when linux and shared library is on

* Fixed linux/windows shared lib handling: FATAL_ERROR for wrong cmake
version and no message in linux
2017-05-17 14:24:11 -06:00
Kjell Hedström
769feca4d0 Corrected cmake log message (#197) 2017-05-17 08:32:10 -06:00
Kjell Hedström
c08fba999b Definitions made explicit (#196)
* force definition inclusion

* to make it clear to the user
2017-05-17 08:25:29 -06:00
Jakob Wanner
24dea1ceea Cast char array to pointer to char in INTERNAL_LOG_MESSAGE (#193) 2017-05-17 08:07:39 -06:00
Andreas Schönle
123977f106 unit tests running with windows shared dll (#178)
* unit tests running with windows shared dll

* CMake automatically uses DLL runtime - remove cmake entries modifying
compiler flags

* missing DBUG vs DEBUG issue in Linux

* generated header added

* correction in CMake: Set HEADER_FILES correctly

* added static library option

* switched to powershell and included WORKING_DIRECTORY

* powershell use in windows and WORKING_DIRECTORY instead of cd

* Fixed appveyor.yml to use Release configuration and run unit tests

* trying to make appveyor work again ...

* make sure ERRORLEVEL is 0 when unit tests run successfully

* Still trying to fix appveyor ...

* Defaulting to shared library in linux, too

* Removed runtime loading test when g3log is not a shared library in linux

* Run unit tests verbosly using ctest.exe

* Disabled AggressiveThreadCallsDuringShutdown test

* Revert "Run unit tests verbosly using ctest.exe" (accidental commit)

This reverts commit b30513450d02d0bcb032e9b3997cf3592f87597e.

* re-committing valid parts of reverted commit

* DBUG vs DEBUG fix moved to generated_definitions.hpp

* cleanup shared/static option

* clarify cmake build types regardless of type

* Added compile test for DEBUG and DBUG

* put back formatting

* Removed commented out /MD switches for MSVC
2017-05-09 10:26:48 -06:00
Andreas Schönle
a1b5d97689 powershell use in windows and WORKING_DIRECTORY instead of cd (#181) 2017-05-04 14:00:17 -06:00
Kjell Hedström
613db7e346 test appveyor (#180)
* test appveyor

* fixed line issue

* extracting software version for windows too

* removed printout
2017-05-03 18:49:11 -06:00
Kjell Hedström
887673f4d0 Time adjustments for VMs and 32-bit embedded (#177)
* in progress. now using std::chrono

* in progress, not working but defined how to fix it - broken unit tests

* working - verified on VM. Unit tests not yet updated accordintly

* fixed all tests

* fixed formatting

* adjusted timezone during testing

* adjusted test for timezone
2017-04-27 22:57:04 -06:00
Kjell Hedström
121bb9c790 fix OSX/Clang build warnings and 32-bit linking errors regarding build versin (#176) 2017-04-24 21:50:35 -06:00
Kjell Hedström
ac54350346 The definitions file has to be generated after the options but before the build step. This way it will be included in the install target (#173) 2017-04-20 00:53:52 -06:00
Kjell Hedström
e04681ac42 Levels api changes 2 (#170)
* in progress

* Update loglevels.hpp

* Update loglevels.hpp

* don't code when too tired

* revert back

* removed comment
2017-04-05 23:03:55 -06:00
lemonnguyen
9f9062f45f Fix typos (#166) 2017-04-02 16:22:35 -06:00
Kjell Hedström
eba984171a Correcting define checks (#164)
* IF (NOT DEFINED  does NOT work on some CMake versions. This is a work-around

* removed log output
2017-04-01 10:39:34 -06:00
Kjell Hedström
33ed100f91 Colorer build and loglevel improvements (#161)
* static build with MS libs; remove vc11 support from cmake
* support AMD processor on winXp
* mingw build
* support older versions
* removed cmake warnings

* fix cmake >= 3.1 warnings (CMP0054)
* add target_include_directories - in projects that depend on g3log, do not need to specify include_directories
* Improved CPackage installation
* cleanup of build and test scripts
* c++14 gives for cleaner syntax
* build cleanup libg3logger.so will be a link to the actual libg3logger.so.<major><minor><build>. Only shared libraries from now on



* disableAll for log levels
* new setLogLevel impl
* cleaned up levels, now it should be easy for the user to understand how to add custom levels
2017-03-30 22:52:09 -06:00
Kjell Hedström
71ad664646 Update CPackLists.txt 2017-03-30 01:48:35 -06:00
Kjell Hedström
66a3d5ec0f Git release versioning (#163)
* corrected versions to fit release versioning

* fixed comments
2017-03-29 11:25:23 -06:00
Kjell Hedström
6e77118706 Time correction (#159)
* Improved the cpackage build. Also removed test compilation warnings

* To correcte what was reported in issue 155 (https://github.com/KjellKod/g3log/issues/155)
2017-03-28 11:09:10 -06:00
Kjell Hedström
417ae2ca10 Added a g3sink example (#158)
* Added a g3sink example

* Update API.markdown

* Update API.markdown

* Update API.markdown
2017-03-28 10:22:19 -06:00
Kjell Hedström
9b17525b97 Improved the cpackage build. Also removed test compilation warnings (#156) 2017-03-26 01:11:18 -06:00
Kjell Hedström
afa9a45a86 Update README.markdown 2017-03-24 13:49:24 -06:00
Aleksey Dobrunov
a48a4860fd fix mingw build (#152) 2017-02-19 10:50:58 -07:00
Kjell Hedström
3305652de5 Merge pull request #150 from 0017031/change_by_0017031
force /utf-8 for MSVC compiler
2017-02-15 00:02:56 -07:00
baic
411b8e249c force /utf-8 for MSVC compiler 2017-02-13 16:25:30 +08:00
Kjell Hedström
5660732d82 Merge pull request #147 from KjellKod/OSX_std_get_timespec
Update time.cpp
2017-01-08 14:07:02 -07:00
Kjell Hedström
c71349ac3d Update time.cpp 2017-01-08 14:01:38 -07:00
Kjell Hedström
a04b17abb5 Merge pull request #144 from rickyzhang82/pr-fix-output-format
Fix message newline issue
2016-12-23 09:13:19 -07:00
Ricky Zhang
d747de2840
Add back ugly tab
Signed-off-by: Ricky Zhang <rickyzhang@gmail.com>
2016-12-22 19:33:29 -05:00
Kjell Hedström
5bc693e099 Merge pull request #145 from rickyzhang82/pr-add-cmake-package
Add CMake package support
2016-12-22 10:24:37 -07:00
Ricky Zhang
601f6af1fd
Add CMake package support
Signed-off-by: Ricky Zhang <rickyzhang@gmail.com>
2016-12-22 11:30:18 -05:00
Ricky Zhang
fc615b4ac0
Fix message newline issue
Signed-off-by: Ricky Zhang <rickyzhang@gmail.com>
2016-12-22 11:23:25 -05:00
Kjell Hedström
3ed2ed2674 Merge pull request #141 from KjellKod/Build-CMake-flags
Inherit C++ flags from build environment
2016-12-21 15:44:47 -07:00
Kjell Hedström
ab5b408f40 Merge pull request #137 from AbberiorInstruments/windows-time-fix
fix timing inaccuracy on windows
2016-12-21 15:38:44 -07:00
Andreas Schönle
2ebb9c2346 Merge branch 'master' into windows-time-fix 2016-12-19 17:03:23 +01:00
Andreas Schönle
294a015175 Merge pull request #1 from AbberiorInstruments/KjellKod-clean-up-timing
merged pull request #1
2016-12-19 16:43:45 +01:00
Kjell Hedström
6cdefee897 Inherit C++ flags from build environment
As suggested in : http://stackoverflow.com/questions/36765217/how-to-create-cmake-recipes-in-yocto
2016-12-14 21:36:52 -07:00
Kjell Hedström
34aa4ff8d6 Update time.cpp
removed ifdef's and using Andreas' implementation of  get_time
2016-12-09 23:26:20 -07:00
Kjell Hedström
6bf8afddfa Merge pull request #133 from AbberiorInstruments/arm-fix
compiles on arm
2016-12-09 23:02:21 -07:00
Kjell Hedström
b7adc0e77d fix formatting to get the branch merged 2016-12-09 23:02:04 -07:00
Andreas Schönle
03734dd29c alternative, better fix as proposed by Kjell 2016-12-06 17:36:17 +01:00
Andreas Schönle
cc2bd60ecb Merge branch 'master' into windows-time-fix 2016-12-06 17:15:37 +01:00
Kjell Hedström
e6f9178d42 Merge pull request #138 from AbberiorInstruments/include-file-path-only
Include file path only
2016-12-06 09:15:05 -07:00
Andreas Schönle
8d01c2224d reverted file parameter to std::string reference, adjusted formatting 2016-12-06 17:13:27 +01:00
Kjell Hedström
dc06cfb683 Merge pull request #139 from AbberiorInstruments/add-levels-only
Add levels only
2016-12-06 08:49:21 -07:00
Andreas Schönle
f018f3e92f Fixed formatting 2016-12-06 14:34:23 +01:00
Andreas Schönle
793ddbd42e changed to copying the file path upon message creation 2016-12-06 14:07:01 +01:00
Andreas Schönle
4bd1870a76 effectively remove feature - it is almost useless. Keep the change to the unit test avoiding premature exit when fatal signal handling is not enabled in the library 2016-12-06 13:55:47 +01:00
Andreas Schönle
c8e9dc367c Merge branch 'master' into arm-fix 2016-12-06 12:01:16 +01:00
Andreas Schönle
7ece784109 Merge branch 'master' into windows-time-fix 2016-12-06 12:00:30 +01:00
Andreas Schönle
cb3e2b1336 Merge branch 'master' into include-file-path-only 2016-12-06 12:00:01 +01:00
Andreas Schönle
b43848c527 Merge branch 'master' into add-levels-only 2016-12-06 11:59:21 +01:00
Kjell Hedström
d9413181d3 Merge pull request #136 from KjellKod/KjellKod-Travis-test
Update .travis.yml
2016-12-05 23:55:17 -07:00
Kjell Hedström
1a27d6379f thanks to: https://github.com/PacificBiosciences/pbbam/blob/master/.travis.yml 2016-12-05 23:49:32 -07:00
Kjell Hedström
8cc59bece2 more sudo 2016-12-05 23:31:46 -07:00
Kjell Hedström
fc1f531d1d sudo change reverted 2016-12-05 23:29:43 -07:00
Kjell Hedström
c70fd4f978 space removed 2016-12-05 23:26:14 -07:00
Kjell Hedström
10150e7633 key-space issues, fixed1 2016-12-05 23:23:16 -07:00
Kjell Hedström
aed15716ad test3 2016-12-05 23:16:48 -07:00
Kjell Hedström
296b91d857 test2 2016-12-05 23:10:28 -07:00
Andreas Schönle
f1f2167864 Update API.markdown
Added description of addLogLevel function
2016-12-05 11:21:40 +01:00
SchoenleAndi
7d1481724c restore needs a flag to remove custom levels (at least the tests need to be able to do it)
addLogLevel again resets the log level to the passed enable_state as even requesting the level before adding it would otherwise lead to unexpectedly not setting a "new" level to the passed state. We now assume setLogLevel is not called before addLogLevel without considering this behavior.
2016-12-05 11:12:28 +01:00
SchoenleAndi
a98b91fc5c ensure that raise(SIGTERM) is not called in test if g3log was compiled without fatal signal handler 2016-12-05 10:48:52 +01:00
SchoenleAndi
a1748ce66b addLogLevel now plays nice with having called setLogLevel before. 2016-12-05 10:17:38 +01:00
SchoenleAndi
bb163ea376 Merge branch 'master' into windows-time-fix 2016-12-04 19:20:22 +01:00
SchoenleAndi
9436660109 Merge branch 'master' into arm-fix 2016-12-04 19:18:50 +01:00
SchoenleAndi
b1088d06ab Merge branch 'master' into include-file-path-only 2016-12-04 19:17:39 +01:00
SchoenleAndi
323ca8e7ce Merge branch 'master' into add-levels-only 2016-12-04 19:15:51 +01:00
Kjell Hedström
0624e8c655 Update .travis.yml
Ref: discussion at https://github.com/travis-ci/travis-ci/issues/4631
2016-12-04 08:32:45 -07:00
SchoenleAndi
069085c451 fix timing inaccuracy on windows 2016-12-04 16:09:23 +01:00
Kjell Hedström
d15fcb3776 Update .travis.yml
Dummy trigger to travis
2016-12-04 07:17:21 -07:00
Kjell Hedström
426e77943e Merge pull request #126 from dasmysh/master
Updated cmake version to correct string compare behaviour.
2016-12-04 07:15:54 -07:00
Kjell Hedström
1ba64d5e09 Merge pull request #134 from KjellKod/KjellKod-trigger-travis-1
trigger travis
2016-12-02 10:22:25 -07:00
Kjell Hedström
5a0e730d0c assume yes for interactive check 2016-12-02 10:16:46 -07:00
Kjell Hedström
0fd9cb8408 trigger travis
test
2016-12-02 10:13:02 -07:00
Kjell Hedström
0fdccaf823 Update .travis.yml
Upgrade travis cmake version
2016-12-02 10:10:01 -07:00
SchoenleAndi
e93031c6d0 compiles on arm 2016-12-02 17:01:16 +01:00
Kjell Hedström
813e3da1f9 Merge pull request #129 from AbberiorInstruments/msvc-format-specifier
MSVC printf format specifier
2016-10-20 13:37:16 -06:00
Kjell Hedström
570a85b997 Merge pull request #128 from AbberiorInstruments/DBUG-vs-DEBUG
Fix compilation errors when CHANGE_G3LOG_DEBUG_TO_DBUG is enabled-
2016-10-20 13:35:17 -06:00
SchoenleAndi
1dafdaf2a4 msfc fromat specifiers added 2016-10-19 13:41:48 +02:00
SchoenleAndi
c39e77c27e DBUG-vs-DEBUG in main_ programs fixed 2016-10-19 13:39:24 +02:00
SchoenleAndi
940d11a61d DBUG vs DEBUG fixed in unit test, too 2016-10-19 13:36:19 +02:00
SchoenleAndi
c467851423 save include fil full path as const char * in LogMessage 2016-10-19 13:21:52 +02:00
SchoenleAndi
09ede1bf1f add loglevels to upstream master only 2016-10-19 13:17:46 +02:00
Sebastian Maisch
e7af386de2 Updated cmake version to correct string compare behaviour. 2016-10-17 19:49:56 +02:00
Kjell Hedström
ba81287ca5 bugfix time formatting (#119)
* bugfix time formatting

* fixit
2016-08-30 18:34:13 -06:00
Lynn
1bae2e6a68 Typo fix (Vaulue → Value) (#120)
* typo fix (Vaulue → Value)

* typo fix (Vaulue → Value)
2016-08-30 11:10:58 -06:00
Kjell Hedstrom
e0fb4fd24e fixit 2016-08-25 00:51:21 -06:00
Kjell Hedstrom
26f76cd103 bugfix time formatting 2016-08-25 00:49:17 -06:00
Kjell Hedström
1496d7aa40 Update API.markdown (#115) 2016-08-18 00:49:49 -06:00
Kjell Hedström
7d6bf2fac5 Update README.markdown (#114)
* Update README.markdown

* Update README.markdown

* Update README.markdown

* Update README.markdown

* Update README.markdown
2016-08-18 00:37:28 -06:00
Kjell Hedström
9b8e13bcfe Update crashhandler.hpp (#110)
Thanks to @graugans
2016-08-11 07:08:41 -06:00
Kjell Hedström
86473c60e0 Gimesketvirtadien's time requested changes (#104)
* Added "removeSink" method and related functionality to LogWorker API

* Added a new API for plugging in custom Timestamp generator.

* Revert "Added "removeSink" method and related functionality to LogWorker API"

This reverts commit c9cee5d9a077ce1e7e68f07cc30d03e4bed19c7b.

* Dropping shared_ptr<Timestamp> in log messages and using regular vars

* Moving to standard timespec struct from custom Timestamp

* Wiring timespec timestamps with formating routine

* Falling back to clock_gettime

* Reverting g3 API changes

* Optimizing format string generation

* Removed _microseconds from LogMessage

* Implemented sec fractional format key

* Optimization of format string generation

* Adjusting comments

* Refining localtime_formatted by introducing two helper functions

* refactored and simplified code

* fixed up some commented away unit tests

* refactoring message specifics tests to it's own test

* Use gcc 4.9

* C++14 for Linux

* Update .travis.yml

* Update buildAndRunTests.sh

* lower case in `-std=c++14`

* -lrt flag for gcc

* Added support for high precision clock on Linux/gcc (already there now for OSX). Windows is still missing

* intermediate comments

* Clarified for some code readers the mysterious use of assert in an expression that is always true

* refactored + renamed functions and constants. Added unit test for retrieving fractional type

* committing changes previously fixed - finished unit testing for g3::internal::time::GetFractional(..)

* added unit test for fractional to string

* added missing unit tests for localtime_formatted

* fixed? nano / microsec functionality to timer

* test
2016-08-11 00:27:52 -06:00
jkhoogland
ff722164d4 Warning braces loglevels clang 3.7 (#108)
* Fix gcc compiler warning for braces around scalar

* use 'toString' to get the formatted output in the fatal cerr message when a LOG fatal or CONTRACT happens. This was already OK on the sink side

* Avoid initialization/shutdown deadlock that could occur due to wrong use of the API

* Workaround for windows testing (#100)

* added automatic linking pragma for `StackWalk64` (#96)

* fix to implicit type casting (#98)

* create a Xcode project

* fixed to implicit type casting

* Revert "create a Xcode project"

This reverts commit e3216391f536fa41c47067fdb0296c56bafa11fa.

* Fixed a bug causing cross-compilers to fail (#101)

(The edited line eliminated the original CXXFLAGS variable, removing the sysroots parameter, which is needed for cross compiling)

* Update logworker.cpp (#103)

* Fix gcc compiler warning for braces around scalar

* Add back braces
2016-07-31 17:01:54 -06:00
Kjell Hedström
e0d4434428 Update logworker.cpp (#103) 2016-06-23 21:35:59 -06:00
Nitaym
56b3f20517 Fixed a bug causing cross-compilers to fail (#101)
(The edited line eliminated the original CXXFLAGS variable, removing the sysroots parameter, which is needed for cross compiling)
2016-06-22 14:29:45 -04:00
Kjell Hedström
04817b6e85 Workaround for windows testing (#100) 2016-06-12 16:58:14 -06:00
Dmitry Ledentsov
f10fbe1d9c added automatic linking pragma for StackWalk64 (#96) 2016-06-12 16:57:55 -06:00
JiHyung Lee
736d6437b8 fix to implicit type casting (#98)
* create a Xcode project

* fixed to implicit type casting

* Revert "create a Xcode project"

This reverts commit e3216391f536fa41c47067fdb0296c56bafa11fa.
2016-06-12 14:09:55 -06:00
Kjell Hedström
e58cc942dd Merge pull request #94 from KjellKod/Fatal_exit_For_Erronous_Initialization
Avoid initialization/shutdown deadlock
2016-05-23 22:34:41 -06:00
Kjell Hedstrom
70b37d66a0 Avoid initialization/shutdown deadlock that could occur due to wrong use of the API 2016-05-23 22:25:32 -06:00
Kjell Hedström
6c1698c4f7 Merge pull request #86 from KjellKod/cerr_when_fatal_exit
use 'toString' to get the formatted output in the fatal cerr message …
2016-03-30 16:42:43 -06:00
Kjell Hedstrom
bfe1e8ad19 use 'toString' to get the formatted output in the fatal cerr message when a LOG fatal or CONTRACT happens. This was already OK on the sink side 2016-03-30 16:35:38 -06:00
Kjell Hedström
7d0779d92d Merge pull request #84 from KjellKod/checkmarx-update
removed false positives as detected by Checkmarx code analysis tool. …
2016-03-24 11:21:43 -06:00
Kjell Hedström
4472ba3cbf fix the tool, not the code 2016-03-24 10:43:09 -06:00
Kjell Hedström
d01dfbf992 revert "fix" for issue with checkmarx. The tool should be fixed, not the code 2016-03-24 10:41:23 -06:00
Kjell Hedstrom
8df4eadd92 removed false positives as detected by Checkmarx code analysis tool. Not impressed so far though with the tool 2016-03-18 10:50:59 -06:00
Kjell Hedström
db23383aea Merge pull request #83 from KjellKod/duedal-install-target
Duedal install target
2016-03-06 23:04:00 -07:00
Kjell Hedsröm
33003af08b fixed user com 2016-03-06 23:02:04 -07:00
Kjell Hedsröm
0bd43a9ef2 start of replacement for: https://github.com/KjellKod/g3log/pull/74/files 2016-03-06 15:55:35 -07:00
Kjell Hedström
5790c3723f Merge pull request #80 from KjellKod/Thread_local
Update stacktrace_windows.cpp
2016-02-24 19:16:09 -07:00
Kjell Hedström
56cef7959c Merge pull request #82 from KjellKod/repace-g3log-in-path
Repace g3log in path
2016-02-17 00:31:15 -07:00
Kjell Hedsröm
fbddb5a5ca added new API for AddDefaultLogger to API 2016-02-17 00:25:55 -07:00
Kjell Hedsröm
b7704b1ed7 fixed merge conflict 2016-02-17 00:06:45 -07:00
Kjell Hedsröm
1ebaf0e7e5 fixed conflict 2016-02-16 23:16:22 -07:00
Kjell Hedström
af505d572a Merge pull request #81 from KjellKod/path_parenthesis_fix
Allow parenthesis in path and filename
2016-02-16 23:00:23 -07:00
Kjell Hedsröm
072a7bef93 put back commented out code 2016-02-16 22:57:02 -07:00
Kjell Hedsröm
fb034e1000 fixed commented out code, left it but corrected 2016-02-16 22:56:21 -07:00
Kjell Hedsröm
a0b961ee04 Allow parenthesis in path and filename 2016-02-16 22:52:38 -07:00
Kjell Hedström
279587c567 Update stacktrace_windows.cpp
For access to thread_local definition
2016-02-16 20:55:28 -07:00
Jiri Hoogland
e981b08c81 Put include headers back per request of Kjell 2016-02-03 18:19:36 -05:00
Jiri Hoogland
b8f28d3a49 Fix missing include files 2016-02-02 19:05:29 -05:00
Kjell Hedström
579579962c Merge pull request #77 from sradigan/FixLinuxClangSupport
Fixed build options to allow compilation on linux using clang
2016-02-02 16:02:35 -07:00
Sean Radigan
a65b99087b Fixed build options to allow compilation on linux using clang 2016-02-02 16:30:44 -05:00
Jiri Hoogland
3aab24d8c8 Handle empty logger_id 2016-01-28 10:06:40 -05:00
Jiri Hoogland
31c01b168c Add ability for user to override 'g3log' monniker in log file 2016-01-28 10:02:22 -05:00
Jiri Hoogland
d9bc515ce8 Add ability for user to override 'g3log' monniker in log file 2016-01-27 18:51:02 -05:00
Aleksey Dobrunov
69e0cafee8 fix unit test 2016-01-27 13:56:14 -05:00
Aleksey Dobrunov
0384eb1638 fix build lib 2016-01-27 13:56:14 -05:00
Aleksey Dobrunov
c9e93c8d14 remove unused include 2016-01-27 13:56:14 -05:00
Hans Duedal
1847312bac Enable an install target
Should work fine on Unix systems, and support install prefixes.
Installs both a static and a shared library to the same location, so we
get an .a and a .so/.dylib file, which can be linked to in the ordinary
way, ie. `-lg3logger`.
2016-01-24 13:27:52 +01:00
Kjell Hedström
1c6ede6db4 Merge pull request #72 from colorer/unused_includes
remove unused include
2016-01-11 12:38:26 -07:00
Aleksey Dobrunov
444642f47b fix unit test 2016-01-11 23:48:56 +05:00
Aleksey Dobrunov
1f4ffbeb6f fix build lib 2016-01-11 23:47:00 +05:00
Aleksey Dobrunov
12beaf89de remove unused include 2016-01-11 00:41:05 +05:00
Kjell Hedström
31d12dc090 Merge pull request #66 from guanqun/patch-1
trivial fix: add double quote around "some text"
2015-12-01 09:53:12 -07:00
Lu Guanqun
901b0d74e6 trivial fix: add double quote around "some text" 2015-12-02 00:10:48 +08:00
Kjell Hedström
501b16ffbd Merge pull request #65 from cstamatopoulos/missing_import_lib_msvc
#13 generate import lib in msvc using cmake >= 3.4
2015-12-01 05:51:48 -07:00
Kjell Hedström
e97656b902 Merge pull request #56 from turenar/thread_local
suppress 'thread attribute directive ignored' warning on mingw
2015-11-26 19:31:34 -07:00
cstamatopoulos
d125990007 #13 generate import lib in msvc using cmake >= 3.4 2015-11-26 19:13:45 -05:00
Kjell Hedström
77b1d1c0d5 Merge pull request #63 from cstamatopoulos/fix-msvc2013-compilation
fix msvc2013 compilation issue of internal::g_log_level_status on res…
2015-11-24 00:22:18 -07:00
Kjell Hedström
2c7faa0ec1 Merge pull request #64 from KjellKod/API_Documentation
Fixed dynamic logging unit test
2015-11-23 23:50:52 -07:00
Kjell Hedsröm
d4d60ca517 Fixed dynamic logging unit testw: 2015-11-23 23:49:27 -07:00
cstamatopoulos
499d1a51ef fix msvc2013 compilation issue of internal::g_log_level_status on reset() 2015-11-24 01:46:27 -05:00
Kjell Hedström
d361a4bbd9 Merge pull request #54 from KjellKod/API_Documentation
Api documentation
2015-11-23 23:20:06 -07:00
Kjell Hedsröm
9a5508b327 fixed typ 2015-11-23 23:18:27 -07:00
Kjell Hedsröm
01666ab80c Added link to the API docmentation 2015-11-23 23:17:47 -07:00
Kjell Hedsröm
2cef7cb174 Merge branch 'master' of github.com:KjellKod/g3log into API_Documentation
Conflicts:
	test_unit/test_io.cpp
2015-11-23 23:12:30 -07:00
Kjell Hedsröm
1007ab1fd9 Added windows fatal handling. All except the stackdump... maybe the options need to be explained as well 2015-11-22 16:55:50 -07:00
Kjell Hedsröm
2b7331c892 TODO --> TOWRITE 2015-11-22 16:43:08 -07:00
Kjell Hedsröm
73cda4bd3e Marking all non-yet made entries with strikethrough and 'TODO' 2015-11-22 16:41:19 -07:00
Kjell Hedsröm
773000caf9 Added fatal handling: Linux 2015-11-22 16:36:30 -07:00
Kjell Hedsröm
11e22dd40d The sigsegv example exited by sigfpe. Fixed! 2015-11-22 16:35:36 -07:00
Kjell Hedsröm
df093e3563 Documentation done till fatal handling.
Improved logging levels
2015-11-22 16:01:53 -07:00
Kjell Hedström
0f790a4a11 Merge pull request #58 from KjellKod/Flush_On_Every_Write__DefaultLogger
flush after every write: https://github.com/KjellKod/g3log/issues/57
2015-11-03 13:54:50 -07:00
Kjell Hedström
4b3c4d7ff7 flush after every write: https://github.com/KjellKod/g3log/issues/57
https://github.com/KjellKod/g3log/issues/57
2015-11-03 13:35:47 -07:00
Turenar
fa15177d58 suppress 'thread attribute directive ignored' warning on mingw
make thread_local workaround on only <=VS2013
VS2015 has thread_local specifier
2015-10-30 16:09:39 +09:00
Kjell Hedsröm
c73c90f93c custom logging levels in progress 2015-10-10 15:25:35 -06:00
Kjell Hedsröm
91542319ee enable-disable logging levels at runtime 2015-10-10 15:14:47 -06:00
Kjell Hedsröm
8b1517896f API for logging and contract 2015-10-10 14:50:24 -06:00
Kjell Hedström
17756a2657 Merge pull request #55 from KjellKod/test_warnings
removed gcc5.2 warnings
2015-10-03 16:15:26 -06:00
Kjell Hedsröm
c1f5b20c6d removed gcc5.2 warnings 2015-10-03 16:13:21 -06:00
Kjell Hedstrom
bb1c31577d lists try 2 2015-09-21 16:23:27 -06:00
Kjell Hedstrom
4349797485 lists try 1 2015-09-21 16:20:32 -06:00
Kjell Hedström
077ede2bfb Merge pull request #53 from rayrapetyan/patch-1
Update Build.cmake (support for FreeBSD 10+)
2015-09-21 16:17:28 -06:00
Kjell Hedstrom
ed51ab8dbb ADDED vanilla API readme. Improved the README.markdown by elaborating on how to use a custom sink 2015-09-21 15:51:23 -06:00
Kjell Hedstrom
09a9bcc95e compile warnings, gtest comparisons 2015-09-21 15:33:34 -06:00
Robert Ayrapetyan
8f109ec131 Update Build.cmake (support for FreeBSD 10+)
Proposed fix for building on FreeBSD 10+ systems:
- c++abi and rt libs are not required
- pthread flag and execinfo lib is required
2015-09-20 19:23:38 -07:00
Kjell Hedström
35cdf42b05 Merge pull request #52 from craig-cogdill/SaveG3Log
Adding the function name and saving the day
2015-09-17 00:40:00 +02:00
Craig Cogdill
051fb50c98 Adding the function name and saving the day 2015-09-16 16:29:48 -06:00
Kjell Hedstrom
40fbc7b4b3 Merge pull request #50 from KjellKod/improve-default-formatting
Improve default formatting
2015-09-14 21:56:51 -06:00
Kjell Hedstrom
d936bc2763 Fixed formatting unit tests 2015-09-14 21:52:42 -06:00
Kjell Hedstrom
403f3cb94f Improve default formatting
Instead of 
<date and time> <file>:L<line> .... 

have 
<date and time>**<file>:<line>**
2015-09-14 19:03:32 -06:00
Kjell Hedstrom
4974cf1da6 Merge pull request #48 from KjellKod/disable_single_signals
Custom signal handler
2015-09-11 07:03:38 -06:00
Kjell Hedstrom
a1a3672d71 Missing include 2015-09-11 03:23:24 -06:00
Kjell Hedstrom
a5e21e5d52 testing ssh 2015-09-11 03:05:34 -06:00
Kjell Hedstrom
b9fc844bb4 testing it again 2015-09-11 03:02:35 -06:00
Kjell Hedstrom
dcdf41b3ee tesing ssh keys again 2015-09-11 02:57:38 -06:00
Kjell Hedstrom
980b863ec7 test ssh key 2015-09-11 02:54:27 -06:00
Kjell Hedstrom
fae01d5e92 Added missing test for custom signal handling for SIGTERM 2015-09-11 02:49:17 -06:00
Kjell Hedstrom
602e135f84 Added resotre and override signal handler 2015-09-10 06:20:26 -06:00
Kjell Hedstrom
6432487adc Merge branch 'master' of https://github.com/KjellKod/g3log into disable_single_signals 2015-09-10 04:18:58 -06:00
Kjell Hedstrom
70f6cc2263 Merge pull request #47 from ctapmex/disable_shared
add option ADD_BUILD_SHARED
2015-09-06 14:14:32 -06:00
Aleksey Dobrunov
0a04ae2bf6 change defaut value and option logic 2015-09-06 23:00:24 +05:00
Kjell Hedstrom
ef277228bd Merge pull request #46 from ctapmex/def_example
fix example
2015-09-06 06:48:37 -06:00
Aleksey Dobrunov
d04b386fb4 add option ADD_BUILD_SHARED 2015-09-06 16:22:04 +05:00
Aleksey Dobrunov
9d853c7839 fix example 2015-09-06 15:35:03 +05:00
Kjell Hedstrom
3bcf360815 vanilla example. dynamic signal turning on/off 2015-09-01 00:35:47 -06:00
Kjell Hedstrom
ad11a34fbb Merge pull request #45 from KjellKod/clang-improved-crash-handling
Clang improved crash handling
2015-09-01 00:07:17 -06:00
Kjell Hedstrom
5eb9ab11c8 merge issues 2015-09-01 00:02:36 -06:00
Kjell Hedstrom
055c4ec2ca Fixed for windows 2015-08-31 23:45:47 -06:00
Kjell Hedstrom
a8d89b67c8 Merge branch 'clang-improved-crash-handling' of https://github.com/KjellKod/g3log into clang-improved-crash-handling
Conflicts:
	Build.cmake
	example/main_fatal_choice.cpp
2015-08-31 23:07:25 -06:00
Kjell Hedstrom
a068575595 removed comments. improved death test 2015-08-31 22:30:48 -06:00
Kjell Hedstrom
662fde2941 Merge pull request #44 from KjellKod/clean-cmake
improved: make clean-cmake to remove temporary files
2015-08-31 21:13:04 -06:00
Kjell Hedstrom
420fc92fa1 improved: make clean-cmake to remove temporary files 2015-08-31 21:12:11 -06:00
Kjell Hedstrom
e065d26953 Merge pull request #43 from jkhoogland/master
small fixes to squash some compile warnings
2015-08-31 21:09:55 -06:00
Kjell Hedstrom
bc5337e780 Merge pull request #42 from ctapmex/issue40
fix issue 40
2015-08-29 07:14:45 -06:00
Aleksey Dobrunov
7d2741c9a8 fix typo 2015-08-29 15:13:08 +05:00
Jiri Hoogland
73751d2e85 - remove unused "-pthread" flags for clang compilation
- set target_property for rpath handling on OSX
2015-08-28 15:39:06 -04:00
Kjell Hedstrom
671fd01aa1 This is made to NOT compile ... lines that don't compile are sections I need to check out
exhausted stack. kill vs exit.  using libunwind or backtrace but with symoblizer should be tested
and blogged about(?)
2015-08-27 08:02:18 -06:00
Kjell Hedstrom
62c7153ce4 Merge pull request #38 from KjellKod/Improved_Sink_API
Breaking change but a good change:  Cleared up the API  for adding sinks
2015-08-23 16:18:20 -06:00
Kjell Hedstrom
3efcef3505 my own code review I 2015-08-19 10:19:55 -06:00
Kjell Hedstrom
1803498e89 Breaking change but a good change: Cleared up the API for Creating log worker and Adding sinks 2015-08-19 10:08:41 -06:00
Kjell Hedstrom
bc4459d779 Merge pull request #37 from KjellKod/filter
preparation for g3sinks: Filter
2015-08-19 08:51:18 -06:00
Kjell Hedstrom
14a46f4567 Swap is less affective 2015-08-12 07:39:09 -06:00
Kjell Hedstrom
c6a0c28435 removed iostream previously used for temporary visibility 2015-08-12 06:48:55 -06:00
Kjell Hedstrom
8dfe9e0716 Improved copy constructors and assignment operator which is needed now when LOGLEVELS can be made on the fly 2015-08-12 06:43:24 -06:00
Kjell Hedstrom
88fc290d45 Merge pull request #36 from AlphaCluster/build-readme-cleanup
Changing the markdown for build examples
2015-08-06 22:31:51 -06:00
Nicholas Omann
60b3a4c359 Changing the markdown for build examples 2015-08-06 21:40:11 -05:00
Kjell Hedstrom
49aee72faf improved comparison test 2015-08-04 07:44:39 -06:00
Kjell Hedstrom
13cc398f06 comparison operators for level: gtest, std::find, == operator, !=operator 2015-08-04 07:43:38 -06:00
Kjell Hedstrom
b53cd95361 Merge pull request #29 from KjellKod/fixed_definitions
use the genereated_definitions.hpp
2015-07-22 13:33:49 -06:00
Kjell Hedstrom
d09ca7787d use the genereated_definitions.hpp 2015-07-22 13:28:10 -06:00
Kjell Hedstrom
a544f0b193 Merge pull request #24 from AlexandrePTJ/master
Fix path removal for windows
2015-07-22 10:24:29 -06:00
Alexandre Petitjean
a529895444 Update Build.cmake 2015-07-22 16:01:47 +02:00
Alexandre Petitjean
6ff84e092b Fix path removal for windows 2015-07-21 12:21:31 +02:00
Kjell Hedstrom
5c7c289069 Merge pull request #23 from KjellKod/levels
handling the case of DEBUG to DBUG
2015-07-20 08:25:11 -06:00
Kjell Hedstrom
540e9601df handling the case of DEBUG to DBUG 2015-07-20 08:23:49 -06:00
Kjell Hedstrom
056a5483da Merge pull request #22 from KjellKod/levels
improved dynamic Levels
2015-07-20 08:16:55 -06:00
Kjell Hedstrom
d5ad2709a7 removed changes to g3::only_change_at_initialization at shutdown/init.
It is thread unsafe and should be done explicitly (also the threaded 100 threads calling with initialzation + shutdown was handing)... good test
2015-07-20 08:11:57 -06:00
Kjell Hedstrom
786b92a6d1 Another, tiny, breaking change.
Due to popular request I have added the possibility to put in your own custom log levels. Due to performance regards changes to the log levels should ONLY be done
in a single thread context (initialiation) for that reason the namespace
used to "setLogLevel" is named appropriately
i.e. use: g3::only_change_at_initialization::setLogLevel(...)
2015-07-20 08:00:33 -06:00
Kjell Hedstrom
c4f9463b6b Custom levels can be added: So far dynamic on-off does not work 2015-07-20 00:45:41 -06:00
Kjell Hedstrom
010ecc5bc7 Merge pull request #20 from KjellKod/install_improvements
Install improvements
2015-07-19 23:32:36 -06:00
Kjell Hedstrom
b4ffc17344 staying with cmake 2.8 2015-07-19 23:29:36 -06:00
Kjell Hedstrom
b05d8d8fb9 sigh... travis needs semi colons 2015-07-19 23:26:38 -06:00
Kjell Hedstrom
b9c6140e84 cmake fixy 2015-07-19 23:24:35 -06:00
Kjell Hedstrom
755895ce93 Using later version of cmake on travis 2015-07-19 23:22:12 -06:00
Kjell Hedstrom
56bdcfa757 fixing travis 2015-07-19 23:16:29 -06:00
Kjell Hedstrom
7c7012325d Easier to install. continues
1) Breaking change:  g3 namespace replaces g2
2) g2log.hpp remains in src/g2log.hpp... but now all it does is to include the g3log.hpp, etc
3) ALL HEADER FILES ARE IN src/g3log/  while all .cpp and .ipp files are in /src  (exception for g2log.hpp)
   This should make it EASIER for clients to copy/install the header files to the new location.  It greatly simplifies
   rpm and cpackage installationsw
2015-07-19 23:10:56 -06:00
Kjell Hedstrom
7cf42c535c Making it easy for other people to see the formatting style 2015-07-16 01:58:21 -06:00
Kjell Hedstrom
6750efe8fe g2log.hpp is kept as a helper include. It will pull in the most frequent include files
All other are under g3log. Example: #include <g3log/time.hpp> #include <g3log/g3log.hpp> etc
This makes sure that the package manager (to be  used soon) does NOT clutter any /usr/local/include space
instead all the includes will be in /usr/local/include/g3log (or similar)
2015-07-16 01:55:23 -06:00
Kjell Hedstrom
94db9bb4db Updated for removing temporary cmake files with "make clean-cmake-files" 2015-07-16 00:27:17 -06:00
Kjell Hedstrom
78103cb415 Auto generate macro defintions in a file. This way you don't have to re-state them in your library
if no options are given a blank file will be generated
2015-07-13 07:49:44 -06:00
Kjell Hedstrom
3e5da340bd Merge pull request #19 from KjellKod/KjellKod-readme-patch
Update README.markdown
2015-07-06 22:36:52 -06:00
Kjell Hedstrom
07c74bbbc3 Update README.markdown 2015-07-06 22:34:20 -06:00
Kjell Hedstrom
389a7d695c Update README.markdown 2015-07-06 22:32:05 -06:00
Kjell Hedstrom
4f73fb4f7c Update README.markdown 2015-07-06 22:25:45 -06:00
Kjell Hedstrom
e219a5e426 Merge pull request #17 from KjellKod/windows_warnings
remove windows warnings. Thanks to @ctapmex
2015-06-24 14:51:54 -06:00
Kjell Hedstrom
ebcfe9ff06 remove windows warnings. Thanks to @ctapmex 2015-06-24 14:50:46 -06:00
Kjell Hedstrom
ed1cab05b0 Merge pull request #16 from KjellKod/timestamp
Thanks to @Bob Flynn:
2015-06-24 14:35:01 -06:00
Kjell Hedstrom
176fca55a6 Thanks to @Bob Flynn:
Separated the microseconds counter with a space instead of a period.
Also added explanation that the counter is from the initialization
2015-06-24 14:32:31 -06:00
Kjell Hedstrom
ab9a70e8a3 Update Options.cmake 2015-06-17 05:26:36 -06:00
Kjell Hedstrom
6731a2910f Update Options.cmake 2015-06-17 05:24:10 -06:00
Kjell Hedstrom
7d879cd7d6 Merge pull request #10 from KjellKod/KjellKod-patch-1
When using options and installing g3log as a rpm library
2015-06-11 21:43:01 -06:00
Kjell Hedstrom
8b6ee253f5 When using options and installing g3log as a rpm library
If the g3log code isn't embedded with your code, the defines must match the options "add_defines"
2015-06-09 10:43:32 -06:00
KjellKod
37989ed52f merging headswq 2015-05-03 22:41:20 -06:00
Kjell Hedström
dc0f3434c2 Merged in kostyabazhanov/g3log/pr4 (pull request #5)
Fix a couple of Clang warnings.
2015-05-03 22:34:34 -06:00
Kostya Bazhanov
43652ef7c9 Fix -Wextra-semi Clang warning.
--HG--
branch : pr4
2015-04-29 12:24:11 +03:00
Kostya Bazhanov
4686fb9cc2 Remove trailing spaces.
--HG--
branch : pr4
2015-04-29 12:23:30 +03:00
Kostya Bazhanov
8e4929cbdb Fix -Wunused-function Clang warning.
--HG--
branch : pr4
2015-04-29 12:22:26 +03:00
Kostya Bazhanov
cb097cbd3e Remove trailing spaces.
--HG--
branch : pr4
2015-04-29 12:21:45 +03:00
Kjell Hedstrom
b3b30a7eaf Merge pull request #8 from spoonless/mingw_xcompil
fixing cross compilation on Linux for MINGW gcc 4.8.2
2015-03-30 20:52:44 +02:00
David Gayerie
4c45244391 fixing cross compilation on Linux for MINGW gcc 4.8.2 2015-03-29 14:29:07 +02:00
Kjell Hedström
9ceb970475 README.markdown edited online with Bitbucket 2015-03-02 15:38:00 +00:00
Kjell Hedström
7464e55e90 README.markdown edited online with Bitbucket 2015-03-02 15:25:31 +00:00
Kjell Hedström
36b4c1df1d README.markdown edited online with Bitbucket 2015-03-02 15:24:35 +00:00
Kjell Hedström
be5c5d6c34 README.markdown edited online with Bitbucket 2015-03-02 15:23:48 +00:00
Kjell Hedstrom
65846fdeaa Merge pull request #7 from KjellKod/windows-vector-exceptions
Windows vector exceptions
2015-03-02 02:14:50 -07:00
Kjell Hedstrom
7c5254c80b thread_local issues on Linux, using atomic instead 2015-03-02 02:02:43 -07:00
Kjell Hedstrom
58ffeac9bc Clarified issue with __debugbreak() 2015-03-02 01:17:52 -07:00
Kjell Hedstrom
a5d922de49 __debugbreak in windows can easily cause recursive crashes if you are
NOT in debug mode in your visual IDE
2015-03-02 01:14:03 -07:00
Kjell Hedstrom
e2117fcc17 Merge pull request #6 from KjellKod/windows-vector-exceptions
Windows vector exceptions
2015-02-23 23:39:14 -07:00
Kjell Hedstrom
cc5cf169ba After code review by Kamil.
Moved internal API to public API.
g2log.hpp/cpp   g2::setFatalPreLoggingHook(...) and g2::setFatalExitHandler(...)
2015-02-23 23:29:02 -07:00
Kjell Hedstrom
a69eb201a1 Pre-fatal-log hook for usage before the fata log is sent to sinks 2015-02-22 23:31:17 -07:00
Kjell Hedstrom
a768d2146a Merge pull request #5 from KjellKod/windows-vector-exceptions
Defines for turning off fatal handling for signals
2015-02-18 04:09:02 -07:00
Kjell Hedstrom
7aea18edea Defines for turning off fatal handling for signals 2015-02-18 04:06:22 -07:00
Kjell Hedstrom
29d7aa7267 Merge pull request #4 from KjellKod/windows-vector-exceptions
Windows vector exceptions
2015-02-18 03:59:28 -07:00
Kjell Hedstrom
fc1acd742d 1) windows exception will now trigger break point in VS
2) Fatal signal will in DEBUG trigger a break point in VS
- It can be disabled by a #define
3) signal handler can be disabled by a #define
2015-02-18 03:55:16 -07:00
Kjell Hedstrom
eab596cfac Added exception handling comment 2015-02-16 02:31:16 -07:00
Kjell Hedstrom
108922784d Changed what was thrown 2015-02-16 02:16:25 -07:00
Kjell Hedstrom
81885e4456 Enabled vectored exception crash handling, it can also be turned off easily with a define
cmake -DENABLE_VECTORED_EXCEPTIONHANDLING=OFF
2015-02-16 01:37:55 -07:00
Kjell Hedstrom
9e3ed03310 Merge pull request #3 from KjellKod/windows-vector-exceptions
Disabled Vectored exception handling: TEMPORARILY.
2015-02-03 22:57:53 -07:00
Kjell Hedstrom
4c7c5c7ca7 Disabled Vectored exception handling: TEMPORARILY.
It will likely be enabled shortly but with
1) options for enabling/disabling it
2) use of unit test for unknown exceptions (and known)
   to make sure that 3rd party libraries that use exceptions (sigh)
   way too frequently are not affected.
3) only handling "known exceptions" unknown exceptions will get perhaps a
   LOG(WARNING) but no more "exiting"
2015-02-03 22:53:01 -07:00
Kjell Hedstrom
e71b5fc7c0 Merge pull request #2 from KjellKod/signal_improved_handling2
JuceTesting shows that all signalhandling should be installed per thread
2015-02-02 21:44:24 -07:00
Kjell Hedstrom
b3e7032678 Signals seems to have to be installed for EVERY thread 2015-02-02 21:35:48 -07:00
KjellKod
892059a2dd dual heads merge madness github-bitbucket 2015-02-02 00:40:34 -07:00
KjellKod
938fc55971 What a mess to merge from Github/KjellKod/g3log to BitBucket/KjellKod/g3log 2015-02-02 00:31:43 -07:00
Kjell Hedstrom
ec345e08c6 Merge pull request #1 from KjellKod/windows-crashhandler
Windows crashhandler
2015-02-02 00:04:37 -07:00
Kjell Hedstrom
f5fabd2868 removed branch from travis 2015-02-02 00:02:30 -07:00
Kjell Hedstrom
0bd34ba5de removed windows fatal conclusions file 2015-02-01 23:53:54 -07:00
Kjell Hedstrom
5b73954910 fixed crash handling after changes on the windows side 2015-02-01 23:52:45 -07:00
Kjell Hedstrom
2c6ead2115 Finishing up stacktrace for windows. Using "reworked" code in namespace "stacktrace"
which originated from Robert Engeln original code at: http://code-freeze.blogspot.com/2012/01/generating-stack-traces-from-c.html
Robert Engeln agreed to contribute with his code as a public domain contribution.
2015-02-01 22:48:20 -07:00
Kjell Hedstrom
84302edf3f hack to take care of stackdump race:wq! 2015-01-29 01:04:53 -07:00
Kjell Hedstrom
c5bb9b96d8 Finally the right sublime AstyleFormat options pointer-align:type and reference-align:type
Fixed bug with dynamic logging levels and DBUG (instead of DEBUG)
2015-01-28 12:49:36 -07:00
Kjell Hedstrom
fb30aef9e8 type issues 2015-01-28 02:58:28 -07:00
Kjell Hedstrom
f1e744c1ec type of fatal id now better handled 2015-01-28 02:54:50 -07:00
Kjell Hedstrom
a9eb7714d6 Same change as under other g2log-g3log repos, opened up for way easier change
of fatal handler
2015-01-28 02:23:34 -07:00
Kjell Hedstrom
55d91601b8 Handle that the signal type might be too big for an int if we are running on Windows
(signal is int, but exceptioncode is unsigned long)
2015-01-28 02:14:24 -07:00
Kjell Hedstrom
1329a1d807 Dynamic levels fixed ... some typo earlier. IN the main g3log on Bitbucket this typo did not exist 2015-01-28 01:04:59 -07:00
Kjell Hedstrom
265db780c3 Avoid catching shutdown-crash after catching the initial exit reason 2015-01-28 00:40:05 -07:00
Kjell Hedstrom
baa109ed89 comments 2015-01-26 21:01:32 -07:00
Kjell Hedstrom
3f39757ffc g2::installSignalHandlerForThread() added as a hook for clients to make sure that that thread is fatal signal covered
g2::internal      void setFatalExitHandler(std::function<void(FatalMessagePtr) > fatal_call); can now be used by clients
who wish to provide their own "exit handling".
2015-01-26 20:58:34 -07:00
Kjell Hedstrom
02d3812d1a Update Build.cmake 2015-01-22 02:47:38 -07:00
Kjell Hedstrom
fd8f4d9e2f REmove windows specific files for linux systems 2015-01-22 02:29:56 -07:00
Kjell Hedstrom
ac6cbd032d run more branches 2015-01-22 02:27:59 -07:00
Kjell Hedstrom
1d09bf8916 Options.cmake now instead of dynamic.cmake 2015-01-22 02:24:02 -07:00
Kjell Hedstrom
895efa35bf local include 2015-01-22 02:03:18 -07:00
Kjell Hedstrom
a5747de01a Work in progress. Now a fatal exception will cause all sinks to be flushed and then be
deleted. Then the exception will continue ... either crashing the app or will be caught in another exception handler
2015-01-22 01:54:59 -07:00
Kjell Hedstrom
2cf9c4aefe g2log levels: Now with options to use DEBUG or DBUG which can be set using cmake -DDCHANGE_G3LOG_DEBUG_TO_DBUG=ON 2015-01-21 22:46:36 -07:00
Kjell Hedstrom
3a234929e5 In progress ... reverting back to the example code make it ALL work
(in DEBUG)
2015-01-11 22:21:40 -07:00
Kjell Hedstrom
bd2b89f9de Varför fixar examplet att fa en bra stackdump MEN INTE g3log examplet???? 2015-01-11 17:02:32 -07:00
Kjell Hedstrom
05fd4632c7 so so working. the original example still works the best 2015-01-11 16:34:13 -07:00
Kjell Hedstrom
8c63adffe1 Fixed vanilla cases with stackdump 2015-01-10 23:10:06 -07:00
Kjell Hedström
1f844f5ea1 README.markdown edited online with Bitbucket 2015-01-08 06:23:05 +00:00
Kjell Hedström
1259e9e1ea README.markdown edited online with Bitbucket 2015-01-08 06:22:36 +00:00
Kjell Hedstrom
b9b58cca02 In progress. Yet to fix
1) FAtal event should have a callback because the handling is very different if
   there is a windows exception that should just continue afterwards or if
2) there is a signal
3) Special signal handling in Windows for SIGFPE and Sigsegv if done in another
   thread
2015-01-04 23:51:29 -07:00
Kjell Hedstrom
3a0cef8f50 Added the skeleton starts for namespace or class to fetch the stackdump 2015-01-04 17:53:28 -07:00
Kjell Hedstrom
936b59d9bb ongoing .... starting to add crashhandler for windows 2015-01-04 17:51:21 -07:00
KjellKod
81a7c9109d Updated travis build script to accept any g++ version
Updated the fatal choice example with informative couts
2014-12-12 02:05:51 -07:00
KjellKod
fdd3c2572a Added a multiple,choice "Choose Your Fatal Exit" example.
Next step is to add the windows g3logger fatal exit handler (POC finished)
2014-12-12 08:44:17 -07:00
Kjell Hedstrom
4d6f2f3913 test commit from gith 2014-12-11 08:29:29 -07:00
KjellKod
7e2d357a9d Nonsense change to push windows g3log changes to GitHub. KjellKod/g3log 2014-12-11 00:25:02 -07:00
kjellkod@kjellkod-Asus.hsd1.co.comcast.net.
c23a8e2419 Remove warning in Windows by using vsnprintf_s 2014-12-11 00:10:47 -07:00
KjellKod
e62eaec8f6 removed faulty lib 2014-10-12 01:02:26 -06:00
KjellKod
785a2f3ff6 iC++abi 2014-10-12 00:58:35 -06:00
KjellKod
03084d11d9 removed c++abi1 2014-10-12 00:46:23 -06:00
KjellKod
ff93adcace skip gcc for now 2014-10-12 00:43:29 -06:00
KjellKod
e29810025f what up with Clang and Travis? 2014-10-11 23:49:22 -06:00
KjellKod
fcdd40ada6 bug in travis. once the environment is restarted it does not start in the right location 2014-10-11 23:17:57 -06:00
KjellKod
008cdaade0 path is kept? 2014-10-11 23:09:26 -06:00
KjellKod
66075853b8 works for gcc but not for linux and clang? 2014-10-11 23:06:26 -06:00
KjellKod
497bd1deab moved compiler exports to build script 2014-10-11 23:00:18 -06:00
KjellKod
e49b1dc15d wrong compiler test 2014-10-11 22:49:25 -06:00
KjellKod
394f2c1bef yet another travis test 2014-10-11 22:45:04 -06:00
KjellKod
3c5c130854 don't put g++ in place when CXX is clang 2014-10-11 22:41:29 -06:00
KjellKod
b695ed3a9e unit test not running 2014-10-11 22:24:57 -06:00
KjellKod
ead70599e6 Annoying but true. dont forge the pesky ";" 2014-10-11 22:21:49 -06:00
KjellKod
3c204aa82c cannot have comments wherever in travis yml file 2014-10-11 22:18:17 -06:00
KjellKod
191acd2f47 Removed clang repo 2014-10-11 22:16:15 -06:00
KjellKod
f50b6234c9 added clang installation 2014-10-11 22:08:07 -06:00
KjellKod
c6324108e5 iCorrected errors in bash 2014-10-11 21:57:07 -06:00
KjellKod
21edd3fc05 g++ and clang but only on Linux 2014-10-11 21:36:39 -06:00
KjellKod
7c5ce707e2 fixed travis scripting 2014-10-11 20:50:32 -06:00
KjellKod
3b7f084805 Attempt to make the travis scripting easier 2014-10-11 20:46:27 -06:00
KjellKod
82e5991a7f Travis-CI and OSX attempt 2014-10-11 20:35:06 -06:00
KjellKod
752d928a63 test cleanup. attempting OSX testing on travis-ci.org
--HG--
rename : scripts/buildtravis.sh => scripts/buildAndRunTests.sh
2014-10-11 20:16:54 -06:00
KjellKod
3bc13a0fc1 Added the .hgrc to easily switch between computer.
This blog was helpful for the hg -> git conversion
http://pythonwise.blogspot.com/2012/05/using-travis-ci-with-bitbucket.html
2014-10-10 01:19:38 -06:00
KjellKod
edef25b5e1 Added all unit tests 2014-10-10 01:06:10 -06:00
KjellKod
20ab983b1a libc++ support? 2014-10-10 00:54:16 -06:00
KjellKod
8bca02d3be test to bookmark default as master automatically 2014-10-10 00:49:20 -06:00
KjellKod
56d1a94b91 Fixed script 2014-10-10 00:45:38 -06:00
KjellKod
d96f88b619 rename
--HG--
rename : scripts/travisbuild.sh => scripts/buildtravis.sh
2014-10-10 00:31:53 -06:00
KjellKod
c680e5303b travis build 2014-10-10 00:27:57 -06:00
KjellKod
7470e0a7a4 isync test 2014-10-10 00:22:32 -06:00
KjellKod
a755ab34ac fixed typowq! 2014-10-10 00:21:08 -06:00
KjellKod
0839847182 test for sync 2014-10-10 00:10:06 -06:00
KjellKod
3100978492 test gihub sync 2014-10-10 00:01:58 -06:00
KjellKod
01a3efcf7d Updated build script 2014-10-09 23:49:51 -06:00
KjellKod
c709e55b42 Updated for building and running one unit test 2014-10-09 23:41:08 -06:00
KjellKod
0b477242dd Nonsense change to see if github push works 2014-10-09 23:07:43 -06:00
KjellKod
7b718d08f8 Tiny change to see if push to GitHub/KjellKod/g3log worked 2014-10-09 23:04:01 -06:00
KjellKod
30ea3a65aa Added travis installation for gcc, and replacing the gcc (4.6) with gcc-4. 2014-10-09 23:00:06 -06:00
KjellKod
ece13751a8 Added empty travis yml file 2014-10-09 22:52:33 -06:00
KjellKod
1f071b3f6e draft of ubuntu cpack... installing into /usr/local 2014-10-09 22:04:26 -06:00
KjellKod
0e37df7162 cleanup. Use G3Log instead of G2Log for binaries and configuration files 2014-10-03 01:53:21 -06:00
KjellKod
c99b1089c2 Updated .ignore file 2014-10-03 01:22:29 -06:00
KjellKod
87a095e384 Renamed directories for a cleaner project structure
--HG--
rename : g2log/Build.cmake => Build.cmake
rename : g2log/CMakeLists.txt => CMakeLists.txt
rename : g2log/CPackLists.txt => CPackLists.txt
rename : g2log/Dynamic.cmake => Dynamic.cmake
rename : g2log/example/Example.cmake => example/Example.cmake
rename : g2log/example/main_contract.cpp => example/main_contract.cpp
rename : g2log/example/main_sigsegv.cpp => example/main_sigsegv.cpp
rename : g2log/src/active.hpp => src/active.hpp
rename : g2log/src/crashhandler.hpp => src/crashhandler.hpp
rename : g2log/src/crashhandler_unix.cpp => src/crashhandler_unix.cpp
rename : g2log/src/crashhandler_win.cpp => src/crashhandler_win.cpp
rename : g2log/src/g2filesink.cpp => src/g2filesink.cpp
rename : g2log/src/g2filesink.hpp => src/g2filesink.hpp
rename : g2log/src/g2filesinkhelper.ipp => src/g2filesinkhelper.ipp
rename : g2log/src/g2future.hpp => src/g2future.hpp
rename : g2log/src/g2log.cpp => src/g2log.cpp
rename : g2log/src/g2log.hpp => src/g2log.hpp
rename : g2log/src/g2loglevels.cpp => src/g2loglevels.cpp
rename : g2log/src/g2loglevels.hpp => src/g2loglevels.hpp
rename : g2log/src/g2logmessage.cpp => src/g2logmessage.cpp
rename : g2log/src/g2logmessage.hpp => src/g2logmessage.hpp
rename : g2log/src/g2logmessagecapture.cpp => src/g2logmessagecapture.cpp
rename : g2log/src/g2logmessagecapture.hpp => src/g2logmessagecapture.hpp
rename : g2log/src/g2logworker.cpp => src/g2logworker.cpp
rename : g2log/src/g2logworker.hpp => src/g2logworker.hpp
rename : g2log/src/g2moveoncopy.hpp => src/g2moveoncopy.hpp
rename : g2log/src/g2sink.hpp => src/g2sink.hpp
rename : g2log/src/g2sinkhandle.hpp => src/g2sinkhandle.hpp
rename : g2log/src/g2sinkwrapper.hpp => src/g2sinkwrapper.hpp
rename : g2log/src/g2time.cpp => src/g2time.cpp
rename : g2log/src/g2time.hpp => src/g2time.hpp
rename : g2log/src/shared_queue.hpp => src/shared_queue.hpp
rename : g2log/src/std2_make_unique.hpp => src/std2_make_unique.hpp
rename : g2log/src/stlpatch_future.hpp => src/stlpatch_future.hpp
rename : g2log/test_performance/Performance.cmake => test_performance/Performance.cmake
rename : g2log/test_performance/main_threaded_mean.cpp => test_performance/main_threaded_mean.cpp
rename : g2log/test_performance/main_threaded_worst.cpp => test_performance/main_threaded_worst.cpp
rename : g2log/test_performance/performance.h => test_performance/performance.h
rename : g2log/test_unit/Test.cmake => test_unit/Test.cmake
rename : g2log/test_unit/test_concept_sink.cpp => test_unit/test_concept_sink.cpp
rename : g2log/test_unit/test_configuration.cpp => test_unit/test_configuration.cpp
rename : g2log/test_unit/test_filechange.cpp => test_unit/test_filechange.cpp
rename : g2log/test_unit/test_io.cpp => test_unit/test_io.cpp
rename : g2log/test_unit/test_linux_dynamic_loaded_sharedlib.cpp => test_unit/test_linux_dynamic_loaded_sharedlib.cpp
rename : g2log/test_unit/test_sink.cpp => test_unit/test_sink.cpp
rename : g2log/test_unit/tester_sharedlib.cpp => test_unit/tester_sharedlib.cpp
rename : g2log/test_unit/tester_sharedlib.h => test_unit/tester_sharedlib.h
rename : g2log/test_unit/testing_helpers.cpp => test_unit/testing_helpers.cpp
rename : g2log/test_unit/testing_helpers.h => test_unit/testing_helpers.h
2014-10-03 01:20:33 -06:00
KjellKod
2bf3017021 BETA CPack 2014-10-03 01:04:26 -06:00
KjellKod
0f971e67b3 Updated cmake 2014-10-03 01:03:56 -06:00
KjellKod
8c89eebade renama example directory
--HG--
rename : g2log/test_example/Example.cmake => g2log/example/Example.cmake
rename : g2log/test_example/main_contract.cpp => g2log/example/main_contract.cpp
rename : g2log/test_example/main_sigsegv.cpp => g2log/example/main_sigsegv.cpp
2014-10-03 00:57:38 -06:00
KjellKod
19b17b9d94 Cleanup of cmake structure 2014-10-03 00:56:13 -06:00
KjellKod
73c6066c66 Removed obsolete gtest and Qt project file 2014-09-11 22:37:37 -06:00
KjellKod
b69d47c174 removed obsolete readme for 3rdparty 2014-09-11 22:29:50 -06:00
KjellKod
58a5fca8bd REmoved Google's performance test. If anyone is interested it can be found at g2log 2014-09-11 22:25:55 -06:00
KjellKod
0931a611ed Some test_io FATAL unit tests were memory sensitive. Added robustness by making the fatal exit message static 2014-09-02 22:59:50 -06:00
KjellKod
afb55095ce Improvement from Sean LK's pull request. The dynamic library test is still just kept for Linux and GCC 2014-09-02 22:26:17 -06:00
Sean LK
c02fe626f8 Ensure Clang and AppleClang are recognized by CMake script
As of CMake 3.0, the CMAKE_<LANG>_COMPILER_ID variable can take on two
different values for Clang: "Clang" and "AppleClang", the latter
referring to the Clang distributed by Apple with Xcode.

Therefore, update the compiler check to match CMAKE_<LANG>_COMPILER_ID
against the regular expression ".*Clang".
2014-08-29 18:31:59 +00:00
Kjell Hedström
3eb2ea5e08 README.markdown edited online with Bitbucket 2014-08-07 03:57:31 +00:00
Kjell Hedström
71791d072a README.markdown edited online with Bitbucket 2014-08-07 03:57:10 +00:00
Kjell Hedström
0eb4b28393 README.markdown edited online with Bitbucket 2014-08-07 03:56:44 +00:00
Kjell Hedström
f09747fba0 README.markdown edited online with Bitbucket 2014-08-07 03:52:16 +00:00
KjellKod
7fbdd34246 Added license and license referral to avoid any license confusion. G3log is a public domain dedication. Ref the unlicense.org 2014-07-03 15:42:19 -06:00
KjellKod
98ec05db7b Added threadID in case someone wants that. The std:🧵:id is looong. cutting it down would be nice,. but that is a job for the client 2014-05-25 01:38:03 -06:00
KjellKod
9be8f49f66 VTune performance .... from 4us on average (dual threads performance test) to 3us avarage 2014-05-25 01:09:50 -06:00
KjellKod
fafa4cf96a Added handling for the the user might have buggy adding of sinks 2014-04-29 07:47:35 -06:00
KjellKod
f0c3a43c3a spell check 2014-04-29 00:10:58 -06:00
KjellKod
c00981fad0 Bugfixes and improvments. Thanks to Csaba with team.
Bugfixes:   Initialization/Destruction order was wrong. This would cause a shutdown race condition.
Improvements:  Skipped pimpl (no hiding necessary), pointer comparison in g2log.cpp,  clarified shutdown safety with comment in ~LogWorker
Unit tests:  Added agressive shutdown test in test_sinks.cpp
2014-04-28 23:46:42 -06:00
KjellKod
e54706d77b std::formard of args in sink 2014-04-12 00:45:19 -06:00
KjellKod
33d6378e01 std::forward arguments. Actually this helped in reducing worst case performance 2014-04-12 00:18:30 -06:00
KjellKod
183a513fd0 Cleanup to help for APPLE use, both Clang and GCC 2014-03-10 23:26:05 -06:00
KjellKod
03bece5bf8 Added another sink to get even more data flow through the test 2014-03-10 23:25:38 -06:00
KjellKod
33106756ec Corrected include 2014-03-09 00:47:09 -07:00
KjellKod
f5438d8232 Thanks to Rajesh to push for g3log support for "runtime loading of dynamic libraries" (that will use g3log, initiated in main)
Thanks to Dmitry (d-led) for this working proof-of-concept of this at: https://github.com/d-led/g2log-dll

--HG--
rename : g2log/src/g2LogMessageBuilder.cpp => g2log/src/g2logmessagecapture.cpp
rename : g2log/src/g2LogMessageBuilder.hpp => g2log/src/g2logmessagecapture.hpp
2014-03-08 23:33:49 -07:00
KjellKod
0bfd6cb97b Readme. fixup 2014-02-25 23:18:18 -07:00
KjellKod
9fa3acf2cb Readme. Build instructions 2014-02-25 23:16:59 -07:00
KjellKod
77653a1d3b Updated REAME. Tested with Clang 2014-02-25 23:14:50 -07:00
kjell@kjell-win7.hsd1.co.comcast.net.
ebc8ae22b7 VS2013: removed warnings 2014-02-26 07:00:08 +01:00
KjellKod
8220839771 Clang/Gcc bugfix:
Fixed g2logworker destructor race condition. Sinks and background thread were not cleared in the right order.
Now the order is enforced.

This means that g3log should work fine with Clang. CMakeLists.txt is updated to reflect the Clang support
2014-02-25 22:05:48 -07:00
KjellKod
a5765af28d Added gtest 1.7,. but will keep gtest 1.6 for now as well in case of issues with older compilers 2014-02-25 22:03:45 -07:00
KjellKod
59269ec351 Removed vs2013 warning. Previously the exception was ignored. 2014-02-24 00:29:50 -07:00
KjellKod
40a6e99bc0 Work around for bug in VS2013. Reported here: http://www.beta.microsoft.com/VisualStudio/feedback/details/757472/c-concurrency-task-and-std-bind
"auto" did not cut it apparently.
2014-02-24 00:23:43 -07:00
KjellKod
956da51317 Thanks to Aleksey Dobrunov who noticed this compile error. Weird that it did not show up in gcc 2014-02-24 00:21:57 -07:00
KjellKod
1ed4bcb38c Bugfix: sinkhandle can now be used to call, asynchronously, functions with more return types than std::string 2014-02-11 20:00:20 -07:00
KjellKod
ffb4d86c1e Improvement: Shutdownlogging is now called AUTOMATICALLY at LogWorker scope exit/destruction. If for some reason (mistake or unit testing) multiple LogWorkers are created then
only the one that is g2::initialized(...) can cause a shutDownLogging when it is destructed.
2014-02-02 23:49:24 -07:00
KjellKod
02543e817a VS2013 must be used, 2014-01-28 09:19:58 -07:00
KjellKod
0c1845ee18 Avoid premature wakeup from reader thread by doing the notify AFTER the mutex is released
http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html
2014-01-24 13:17:10 -07:00
KjellKod
63616d2acd performance increase by using internal unique_ptr for the sink instead of shared_pointer.
Better average (10-15%), and much, much, much better worst case
2014-01-19 22:55:44 -07:00
kjell@kjell-win7.hsd1.co.comcast.net.
d0045de73b spell check 2014-01-17 09:06:11 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
460f16d5f4 text 2014-01-17 09:01:28 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
82095de062 code examples 2014-01-17 08:47:01 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
f3388a66df ... 2014-01-17 08:46:15 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
e558d3baed code example of handle 2014-01-17 08:45:12 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
c772785e2a Explanation of how to call a sink through handler 2014-01-17 08:44:00 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
9be95044ef formatting 2014-01-17 08:26:38 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
ba6d1856a5 formatting 2014-01-17 08:25:38 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
f5c89d67b6 explanation of sinks 2014-01-17 08:24:35 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
3abf46b336 formatting 2014-01-17 08:20:14 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
c995f4e8a6 markup bugfix 2014-01-17 08:17:18 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
82cc712fca fDraft of finished readme now that the sinks examples are in 2014-01-17 08:15:40 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
3b34da51db Added code example on how to use sinks 2014-01-17 08:04:51 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
342c8aefff fixing up. introduction 2014-01-17 07:34:53 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
cc554ff2cc comment fix 2014-01-14 07:18:38 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
9df4fbd99c constexpr and static_assert when NOT on MSVC. #ifdef workaround for MSVC 2014-01-14 07:10:26 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
9f015b4216 Performance fix: g2time return string without unnecessary (old) stream buffering 2014-01-14 07:07:00 +01:00
KjellKod
1ac2e9070e Thanks to Aleksey Dobrunov: Improvement by making all raw data in the g2logmessage public
Added explaining comments to g2logmessage
2014-01-10 09:18:27 -07:00
KjellKod
cb7c0f8ac5 less junk in status check 2014-01-08 22:59:28 -07:00
KjellKod
5486bbceca Dynamic logging levels can be enabled with a define. All levels are by default ON 2014-01-08 22:48:18 -07:00
Aleksey Dobrunov
beff32d718 mingw build 2013-12-30 13:44:32 +06:00
KjellKod
916f478267 Updated performance test in case all "buckets" hits would be in the 0ms bucket then it is shown in us instead 2013-12-28 14:58:22 -07:00
kjell@kjell-win7.hsd1.co.comcast.net.
e850c33354 pragma remove 2013-12-28 20:52:46 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
c2b328bfe8 comment and pragma cleanup 2013-12-28 20:46:56 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
913208bba8 part of previous commit (missed description)
stlpatch to make vs2013 work with packaged_task<void()>.
Thanks to Michael Rasmussen (lap777).
Ref: http://connect.microsoft.com/VisualStudio/feedback/details/791185/std-packaged-task-t-where-t-is-void-or-a-reference-class-are-not-movable
2013-12-28 20:42:50 +01:00
kjell@kjell-win7.hsd1.co.comcast.net.
a522c219ce cleaned up time use 2013-12-28 20:39:12 +01:00
KjellKod
2e5d323b52 Input from Gem Chen triggerd review of shared_queue (now made clearer) and active.hpp (now all header file) 2013-12-19 23:47:31 -07:00
KjellKod
74963e13f1 Bugfix: stackdump not called at the right place for failed contracts and LOG(FATAL) 2013-12-19 22:55:10 -07:00
KjellKod
c847ee037f removed old fatal test 2013-12-19 22:52:09 -07:00
KjellKod
8d9f1bfea2 split FATAL examples into a SIGSEGV and a CONTRACT examplew 2013-12-19 22:51:47 -07:00
KjellKod
726bdb369a using wiki syntax
--HG--
rename : README => README.markdown
2013-12-17 23:38:52 -07:00
KjellKod
f61af5529c Updated README... still in progress 2013-12-17 23:37:12 -07:00
KjellKod
8f7db77177 crashhandler_unix now with support for OSX/Clang 2013-12-15 22:44:53 -07:00
Kjell Hedström
6efdaf9d47 Merged tip into default 2013-12-15 22:32:01 -07:00
Kjell Hedström
fcaf0c0217 Close branch merge
--HG--
branch : merge
extra : close : True
2013-12-15 22:31:37 -07:00
KjellKod
fe4862a96b Cleanup, added headers where they were missing. Removed default option ON for unit test. 2013-12-15 22:29:26 -07:00
KjellKod
507ec52c04 merging heads 2 of 2
--HG--
rename : g2log/src/g2sinkhandle.h => g2log/src/g2sinkhandle.hpp
2013-12-15 22:17:06 -07:00
KjellKod
97a6492d81 merging heads 1 of 2 2013-12-15 22:16:32 -07:00
KjellKod
d5ec3424e5 Renaming, moving from .h to .hpp. Should not affect API, mostly internal stuff
--HG--
rename : g2log/src/g2future.h => g2log/src/g2future.hpp
rename : g2log/src/g2sink.h => g2log/src/g2sink.hpp
rename : g2log/src/g2sinkhandle.h => g2log/src/g2sinkhandle.hpp
rename : g2log/src/g2sinkwrapper.h => g2log/src/g2sinkwrapper.hpp
rename : g2log/src/shared_queue.h => g2log/src/shared_queue.hpp
2013-12-15 22:13:43 -07:00
Aleksey Dobrunov
c2ba2546bb fix unit tests 2013-12-14 02:58:36 +06:00
Aleksey Dobrunov
f3dda737ed fix build program that uses g2log 2013-12-14 02:50:29 +06:00
Aleksey Dobrunov
781b1c1b5e add build target for mingw 2013-12-14 01:39:50 +06:00
Aleksey Dobrunov
768f6a3ae5 fix warning in CMakeLists.txt 2013-12-14 01:39:03 +06:00
Aleksey Dobrunov
e35a9df89f fix crashhandler for windows 2013-12-14 01:12:35 +06:00
Aleksey Dobrunov
570a2d8f10 fix colon in log path 2013-12-14 01:07:07 +06:00
Aleksey Dobrunov
c76f2fc5bd fix time for mingw 2013-12-14 01:04:28 +06:00
KjellKod
aeadc490b1 Thanks to Rui Pacheco. Bugfix: could occurr if logger was initialized, had "shutownlogging" and then a fatal signal occurred 2013-12-13 08:36:45 -07:00
KjellKod
68e3d2f1a5 showing worst times in ms and us 2013-12-10 15:29:43 -07:00
KjellKod
f8c729ce1e dynamic logging levels are now possible. Use "#define G2_DYNAMIC_LOGGING" to get it. A slight performance penalty will result
but logging levels can then be turn on/off dynamically
2013-12-10 14:57:04 -07:00
KjellKod
340c4ac1d5 Fixed compile error for gcc 4.7.3 2013-12-10 10:46:27 -07:00
KjellKod
7de3c5fe78 merging heads
--HG--
branch : merge
2013-12-10 10:36:21 -07:00
KjellKod
8da7e44cd0 slight performance increase 2013-11-23 13:42:03 -07:00
kjell@kjell-win7.hsd1.co.comcast.net.
84f5dddc69 msbuild detected issues (ms only?) 2013-11-23 09:12:00 +01:00
KjellKod
c28593e87e Even faster. Using internal MoveOnCopy struct-wrapper. 2013-11-15 02:02:30 -07:00
KjellKod
889145453d Updated ... performance testing in purpose. 2x1million takes 18seconds to disk. average API calls 7us, average API call and bg disk write 9us
--HG--
rename : g2log/src/g2pretendtobecopyable.hpp => g2log/src/g2moveoncopy.hpp
2013-11-14 22:27:03 -07:00
KjellKod
e430a40884 printout if dynamic level is enabled or not 2013-11-13 01:19:33 -07:00
KjellKod
54925d3ba2 Forg 2013-11-13 01:03:42 -07:00
KjellKod
b1ed735d39 Speedup. Inline functions and toString uses string and not ostringstream 2013-11-12 03:37:36 -07:00
KjellKod
2ba9d6187c All unit test working. Next step is to increase performance even more 2013-11-12 02:45:09 -07:00
KjellKod
61af55e335 (after 1 day of lost work)... recreating-work in progress. some unit test are still failing. Using unique_ptr for spee 2013-11-12 02:21:40 -07:00
KjellKod
11235acbc9 Removing g2logmessage pimpl 2013-11-11 23:07:34 -07:00
KjellKod
43806018aa TODO: Remove all usage of shared_ptr,. passing with moved unique_ptr and by value will have a huge performance boost 2013-11-08 02:47:43 -07:00
KjellKod
05dd7c9018 Performance testing. Left to tweak performance to get close to g2log original speed 2013-11-08 02:31:32 -07:00
KjellKod
ac2915da1f All unit tests are working after cleanup 2013-11-08 01:45:10 -07:00
KjellKod
ad322fd460 Updated. LOG(...) calls to uninizialized logger does not make it crash 2013-11-07 01:56:48 -07:00
KjellKod
99ea2e3f19 Updated unit test to deal with LogMessage. Using just string as default would trigger LogMessage::toString() 2013-11-04 22:15:44 -07:00
KjellKod
225c16313d All compile errors fixed. After refactoring/remodelling. Left is touching up the unit tests 2013-11-03 21:46:19 -07:00
KjellKod
a69286399d compile error: namespace usage or lack thereof 2013-11-02 21:04:44 -06:00
KjellKod
81b6b91038 fixing compile errors after large conceptual remake 2013-11-02 10:01:18 -06:00
KjellKod
4adbd1c065 compile error fixes after major g2log-dev influence-refactoring 2013-10-31 03:28:08 -06:00
KjellKod
a59c837fd2 Dynamic sinks... all unit test working (although they should be consolidated). name-file manual merge from g2log-dev 2013-10-04 22:14:35 -06:00
KjellKod
ad998db248 Renameing. Reformatting crashhandler for c++11 2013-09-25 21:59:28 -06:00
KjellKod
e0355e766a active using lambda instead of std::function for exit. Cleanup of includes. Renamed to hpp
--HG--
rename : g2log/src/active.h => g2log/src/active.hpp
2013-09-25 21:39:11 -06:00
KjellKod
49aefe06f5 Universal copy constructor 2013-09-15 14:24:12 -06:00
KjellKod
e2af025563 All unit tests are passing. Seg fault was in unit test, not in code
Next: Cleanup namespace and creation
Next Next: Cleanup/Refactor message sending
2013-09-01 00:44:30 -06:00
KjellKod
e237f5a8fa narrowing down the errors§ 2013-08-30 00:01:07 -06:00
KjellKod
60af9ac1ca Added crashing unit test for next time debugging
--HG--
rename : g2log/test_unit/test_sink_concept.cpp => g2log/test_unit/test_concept_sink.cpp
2013-08-20 23:40:39 -06:00
KjellKod
d254879890 Generic cleanup and bugfix after massive merge... still ongoing
--HG--
rename : g2log/test_unit/test_sink.cpp => g2log/test_unit/test_sink_concept.cpp
2013-08-18 23:18:18 -06:00
KjellKod
17cf2ee910 Added simple test for sinks 2013-08-18 23:17:46 -06:00
KjellKod
bb778adf25 Cleanup 2013-08-18 23:17:04 -06:00
KjellKod
f4c939dc8a Corrected lambda bug. Capture this. 2013-08-18 23:15:56 -06:00
KjellKod
b490624ea0 Removed race condition with destruction and cleaning up sinks.
Using string instead of stream
2013-08-18 23:15:09 -06:00
KjellKod
8a36ef87ea Speedup. using string instead of stream 2013-08-18 23:13:18 -06:00
KjellKod
1aaa79fb3f compile errors fixed. multiple start/stop of logger fails 2013-08-01 23:06:12 -06:00
KjellKod
ab07e5978d Corrected the merging compile errors...
--HG--
rename : g2log/src/crashhandler.h => g2log/src/crashhandler.hpp
rename : g2log/src/g2logmessage.h => g2log/src/g2logmessage.hpp
rename : g2log/src/g2time.h => g2log/src/g2time.hpp
2013-07-29 22:43:33 -06:00
KjellKod
05018e389a commented out some unit test. corrected other's. rigth now I am pondering to
always keeping the file-handle known in the bglogger.
--- Alternatively there is no zink at startup except colored out maybe?
2013-07-23 22:01:12 -06:00
KjellKod
3c67023389 Internal for sinks added. Simple unit test added 2013-07-21 14:04:48 -06:00
KjellKod
301f2df05b made it compile by commenting away. let if fail! 2013-07-13 23:06:30 -06:00
KjellKod
6c3f58086d adding first failing test to test_sink 2013-07-13 22:59:02 -06:00
KjellKod
c015191b83 unit test refactoring. g2log, safe to do shutdownlogging multiple times 2013-07-13 19:33:00 -06:00
KjellKod
3e2f092924 adding unit test + make_unique 2013-07-13 17:57:26 -06:00
KjellKod
3fb37b0709 cmake refactoring , adding of unit tests 2013-07-13 17:56:38 -06:00
KjellKod
062b92188c refactored cmake 2013-07-13 10:21:00 -06:00
KjellKod
12dfc91458 Bugfix: Thanks to Alexander Ignatyev. Now handles illegal, empty directory names.
Bugfix: If directory path cannot be resolved it will as a last resort write the log to the current directory
2013-07-11 23:22:40 -06:00
kjellkod@kjellkod-Asus
68d1c12858 Thanks to Wilfred van Velzen for adding fix for mingw / windows 2013-06-05 12:19:52 -04:00
kjellkod@kjellkod-Asus
84d625c8cc Correction. SanityFix for illegally written path
thanks to 'Tim L' at CodeProject/g2log
2013-05-09 11:32:25 -04:00
KjellKod
1011af308a prefixsanityfix... better handling of illegal character and their removal from file name 2012-11-19 21:10:55 +01:00
KjellKod
4a481acc6e updated after merge (no changes) 2012-10-21 18:42:18 +02:00
KjellKod
75ecece72f no longer default: g2log unit test 2012-10-21 18:38:05 +02:00
KjellKod
8f808f04ec README first-user improved 2012-10-18 16:10:26 +02:00
KjellKod
eb6e7faef5 spell check REAME 2012-10-18 16:10:17 +02:00
KjellKod
8d9e4984e9 README first-user improved 2012-10-18 16:06:58 +02:00
KjellKod
60a1244850 spell check REAME 2012-10-18 16:05:34 +02:00
KjellKod
03174baddb spell check REAME 2012-10-18 15:58:11 +02:00
KjellKod
8e72da9740 spell check REAME 2012-10-18 15:52:08 +02:00
KjellKod
d57080dbd6 readme updated 2012-10-18 07:45:34 +02:00
KjellKod
b5fc2dcd1a readme finished 2012-10-18 07:44:53 +02:00
KjellKod
1d75316cf8 readme test wiki formatting 2012-10-18 07:42:11 +02:00
KjellKod
06688ea16b readme line-wrap (naive) 2012-10-18 07:40:49 +02:00
KjellKod
1c2ec0788a readme line-wrap (naive) 2012-10-18 07:39:21 +02:00
KjellKod
dbeb4c5780 readme update 2012-10-18 07:35:09 +02:00
KjellKod
4529eb058f Added tag version-1.0 for changeset d9a55a4a6154 2012-10-17 07:25:55 +02:00
127 changed files with 10713 additions and 3130 deletions

83
.clang-format Normal file
View File

@ -0,0 +1,83 @@
# Google C/C++ Code Style settings
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
# Author: Kehan Xue, kehan.xue (at) gmail.com
Language: Cpp
BasedOnStyle: Google
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: None
AlignOperands: Align
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: Never # To avoid conflict, set this "Never" and each "if statement" should include brace when coding
AllowShortLambdasOnASingleLine: Inline
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
PackConstructorInitializers: Never
BreakBeforeBraces: Attach
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterStruct: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
BreakInheritanceList: BeforeColon
ColumnLimit: 0
CompactNamespaces: false
ContinuationIndentWidth: 3
Cpp11BracedListStyle: true
DerivePointerAlignment: false # Make sure the * or & align on the left
EmptyLineBeforeAccessModifier: LogicalBlock
FixNamespaceComments: true
IncludeBlocks: Preserve
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 3
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PointerAlignment: Left
ReflowComments: false
# SeparateDefinitionBlocks: Always # Only support since clang-format 14
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: c++11
TabWidth: 3
UseTab: Never

19
.devcontainer/Dockerfile Normal file
View File

@ -0,0 +1,19 @@
# Latest Debian
FROM mcr.microsoft.com/devcontainers/cpp:debian
ARG REINSTALL_CMAKE_VERSION_FROM_SOURCE="none"
# Optionally install the cmake for vcpkg
COPY ./reinstall_cmake.sh /tmp/
RUN if [ "${REINSTALL_CMAKE_VERSION_FROM_SOURCE}" != "none" ]; then \
chmod +x /tmp/reinstall_cmake.sh && /tmp/reinstall_cmake.sh ${REINSTALL_CMAKE_VERSION_FROM_SOURCE}; \
fi \
&& rm -f /tmp/reinstall_cmake.sh
# [Optional] Uncomment this section to install additional vcpkg ports.
# RUN su vscode -c "${VCPKG_ROOT}/vcpkg install <your-port-name-here>"
# [Optional] Uncomment this section to install additional packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>

View File

@ -0,0 +1,34 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/cpp
{
"name": "C++",
"build": {
"dockerfile": "Dockerfile"
},
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
"settings": {},
"extensions": [
"streetsidesoftware.code-spell-checker",
"genieai.chatgpt-vscode",
"ms-vscode.cpptools-extension-pack",
"ms-vscode.cpptools"
]
}
}
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "gcc -v",
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}

View File

@ -0,0 +1,60 @@
#!/usr/bin/env bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
#
# testing, unsure if it's needed. following steps from example: https://github.com/microsoft/vscode-remote-try-cpp/tree/main/.devcontainer
set -e
CMAKE_VERSION=${1:-"none"}
if [ "${CMAKE_VERSION}" = "none" ]; then
echo "No CMake version specified, skipping CMake reinstallation"
exit 0
fi
# Cleanup temporary directory and associated files when exiting the script.
cleanup() {
EXIT_CODE=$?
set +e
if [[ -n "${TMP_DIR}" ]]; then
echo "Executing cleanup of tmp files"
rm -Rf "${TMP_DIR}"
fi
exit $EXIT_CODE
}
trap cleanup EXIT
echo "Installing CMake..."
apt-get -y purge --auto-remove cmake
mkdir -p /opt/cmake
architecture=$(dpkg --print-architecture)
case "${architecture}" in
arm64)
ARCH=aarch64 ;;
amd64)
ARCH=x86_64 ;;
*)
echo "Unsupported architecture ${architecture}."
exit 1
;;
esac
CMAKE_BINARY_NAME="cmake-${CMAKE_VERSION}-linux-${ARCH}.sh"
CMAKE_CHECKSUM_NAME="cmake-${CMAKE_VERSION}-SHA-256.txt"
TMP_DIR=$(mktemp -d -t cmake-XXXXXXXXXX)
echo "${TMP_DIR}"
cd "${TMP_DIR}"
curl -sSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_BINARY_NAME}" -O
curl -sSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_CHECKSUM_NAME}" -O
sha256sum -c --ignore-missing "${CMAKE_CHECKSUM_NAME}"
sh "${TMP_DIR}/${CMAKE_BINARY_NAME}" --prefix=/opt/cmake --skip-license
ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake

19
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,19 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: under investigation
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
- What system, compiler etc was used to run this?
- Is something done differently on your setup than what the documentation specifies?
- Have you provided a code snippet that can be tested?
**Additional context**
Add any other context about the problem here.

View File

@ -0,0 +1,21 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
Keep in mind that g3log is community driven. Do you want to take on the feature work yourself, or do you want someone else to take it on? The latter will require a whole lot more "selling". If you want to drive it yourself you can likely get community feedback on your idea + definitely great code reviews.
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

20
.github/ISSUE_TEMPLATE/question.md vendored Normal file
View File

@ -0,0 +1,20 @@
---
name: Question
about: Question to the community, request for help to troubleshoot or undersand
title: "[Question]"
labels: question
assignees: ''
---
### Uncertain what's going on? Do you need advice or help troubleshooting?
A clear and concise description of what the problem is.
### Describe the solution you'd like
A clear and concise description of what you want to happen.
### Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
### Additional context
Add any other context or screenshots that might help.

49
.github/workflows/buildAndRunTests.yml vendored Normal file
View File

@ -0,0 +1,49 @@
name: ci/action ctest Ubuntu v3
on:
push:
paths-ignore:
- docs/**
- '**.md'
- '**.markdown'
- '**.yml'
branches: [ master ]
pull_request:
paths-ignore:
- docs/**
- '**.md'
- '**.markdown'
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Print env
run: |
echo github.event.action: ${{ github.event.action }}
echo github.event_name: ${{ github.event_name }}
gcc --version
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install ninja-build cmake gcc-9 g++-9
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 90 --slave /usr/bin/g++ g++ /usr/bin/g++-9 --slave /usr/bin/gcov gcov /usr/bin/gcov-9
echo gcc version after
gcc --version
cmake --version
# example: https://gist.github.com/NickNaso/0d478f1481686d5bcc868cac06620a60
- name: configure
shell: bash
# run: ./configure
run: ./scripts/buildAndRunTests.sh
#- name: make
# run: make
#- name: make check
# run: make check
#- name: make distcheck
# run: make distcheck

76
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@ -0,0 +1,76 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "ci/action CodeQL"
on:
push:
paths-ignore:
- docs/**
- '**.md'
- '**.markdown'
- '**.yml'
branches: [ master ]
pull_request:
paths-ignore:
- docs/**
- '**.md'
- '**.markdown'
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '17 8 * * 2'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'cpp' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'cmake' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v3
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

87
.github/workflows/ctest.yml vendored Normal file
View File

@ -0,0 +1,87 @@
name: matrix (ubuntu, macos, windows) ctes
on:
push:
paths-ignore:
- docs/**
- "**.md"
- "**.markdown"
branches:
- master
pull_request:
paths-ignore:
- docs/**
- "**.md"
- "**.markdown"
- '**.yml'
branches:
- master
env:
BUILD_TYPE: Release
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
strategy:
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
# checkout full depth of history.
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run Linux Build
if: matrix.os == 'ubuntu-latest'
run: echo "Ubuntu Latest" > release_ubuntu
- name: Run Mac Build
if: matrix.os == 'macos-latest'
run: echo "MacOS Latest" > release_mac
- name: Run Windows Build
if: matrix.os == 'windows-latest'
run: echo "Windows Latest" > release_windows
- name: Create Build Environment
run: cmake -E make_directory ${{github.workspace}}/build
- name: Configure Linux/OSX CMake
if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'
shell: bash
working-directory: ${{github.workspace}}/build
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DADD_G3LOG_UNIT_TEST=ON
- name: Configure Windows CMake
if: matrix.os == 'windows-latest'
shell: cmd
working-directory: ${{github.workspace}}/build
run: ls && cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DADD_G3LOG_UNIT_TEST=ON ..
- name: Build Linux/OSx
working-directory: ${{github.workspace}}/build
shell: bash
run: cmake --build . --config $BUILD_TYPE
- name: Test
working-directory: ${{github.workspace}}/build
shell: bash
run: ctest -V
- name: Fatal Exit Example Linux/OSX
working-directory: ${{github.workspace}}/build
if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'
shell: bash
run: ./g3log-FATAL-sigsegv || true && echo -e
"\n\nverifying SIGSEGV existed in stackdump\n\n\n\n" && cat /tmp/*3log*FATAL*.log && cat /tmp/g3log*FATAL*.log | grep "SIGSEGV"
- name: Fatal Exit Example Windows
working-directory: ${{github.workspace}}/build
if: matrix.os == 'windows-latest'
shell: bash
run: ./Release/g3log-FATAL-sigsegv.exe || true && echo -e "\n\nverifying SIGSEGV - EXCEPTION_ACCESS_VIOLATION existed in
stackdump\n\n\n\n" && cat *3log*FATAL*.log && cat *3log*FATAL*.log | grep "EXCEPTION_ACCESS_VIOLATION"

31
.github/workflows/documentation.yml vendored Normal file
View File

@ -0,0 +1,31 @@
# Locally you can try this out also with `mkdocs serve`
# Remember if doing changes that github pages, need to deploy branch gh_pages
# which points to root.
name: Dockumentation Publish v2
on:
push:
branches:
- master
permissions:
contents: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure Git Credentials
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
- uses: actions/setup-python@v5
with:
python-version: 3.x
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- uses: actions/cache@v4
with:
key: mkdocs-material-${{ env.cache_id }}
path: .cache
restore-keys: |
mkdocs-material-
- run: pip install mkdocs-material
- run: mkdocs gh-deploy --force

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
syntax: glob
sinks/*
build/*
nbproject/*
build_clang
build_travis
gtest-1.7.0
*~

12
.hgrc_copy Normal file
View File

@ -0,0 +1,12 @@
[paths]
default = https://bitbucket.org/KjellKod/g3log
[extensions]
hgext.bookmarks =
hggit =
[paths]
github = git+ssh://git@github.com/KjellKod/g3log.git
[hooks]
outgoing = hg bookmark -r default master || true && hg push github || true

1
.hgtags Normal file
View File

@ -0,0 +1 @@
d9a55a4a615449b8eb50ed6208e3dcaf1c678d7e version-1.0

13
.vscode/easycode.ignore vendored Normal file
View File

@ -0,0 +1,13 @@
node_modules/
dist/
vendor/
cache/
.*/
*.min.*
*.test.*
*.spec.*
*.bundle.*
*.bundle-min.*
*.*.js
*.*.ts
*.log

23
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,23 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
// Remember to build the specific part of cmake with
// mkdir build; cd build
// "cmake -DCMAKE_BUILD_TYPE=Debug .. " if you want to be able to debug it.
// don't forget to inspect the cmake output for more configuration options
"configurations": [
{
"name": "(lldb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/test_signal",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "lldb"
}
]
}

7
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
"cmake.configureOnOpen": false,
"editor.formatOnSave": true,
"files.associations": {
"ostream": "cpp"
}
}

2
3rdParty/README vendored
View File

@ -1,2 +0,0 @@
Well, you can download glog and install it yourself. I just provided this for convenience
--- KjellKod

Binary file not shown.

View File

@ -1,66 +0,0 @@
#-------------------------------------------------
#
# Project created by QtCreator 2011-07-01T10:35:00
#
#-------------------------------------------------
QT -= core
TARGET = 3rdparty_gtest
TEMPLATE = lib
CONFIG += staticlib
CONFIG += create_prl
CONFIG += link_prl
builddir = ../../build
DESTDIR = $$builddir
# specify builddir BEFORE include make-settings.pri
! include( ../../make-test-settings.pri ) {
error( Couldn't find the make-test-settings.pri file! )
}
GTEST_DIR = gtest-1.6.0__stripped
GTEST_INCLUDE = $$GTEST_DIR/include
GTEST_INCLUDE_DIR = $$GTEST_DIR/include/gtest
GTEST_SRC_DIR = $$GTEST_DIR/src
HEADERS = $$GTEST_INCLUDE_DIR/gtest-death-test.h \
$$GTEST_INCLUDE_DIR/gtest.h \
$$GTEST_INCLUDE_DIR/gtest-message.h \
$$GTEST_INCLUDE_DIR/gtest-param-test.h \
$$GTEST_INCLUDE_DIR/gtest-param-test.h.pump \
$$GTEST_INCLUDE_DIR/gtest_pred_impl.h \
$$GTEST_INCLUDE_DIR/gtest-printers.h \
$$GTEST_INCLUDE_DIR/gtest_prod.h \
$$GTEST_INCLUDE_DIR/gtest-spi.h \
$$GTEST_INCLUDE_DIR/gtest-test-part.h \
$$GTEST_INCLUDE_DIR/gtest-typed-test.h
# Add internals to headers
HEADERS += $$GTEST_INCLUDE_DIR/internal/gtest-death-test-internal.h \
$$GTEST_INCLUDE_DIR/internal/gtest-filepath.h \
$$GTEST_INCLUDE_DIR/internal/gtest-internal.h \
$$GTEST_INCLUDE_DIR/internal/gtest-linked_ptr.h \
$$GTEST_INCLUDE_DIR/internal/gtest-param-util-generated.h \
$$GTEST_INCLUDE_DIR/internal/gtest-param-util-generated.h.pump \
$$GTEST_INCLUDE_DIR/internal/gtest-param-util.h \
$$GTEST_INCLUDE_DIR/internal/gtest-port.h \
$$GTEST_INCLUDE_DIR/internal/gtest-string.h \
$$GTEST_INCLUDE_DIR/internal/gtest-tuple.h \
$$GTEST_INCLUDE_DIR/internal/gtest-tuple.h.pump \
$$GTEST_INCLUDE_DIR/internal/gtest-type-util.h \
$$GTEST_INCLUDE_DIR/internal/gtest-type-util.h.pump
SOURCES = $$GTEST_SRC_DIR/gtest-all.cc \
$$GTEST_SRC_DIR/gtest.cc \
$$GTEST_SRC_DIR/gtest-death-test.cc \
$$GTEST_SRC_DIR/gtest-filepath.cc \
# $$GTEST_SRC_DIR/gtest-internal-inl.h \
$$GTEST_SRC_DIR/gtest_main.cc \
$$GTEST_SRC_DIR/gtest-port.cc \
$$GTEST_SRC_DIR/gtest-printers.cc \
$$GTEST_SRC_DIR/gtest-test-part.cc \
$$GTEST_SRC_DIR/gtest-typed-test.cc
INCLUDEPATH += $${GTEST_INCLUDE}
INCLUDEPATH += $${GTEST_DIR}

Binary file not shown.

173
Build.cmake Normal file
View File

@ -0,0 +1,173 @@
# g3log is a KjellKod Logger
# 2015 @author Kjell Hedström, hedstrom@kjellkod.cc
# ==================================================================
# 2015 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own
# risk and comes with no warranties.
#
# This code is yours to share, use and modify with no strings attached
# and no restrictions or obligations
# ===================================================================
# GENERIC STEPS
SET(LOG_SRC ${g3log_SOURCE_DIR}/src)
file(GLOB SRC_FILES ${LOG_SRC}/*.cpp ${LOG_SRC}/*.ipp)
file(GLOB HEADER_FILES ${LOG_SRC}/g3log/*.hpp)
list( APPEND HEADER_FILES ${GENERATED_G3_DEFINITIONS} )
list( APPEND SRC_FILES ${GENERATED_G3_DEFINITIONS} )
IF (MSVC OR MINGW)
list(REMOVE_ITEM SRC_FILES ${LOG_SRC}/crashhandler_unix.cpp)
ELSE()
list(REMOVE_ITEM SRC_FILES ${LOG_SRC}/crashhandler_windows.cpp ${LOG_SRC}/g3log/stacktrace_windows.hpp ${LOG_SRC}/stacktrace_windows.cpp)
ENDIF (MSVC OR MINGW)
set(SRC_FILES ${SRC_FILES} ${SRC_PLATFORM_SPECIFIC})
# Create the g3log library
SET(G3LOG_LIBRARY g3log)
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
message("CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
IF( NOT CMAKE_INSTALL_PREFIX)
SET(CMAKE_INSTALL_PREFIX /usr/local)
ENDIF()
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX})
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
message("Install rpath location: ${CMAKE_INSTALL_RPATH}")
ENDIF()
IF( G3_SHARED_LIB )
IF( WIN32 )
IF(NOT(${CMAKE_VERSION} VERSION_LESS "3.4"))
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
ELSE()
message( FATAL_ERROR "Need CMake version >=3.4 to build shared windows library!" )
ENDIF()
ENDIF()
ADD_LIBRARY(${G3LOG_LIBRARY} SHARED ${SRC_FILES})
ELSE()
IF(MSVC)
IF(NOT G3_SHARED_RUNTIME)
SET(CompilerFlags
CMAKE_CXX_FLAGS
CMAKE_CXX_FLAGS_DEBUG
CMAKE_CXX_FLAGS_RELEASE
CMAKE_C_FLAGS
CMAKE_C_FLAGS_DEBUG
CMAKE_C_FLAGS_RELEASE
)
foreach(CompilerFlag ${CompilerFlags})
string(REPLACE "/MDd" "/MTd" ${CompilerFlag} "${${CompilerFlag}}")
string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
endforeach()
ENDIF()
ENDIF()
ADD_LIBRARY(${G3LOG_LIBRARY} STATIC ${SRC_FILES})
ENDIF()
SET(${G3LOG_LIBRARY}_VERSION_STRING ${VERSION})
MESSAGE( STATUS "Creating ${G3LOG_LIBRARY} VERSION: ${VERSION}" )
MESSAGE( STATUS "Creating ${G3LOG_LIBRARY} SOVERSION: ${MAJOR_VERSION}" )
SET_TARGET_PROPERTIES(${G3LOG_LIBRARY} PROPERTIES
LINKER_LANGUAGE CXX
OUTPUT_NAME g3log
CLEAN_DIRECT_OUTPUT 1
SOVERSION ${MAJOR_VERSION}
VERSION ${VERSION}
)
IF(APPLE)
SET_TARGET_PROPERTIES(${G3LOG_LIBRARY} PROPERTIES MACOSX_RPATH TRUE)
ENDIF()
# require here some proxy for c++14/c++17? standard to avoid problems TARGET_PROPERTY CXX_STANDARD
TARGET_COMPILE_FEATURES(${G3LOG_LIBRARY} PUBLIC cxx_variable_templates)
TARGET_INCLUDE_DIRECTORIES(${G3LOG_LIBRARY}
PUBLIC
$<BUILD_INTERFACE:${LOG_SRC}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
)
SET(ACTIVE_CPP0xx_DIR "Release")
# find corresponding thread lib (e.g. whether -lpthread is needed or not)
FIND_PACKAGE(Threads REQUIRED)
TARGET_LINK_LIBRARIES(${G3LOG_LIBRARY} Threads::Threads )
# check for backtrace and cxa_demangle only in non-Windows dev environments
IF(NOT(MSVC OR MINGW))
# the backtrace module does not provide a modern cmake target
FIND_PACKAGE(Backtrace REQUIRED)
if(Backtrace_FOUND)
TARGET_INCLUDE_DIRECTORIES(${G3LOG_LIBRARY} PRIVATE ${Backtrace_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(${G3LOG_LIBRARY} ${Backtrace_LIBRARIES})
else()
message( FATAL_ERROR "Could not find Library to create backtraces")
endif()
INCLUDE(CheckLibraryExists)
INCLUDE(CheckCXXSymbolExists)
#if demangle is in c++ runtime lib
CHECK_CXX_SYMBOL_EXISTS(abi::__cxa_demangle "cxxabi.h" DEMANGLE_EXISTS)
IF( NOT (DEMANGLE_EXISTS))
#try to link against c++abi to get demangle
CHECK_LIBRARY_EXISTS(c++abi abi::__cxa_demangle "cxxabi.h" NEED_C++ABI)
IF( NEED_C++ABI)
TARGET_LINK_LIBRARIES(${G3LOG_LIBRARY} c++abi)
ELSE()
message( FATAL_ERROR "Could not find function abi::__cxa_demangle")
ENDIF()
endif()
ENDIF()
# add Warnings
target_compile_options(${G3LOG_LIBRARY} PRIVATE
# clang/GCC warnings
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:GNU>>:-Wall -Wunused>
# MSVC warnings
$<$<CXX_COMPILER_ID:MSVC>:/W4>)
# add GCC specific stuff
target_compile_options(${G3LOG_LIBRARY} PRIVATE
# clang/GCC warnings
$<$<AND:$<CXX_COMPILER_ID:GNU>,$<NOT:$<BOOL:${MINGW}>>>:-rdynamic>
)
#cmake -DCMAKE_CXX_COMPILER=clang++ ..
# WARNING: If Clang for Linux does not work with full c++14 support it might be your
# installation that is faulty. When I tested Clang on Ubuntu I followed the following
# description
# 1) http://kjellkod.wordpress.com/2013/09/23/experimental-g3log-with-clang/
# 2) https://github.com/maidsafe/MaidSafe/wiki/Hacking-with-Clang-llvm-abi-and-llvm-libc
# Windows Stuff
IF(MSVC OR MINGW)
TARGET_COMPILE_DEFINITIONS(${G3LOG_LIBRARY} PRIVATE NOGDI)
TARGET_LINK_LIBRARIES(${G3LOG_LIBRARY} dbghelp)
# VC11 bug: http://code.google.com/p/googletest/issues/detail?id=408
# add_definition(-D_VARIADIC_MAX=10)
# https://github.com/anhstudios/swganh/pull/186/files
TARGET_COMPILE_DEFINITIONS(${G3LOG_LIBRARY} PRIVATE _VARIADIC_MAX=10)
MESSAGE(STATUS "- MSVC: Set variadic max to 10 for MSVC compatibility")
# Remember to set set target properties if using GTEST similar to done below on target "unit_test"
# "set_target_properties(unit_test PROPERTIES COMPILE_DEFINITIONS "GTEST_USE_OWN_TR1_TUPLE=0")
message( STATUS "" )
message( STATUS "Windows: Run cmake with the appropriate Visual Studio generator" )
message( STATUS "The generator is one number below the official version number. I.e. VS2013 -> Generator 'Visual Studio 12'" )
MESSAGE( STATUS "I.e. if VS2013: Please run the command [cmake -DCMAKE_BUILD_TYPE=Release -G \"Visual Studio 12\" ..]")
message( STATUS "if cmake finishes OK, do 'msbuild g3log.sln /p:Configuration=Release'" )
message( STATUS "then run 'Release\\g3log-FATAL-*' examples" )
message( STATUS "" )
ENDIF()
TARGET_COMPILE_OPTIONS(${G3LOG_LIBRARY} PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/utf-8> # source code already in utf-8, force it for compilers in non-utf8_windows_locale
$<$<CXX_COMPILER_ID:MSVC>:$<$<EQUAL:4,${CMAKE_SIZEOF_VOID_P}>:/arch:IA32>>
)

172
CMakeLists.txt Normal file
View File

@ -0,0 +1,172 @@
# =============================================================================
# 2010 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
# with no warranties. This code is yours to share, use and modify with no
# strings attached and no restrictions or obligations.
#
# For more information see g3log/LICENSE or refer refer to http://unlicense.org
# ==============================================================================
# Below are details for compiling on Windows and Linux by default only an
# example g3log binary is created the performance and unit tests creation can be
# enabled by switching their OPTIONs from OFF to ON --- See below at around line
# 110
# === WINDOWS ===
# Example for: Visual Studio 2013 (earlier should work too) 1. please use the
# "Visual Studio Command Prompt 12 (2013)" 2. from the g3log folder mkdir build
# cd build; 3. cmake -DCMAKE_BUILD_TYPE=Release -G "Visual Studio XXX" .. (cmake
# -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 12") MAKE SURE you check the
# CMake documentation so you are using the correct bit flags(64 bit etc). The
# "XXX" needs tto be replaced for your specific build system, ref: cmake docs.
#
# (Example from Appveyor Ci:
# https://github.com/KjellKod/g3log/blob/master/appveyor.yml cmake -G "Visual
# Studio 14 2015 Win64" -DADD_G3LOG_UNIT_TEST=ON ..)
#
# 1. msbuild g3log.sln /p:Configuration=Release
#
# Try to run an example, such as: 5. Release\g3log-FATAL-contract.exe
#
# === LINUX: === To try this out from folder g3log: mkdir build cd build >>
# create makefiles in g3log/build directory cmake -DCMAKE_BUILD_TYPE=Release ..
# make -jN (where N stands for number of cores you want to utilize)
#
# === Clang on Linux ===
# From g3log mkdir build && cd build cmake -DCMAKE_CXX_COMPILER=clang++ .. if
# you want to double-check settings: "VERBOSE=1 make" otherwise just run:
# "make -j"
#
# ============================================================================
cmake_minimum_required(VERSION 3.5)
project(g3log CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(NOT CMAKE_BUILD_TYPE AND NOT (MSVC_IDE OR XCODE))
set(CMAKE_BUILD_TYPE
Release
CACHE STRING "Build type, one of: Release, Debug" FORCE)
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "Configuration types: ${CMAKE_CONFIGURATION_TYPES}")
# Detect 64 or 32 bit
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
# 64-bit project
set(64_BIT_OS TRUE)
message(STATUS "A 64-bit OS detected")
else()
set(64_BIT_OS FALSE)
message(STATUS "A 32-bit OS detected")
endif()
# Calculate the version number
SET(MAJOR_VERSION 2)
SET(MINOR_VERSION 6)
IF ( NOT VERSION )
IF ( "${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows" )
message("windows: Extracting git software version")
execute_process(COMMAND cmd /c "git rev-list ${MAJOR_VERSION}.${MINOR_VERSION}..HEAD | find /v " " /c" OUTPUT_VARIABLE GIT_RELEASE_COMMITS WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
ELSE()
IF(UNIX OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
message( STATUS "nix: Extracting git software version" )
ELSE()
message( STATUS "unknown platform: extracting git software version" )
ENDIF()
execute_process(COMMAND bash "-c" "git rev-list ${MAJOR_VERSION}.${MINOR_VERSION}..HEAD | wc -l" OUTPUT_VARIABLE GIT_RELEASE_COMMITS WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
ENDIF()
string(STRIP ${GIT_RELEASE_COMMITS} GIT_RELEASE_COMMITS)
message( STATUS "git build version: ${GIT_VERSION}" )
message( STATUS "version base: ${VERSION-BASE}" )
message( STATUS "version remainder: ${VERSION-REMAINDER}" )
SET(BUILD_NUMBER ${VERSION-BASE})
SET(VERSION ${MAJOR_VERSION}.${MINOR_VERSION}-${GIT_RELEASE_COMMITS}) #-${VERSION-REMAINDER})
ENDIF()
message( STATUS "Software Version: ${VERSION}" )
# ============================================================================
# G3LOG OPTIONAL FEATURES
# ============================================================================
include(${g3log_SOURCE_DIR}/Options.cmake)
# ============================================================================
# G3LOG iOS BUILD SUPPORT
# ============================================================================
include(${g3log_SOURCE_DIR}/iOSBuild.cmake)
if(G3_IOS_LIB)
# G3_IOS_LIB is the pass used to generate all the other cmakefiles for the
# different architectures needed for the universal library. So we're done at
# here.
return()
endif()
# =========================================================================
# G3 Macro definitions in Options.cmake are written to file this avoids having
# to re-state your definitions in your source code or compile options
# ==========================================================================
include(${g3log_SOURCE_DIR}/GenerateMacroDefinitionsFile.cmake)
# =========================================================================
# G3LOG BUILD
# ==========================================================================
include(${g3log_SOURCE_DIR}/Build.cmake)
# ============================================================================
# EXAMPLE OPTIONS: By defauls is ON. This will create 'g3log-FATAL-* examples'
# ============================================================================
# DISABLE WITH: -DADD_FATAL_EXAMPLE=OFF
include(${g3log_SOURCE_DIR}/example/Example.cmake)
# ============================================================================
# PERFORMANCE TEST OPTIONS: Performance operations for g3log
# ============================================================================
# ENABLE WITH: -DADD_G3LOG_PERFORMANCE=ON
include(${g3log_SOURCE_DIR}/test_performance/Performance.cmake)
# ==========================================================================
# UNIT TEST OPTIONS:
# ============================================================================
# ENABLE WITH: -DADD_G3LOG_UNIT_TEST=ON
include(${g3log_SOURCE_DIR}/test_unit/Test.cmake)
# ==========================================================================
# CMAKE INSTALL AND CPACK OPTIONS:
# ==========================================================================
#
# Alternative 1: Package handling is done AFTER all other CMake setup usage:
# make package Check the output result and install accordingly.
#
# Alternative 2: usage: make; sudo make install
#
# For OSX you can also install an older version using 'brew install'
#
# ==========================================================================
include(${g3log_SOURCE_DIR}/CPackLists.txt)
if(MINGW)
# this enables strerror_s
add_definitions(-DMINGW_HAS_SECURE_API)
endif()
if(NOT MSVC)
message(
STATUS
"\n\n
*******************************************************************
Please do 'make clean-cmake' before next cmake generation.
It is a good idea to purge your build directory of CMake
generated cache files
*******************************************************************
")
add_custom_target(clean-cmake COMMAND ${CMAKE_COMMAND} -P
${g3log_SOURCE_DIR}/CleanAll.cmake)
endif()

15
CMakeLists.txt.in Normal file
View File

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.5)
project(googletest-download NONE)
include(ExternalProject)
ExternalProject_Add(googletest
URL https://github.com/google/googletest/archive/refs/heads/main.zip
SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)

95
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,95 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
kjell.hedstrom+g3log_code_of_conduct@gmail.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Warning
**Community Impact**: A violation through a single incident or series
of actions. Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested. Violating these terms may lead to a permanent ban.
### 2. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

13
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,13 @@
# New Code
1. Please support all changed functionality with unit testing. A TDD approach usually leaves a cleaner end result than writing test afterwards
# Issues
1. Please explain your environment in the ticket. Frequently initialization issues due to not following best practices or the documentation are the causes.
Check the documentation and search previous issues before opening up a new one.
1. Don't be afraid of adding additional contexst of an old issue in case you think
this will improve things for the community going forward.
# Community Driven
G3log is community driven. Be respectful. G3log is developed and maintained without financial support, being helpful and polite will move your request and input along faster.

104
CPackLists.txt Normal file
View File

@ -0,0 +1,104 @@
# ==========================================================================
# 2015 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
# with no warranties. This code is yours to share, use and modify with no
# strings attached and no restrictions or obligations.
#
# For more information see g3log/LICENSE or refer refer to http://unlicense.org
# ============================================================================*/
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
IF(NOT CPACK_PACKAGING_INSTALL_PREFIX)
IF(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
SET(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
# set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX})
ELSE()
SET(CPACK_PACKAGING_INSTALL_PREFIX /usr/local)
ENDIF()
ENDIF()
# message("Install rpath location: ${CMAKE_INSTALL_RPATH}")
ENDIF()
INCLUDE(CMakePackageConfigHelpers)
INCLUDE(GNUInstallDirs)
SET(CPACK_PACKAGE_NAME g3log)
SET(CPACK_PACKAGE_VERSION_MAJOR ${MAJOR_VERSION})
SET(CPACK_PACKAGE_VERSION_MINOR ${MINOR_VERSION})
SET(CPACK_PACKAGE_VERSION_PATCH ${GIT_RELEASE_COMMITS})
SET(CPACK_PACKAGE_DESCRIPTION "Asynchronous 'crash safe' logger
License: http://unlicense.org
Repository: https://github.com/KjellKod/g3log")
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${CPACK_PACKAGE_DESCRIPTION})
SET(CPACK_PACKAGE_CONTACT "Kjell Hedstrom hedstrom@kjellkoc.cc")
SET(CPACK_RESOURCE_FILE_LICENSE ${g3log_SOURCE_DIR}/LICENSE)
SET(CPACK_PACKAGE_VENDOR "KjellKod")
IF(INSTALL_G3LOG)
INSTALL( TARGETS g3log
EXPORT g3log-targets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT libraries
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
INSTALL( FILES ${HEADER_FILES}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/g3log
COMPONENT headers)
INSTALL(
EXPORT g3log-targets
FILE g3logTargets.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/g3log
)
CONFIGURE_PACKAGE_CONFIG_FILE(
${PROJECT_SOURCE_DIR}/cmake/g3logConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/g3logConfig.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/g3log
)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/g3logConfig.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/g3log
)
ENDIF()
SET(CPACK_COMPONENTS_ALL libraries headers)
SET(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "g3log libraries")
SET(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "g3log C++ headers")
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
SET(CPACK_GENERATOR "DEB")
SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "KjellKod - Kjell Hedstrom")
ELSEIF(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
SET(CPACK_GENERATOR "ZIP") # Otherwise, NSIS is needed.
ENDIF()
message( STATUS "\nTo create installation package: " )
message( STATUS "make package" )
message( STATUS "\nOption to install using 'make install'" )
message( STATUS "Installation locations: " )
message( STATUS "====================" )
message( STATUS "Headers: ${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/g3log" )
message( STATUS "Library installation directory: ${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" )
message( STATUS "For more information please see g3log/CPackLists.txt\n\n" )
IF(NOT MINGW)
message( STATUS "To install: sudo dpkg -i g3log-***Linux.deb" )
message( STATUS "To list package contents: sudo dpkg --contents g3log-***Linux.deb" )
message( STATUS "List content of the installed package: sudo dpkg -L g3log" )
message( STATUS "To remove: sudo dpkg -r g3log" )
ENDIF()
# NOTE: to change installation locations you can use the settings below
# examples:
# CPACK_PACKAGING_INSTALL_PREFIX
# CPACK_OUTPUT_FILE_PREFIX
# CMAKE_INSTALL_PREFIX
INCLUDE(CPack)

21
CleanAll.cmake Normal file
View File

@ -0,0 +1,21 @@
# ==========================================================================
# 2015 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
# with no warranties. This code is yours to share, use and modify with no
# strings attached and no restrictions or obligations.
#
# For more information see g3log/LICENSE or refer refer to http://unlicense.org
# ============================================================================*/
set(cmake_generated ${CMAKE_BINARY_DIR}/CMakeCache.txt
${CMAKE_BINARY_DIR}/cmake_install.cmake
${CMAKE_BINARY_DIR}/Makefile
${CMAKE_BINARY_DIR}/CMakeFiles
)
foreach(file ${cmake_generated})
if (EXISTS ${file})
message( STATUS "Removing: ${file}" )
file(REMOVE_RECURSE ${file})
endif()
endforeach(file)

View File

@ -0,0 +1,53 @@
# ==========================================================================
# 2015 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
# with no warranties. This code is yours to share, use and modify with no
# strings attached and no restrictions or obligations.
#
# For more information see g3log/LICENSE or refer refer to http://unlicense.org
# ============================================================================*/
# Prerequisite : Options.cmake should run first
SET(HEADER "/** ==========================================================================
* 2015 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/")
message( STATUS "" )
message( STATUS "COMPILE_DEFINITIONS:\n\t[${G3_DEFINITIONS}]" )
message( STATUS "" )
SET(GENERATED_G3_DEFINITIONS "${CMAKE_CURRENT_BINARY_DIR}/include/g3log/generated_definitions.hpp")
# If it exists, read existing file
set(current_content "")
if(EXISTS ${GENERATED_G3_DEFINITIONS})
file(READ ${GENERATED_G3_DEFINITIONS} current_content)
endif()
set(generated_content "// AUTO GENERATED MACRO DEFINITIONS FOR G3LOG\n\n")
set(generated_content "${generated_content}\n${HEADER}\n")
set(generated_content "${generated_content}\n#pragma once\n\n")
set(generated_content "${generated_content}\n// CMake induced definitions below. See g3log/Options.cmake for details.\n\n")
FOREACH(definition ${G3_DEFINITIONS} )
set(generated_content "${generated_content}\n#define ${definition}\n")
ENDFOREACH(definition)
if(NOT "${current_content}" STREQUAL "${generated_content}")
message( STATUS "Generated ${GENERATED_G3_DEFINITIONS}" )
message( STATUS "******************** START *************************" )
message(${generated_content})
message( STATUS "******************** END *************************" )
file(WRITE ${GENERATED_G3_DEFINITIONS} ${generated_content})
endif()

24
LICENSE Normal file
View File

@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>

182
Options.cmake Normal file
View File

@ -0,0 +1,182 @@
# g3log is a KjellKod Logger
# 2015 @author Kjell Hedström, hedstrom@kjellkod.cc
# ==================================================================
# 2015 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own
# risk and comes with no warranties.
#
# This code is yours to share, use and modify with no strings attached
# and no restrictions or obligations.
# ===================================================================
# PLEASE NOTE THAT:
# the following definitions can through options be added
# to the auto generated file src/g3log/generated_definitions.hpp
# add_definitions(-DG3_DYNAMIC_LOGGING)
# add_definitions(-DCHANGE_G3LOG_DEBUG_TO_DBUG)
# add_definitions(-DWINDOWS_FUNCSIG)
# add_definitions(-DPRETTY_FUNCTION)
# add_definitions(-DDISABLE_FATAL_SIGNALHANDLING)
# add_definitions(-DDISABLE_VECTORED_EXCEPTIONHANDLING)
# add_definitions(-DDEBUG_BREAK_AT_FATAL_SIGNAL)
# add_definitions(-DG3_DYNAMIC_MAX_MESSAGE_SIZE)
# Used for generating a macro definitions file that is to be included
# that way you do not have to re-state the Options.cmake definitions when
# compiling your binary (if done in a separate build step from the g3log library)
SET(G3_DEFINITIONS "")
# -DG3_IOS_LIB=ON : iOS version of library
option(G3_IOS_LIB
"iOS version of library." OFF)
IF(G3_IOS_LIB)
MESSAGE("-DG3_IOS_LIB=ON\t\t\t\tBuilding iOS version")
ENDIF(G3_IOS_LIB)
# -DUSE_DYNAMIC_LOGGING_LEVELS=ON : run-type turn on/off levels
option (USE_DYNAMIC_LOGGING_LEVELS
"Turn ON/OFF log levels. An disabled level will not push logs of that level to the sink. By default dynamic logging is disabled" OFF)
IF(USE_DYNAMIC_LOGGING_LEVELS)
LIST(APPEND G3_DEFINITIONS G3_DYNAMIC_LOGGING)
message( STATUS "-DUSE_DYNAMIC_LOGGING_LEVELS=ON" )
message( STATUS "\tDynamic logging levels is used" )
message( STATUS "\tUse [g3::addLogLevel(LEVEL boolean)] to enable/disable logging on specified levels\n\n" )
ELSE()
message( STATUS "-DUSE_DYNAMIC_LOGGING_LEVELS=OFF" )
ENDIF(USE_DYNAMIC_LOGGING_LEVELS)
# -DCHANGE_G3LOG_DEBUG_TO_DBUG=ON : change the DEBUG logging level to be DBUG to avoid clash with other libraries that might have
# predefined DEBUG for their own purposes
option (CHANGE_G3LOG_DEBUG_TO_DBUG
"Use DBUG logging level instead of DEBUG. By default DEBUG is the debugging level" OFF)
IF(CHANGE_G3LOG_DEBUG_TO_DBUG)
LIST(APPEND G3_DEFINITIONS CHANGE_G3LOG_DEBUG_TO_DBUG)
LIST(APPEND G3_DEFINITIONS "G3LOG_DEBUG DBUG")
message( STATUS "-DCHANGE_G3LOG_DEBUG_TO_DBUG=ON DBUG instead of DEBUG logging level is used" )
ELSE()
LIST(APPEND G3_DEFINITIONS "G3LOG_DEBUG DEBUG")
message( STATUS "-DCHANGE_G3LOG_DEBUG_TO_DBUG=OFF \t(Debuggin logging level is 'DEBUG')" )
ENDIF(CHANGE_G3LOG_DEBUG_TO_DBUG)
# -DWINDOWS_USE_FUNCSIG=ON : (Default OFF) Override the use of __FUNCTION__ for Windows platform and instead use __FUNCSIG__
option (WINDOWS_FUNCSIG
"Windows __FUNCSIG__ to expand `Function` location of the LOG call instead of the default __FUNCTION__" OFF)
IF(WINDOWS_FUNCSIG)
LIST(APPEND G3_DEFINITIONS WINDOWS_FUNCSIG)
message( STATUS "-DWINDOWS_FUNCSIG=ON\t\t__SIGFUNC__ is used instead of the default __FUNCTION__ for LOG call locations" )
ELSE()
message( STATUS "-DWINDOWS_FUNCSIG=OFF")
ENDIF(WINDOWS_FUNCSIG)
# -DPRETTY_FUNCTION=ON : (Default OFF) Override the use of __FUNCTION__ for Windows platform and instead use __FUNCSIG__
# NOTE: heavy templated integrations such as boost log calls that shows the function name can cause function name expansion
# to "spam" the LOG output with the now visible template arguments.
option (PRETTY_FUNCTION
"Windows __PRETTY_FUNCTION__ to expand `Function` location of the LOG call instead of the default __FUNCTION__" OFF)
IF(PRETTY_FUNCTION)
LIST(APPEND G3_DEFINITIONS PRETTY_FUNCTION)
message( STATUS "-DPRETTY_FUNCTION=ON\t\t__PRETTY_FUNCTION__ is used instead of the default __FUNCTION__ for LOG call locations" )
ELSE()
message( STATUS "-DPRETTY_FUNCTION=OFF")
ENDIF(PRETTY_FUNCTION)
# -DG3_DYNAMIC_MAX_MESSAGE_SIZE : use dynamic memory for final_message in logcapture.cpp
option (USE_G3_DYNAMIC_MAX_MESSAGE_SIZE
"Use dynamic memory for message buffer during log capturing" OFF)
IF(USE_G3_DYNAMIC_MAX_MESSAGE_SIZE)
LIST(APPEND G3_DEFINITIONS G3_DYNAMIC_MAX_MESSAGE_SIZE)
message( STATUS "-DUSE_G3_DYNAMIC_MAX_MESSAGE_SIZE=ON\t\tDynamic memory used during log capture" )
ELSE()
message( STATUS "-DUSE_G3_DYNAMIC_MAX_MESSAGE_SIZE=OFF" )
ENDIF(USE_G3_DYNAMIC_MAX_MESSAGE_SIZE)
# G3LOG_FULL_FILENAME logs full file name instead of short filename. This makes it
# easier to copy filenames to open them without needing to search.
option (G3_LOG_FULL_FILENAME "Log full filename" OFF)
IF(G3_LOG_FULL_FILENAME)
LIST(APPEND G3_DEFINITIONS G3_LOG_FULL_FILENAME)
message( STATUS "-DG3_LOG_FULL_FILENAME=ON\t\tShowing full filenames with logs")
ELSE()
message( STATUS "-DG3_LOG_FULL_FILENAME=OFF")
ENDIF(G3_LOG_FULL_FILENAME)
# -DENABLE_FATAL_SIGNALHANDLING=ON : default change the
# By default fatal signal handling is enabled. You can disable it with this option
# enumerated in src/stacktrace_windows.cpp
option (ENABLE_FATAL_SIGNALHANDLING
"Vectored exception / crash handling with improved stack trace" ON)
IF(NOT ENABLE_FATAL_SIGNALHANDLING)
LIST(APPEND G3_DEFINITIONS DISABLE_FATAL_SIGNALHANDLING)
message( STATUS "-DENABLE_FATAL_SIGNALHANDLING=OFF Fatal signal handler is disabled" )
ELSE()
message( STATUS "-DENABLE_FATAL_SIGNALHANDLING=ON\tFatal signal handler is enabled" )
ENDIF(NOT ENABLE_FATAL_SIGNALHANDLING)
# Option for building as a static or shared library in all platforms
option (G3_SHARED_LIB "Build shared library" ON)
IF(G3_SHARED_LIB)
message( STATUS "-DG3_SHARED_LIB=ON\tBuild shared library" )
ELSE()
MESSAGE( STATUS "-DG3_SHARED_LIB=OFF\tBuild static library")
ENDIF()
# Option for building as a static or shared runtime library in MS VC++
option (G3_SHARED_RUNTIME "Build shared runtime library MS VC" ON)
IF(G3_SHARED_RUNTIME)
message( STATUS "-DG3_SHARED_RUNTIME=ON\tBuild shared runtime library" )
ELSE()
message( STATUS "-DG3_SHARED_RUNTIME=OFF\tBuild static runtime library")
ENDIF()
# WINDOWS OPTIONS
IF (MSVC OR MINGW)
# -DENABLE_VECTORED_EXCEPTIONHANDLING=ON : defualt change the
# By default vectored exception handling is enabled, you can disable it with this option.
# Please know that only known fatal exceptions will be caught, these exceptions are the ones
# enumerated in src/stacktrace_windows.cpp
option (ENABLE_VECTORED_EXCEPTIONHANDLING
"Vectored exception / crash handling with improved stack trace" ON)
IF(NOT ENABLE_VECTORED_EXCEPTIONHANDLING)
LIST(APPEND G3_DEFINITIONS DISABLE_VECTORED_EXCEPTIONHANDLING)
message( STATUS "-DENABLE_VECTORED_EXCEPTIONHANDLING=OFF Vectored exception handling is disabled" )
ELSE()
message( STATUS "-DENABLE_VECTORED_EXCEPTIONHANDLING=ON\t\t\tVectored exception handling is enabled" )
ENDIF(NOT ENABLE_VECTORED_EXCEPTIONHANDLING)
# Default ON. Will trigger a break point in DEBUG builds if the signal handler
# receives a fatal signal.
#
option (DEBUG_BREAK_AT_FATAL_SIGNAL
"Enable Visual Studio break point when receiving a fatal exception. In __DEBUG mode only" OFF)
IF(DEBUG_BREAK_AT_FATAL_SIGNAL)
LIST(APPEND G3_DEFINITIONS DEBUG_BREAK_AT_FATAL_SIGNAL)
message( STATUS "-DDEBUG_BREAK_AT_FATAL_SIGNAL=ON Break point for fatal signal is enabled for __DEBUG." )
ELSE()
message( STATUS "-DDEBUG_BREAK_AT_FATAL_SIGNAL=OFF\t\t\tBreak point for fatal signal is disabled" )
ENDIF(DEBUG_BREAK_AT_FATAL_SIGNAL)
ENDIF (MSVC OR MINGW)
message( STATUS "\n\n\n" )
option(INSTALL_G3LOG "Enable installation of g3log. (Projects embedding g3log may want to turn this OFF.)" ON)

36
PULL_REQUEST_TEMPLATE.md Normal file
View File

@ -0,0 +1,36 @@
# PULL REQUEST DESCRIPTION
`ADD CONTENT HERE TO DESCRIBE THE PURPOSE OF THE PULL REQUEST`
# Formatting
- [ ] I am following the formatting style of the existing codebase.
_a clang-format configuration file is available in the root of g3log._
- _Use VSCode with clang-formatter or commandline:_
`clang-format -i path_to_file`
- _or recursive throughout the whole repo:_ `find . -iname "*.hpp" -o -iname "*.cpp" | xargs clang-format -i`
# Testing
- [ ] This new/modified code was covered by unit tests.
- [ ] (insight) Was all tests written using TDD (Test Driven Development) style?
- [ ] The CI (Windows, Linux, OSX) are working without issues.
- [ ] Was new functionality documented?
- [ ] The testing steps 1 - 2 below were followed
_step 1_
```bash
mkdir build; cd build; cmake -DADD_G3LOG_UNIT_TEST=ON ..
// linux/osx alternative, simply run: ./scripts/buildAndRunTests.sh
```
_step 2: use one of these alternatives to run tests:_
- Cross-Platform: `ctest`
- or `ctest -V` for verbose output
- Linux: `make test`

82
README
View File

@ -1,82 +0,0 @@
LATEST CHANGES
=====================
2012, Oct 14th
* Complete threadsafe use of localtime for timestamp. Reference g2time
* Runtime change of filename, request of filename. Reference g2logwoker g2future
Tested on
x86 Windows7: Visual Studio 2012 Desktop Express
x86 Ubuntu 11.04: gcc 4.7.3
x64 Ubuntu 12...: gcc 4.7.2
x64 Windows7: Visual Studio 2012 Professional
NOTE: It does NOT work with "Visual Studio 11 Beta"
HOW TO BUILD
===================
This g2log is a snapshot from KjellKod repository.
It contains what is needed to build example, unit test and performance test of g2log.
justthread C++11 thread library is no longer needed.
On Windows it is enough to use Visual Studio 11 (2012)
On Linux it is enough to use gcc4.7.2. The CMakeFile.txt
is updated to reflect that, the justthread parts is
commented away in case someone still needs that.
If you do not have gcc 4.7.2
If you want to integrate g2log in your own software you need
the files under g2log/src
BUILDING g2log:
-----------
The default is to build an example binary 'g2log-FATAL'
I suggest you start with that, run it and view the created log also.
If you are interested in the performance or unit tests then you can
enable the creation of them in the g2log/CMakeLists.txt file. See that file for more details
--- Building on Linux ---
cd g2log
mkdir build
cd build
cmake ..
make
--- Building on Windows ---
Please use the Visual Studio 11 (2012) command prompt "Developer command prompt"
cd g2log
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 11" ..
msbuild g2log_by_kjellkod.sln /p:Configuration=Release
Release\g2log-FATAL.exe
CONTENTS
===========================
3rdParty -- gtest, glog.
-----------------------
Both are needed to compile the unit test and the logger comparison tests
Gtest must be unpacked before used, but it IS included by the CMake and you don't need to do install or compile it in any other way than through the g2log cmake setup.
glog is not included and must be installed if you want to run the comparison tests
About the Active Object
--------------------
Is made with standard C++ components with the help of the latest C++11 and std::thread features (thanks to justthread). For more details see www.kjellkod.cc/active-object-with-cpp0x. An example is provided. Other examples on pre C++0x Active Objects can also be found at www.kjellkod.cc (code page)
If you like it (or not) it would be nice with some feedback. That way
I can improve g2log and it is also nice to see if someone is using it.
If you have ANY questions or problems please do not hesitate in contacting
me on my blog http://kjellkod.wordpress.com/2011/11/17/kjellkods-g2log-vs-googles-glog-are-asynchronous-loggers-taking-over/
or at <Hedstrom at KjellKod dot cc>
Good luck :)
Cheers
Kjell (a.k.a. KjellKod)

136
README.md Normal file
View File

@ -0,0 +1,136 @@
**Scanning Update**: [![ci/action CodeQL](https://github.com/KjellKod/g3log/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/KjellKod/g3log/actions/workflows/codeql-analysis.yml)
# Contents
[**introduction**](docs/index.md) | [detailed information](docs/g3log_usage.md) | [Configure & Build](docs/building.md) | [API description](docs/API.md) | [Custom log formatting](docs/API_custom_formatting.md)
# Welcome to g3log
### Use [kjellkod.github.io/g3log/](https://kjellkod.github.io/g3log/) for best reading / searching / navigating of g3log's documentation
G3log is an asynchronous logger with three main features:
1. Intuitive `LOG(...)` API
2. `Design-by-contract` `CHECK(...)` functionality
3. Fatal crash handling for graceful shutdown of the logged process without loosing any log details up to the point of the crash.
The super quick introduction to g3log can be seen in the steps 1 - 9 below.
For more in-depth information please see the full usage description in [g3log_usage.md](docs/g3log_usage.md). If you want to understand better the internals of g3log, then plase look at the [API.md](docs/API.md) for both high-level and deep-dive insights.
## Experiment and try-out g3log in Github Codespaces
ref: [codespaces.md](docs/codespaces.md)
## 1. Easy usage in files
Avoid deep dependency injection complexity and instead get access to the logger as easy as:
```
#include <g3log/g3log.hpp>
```
## 2. Access to streaming and print_f log call syntax
Both streaming syntax `LOG` and print_f `LOGF` syntax are available:
```
LOGF(INFO, "Hi log %d", 123);
LOG(INF) << "Hi log " << 123;
```
## 3. Conditional logging
```
LOG_IF(INFO, (1 < 2)) << "If true this message will be logged";
LOGF_IF(INFO, (1 < 2), "If true, then this %s will be logged", "message");
```
## 4. Design-by-contract framework
```
CHECK(less != more); // not fatal
CHECK_F(less > more, "CHECK(false) will trigger a fatal message")
```
## 5. Handling of fatal
By default g3log will capture fatal events such as `LOG(FATAL)`, `CHECK(false)` and otherwise fatal signals such as:
```
SIGABRT
SIGFPE
SIGILL
SIGSEGV
SIGTERM
```
When a fatal event happens the not-yet written log activity will be flushed to the logging sinks. Only when all logging activity up to the point of the fatal event has happend, will g3log allow the fatal event to proceed and exit the process.
If `object` symbols are available the fatal handler will attempt to push the stacktrace up to the fatal reason to the logging sink.
#### 5b. Overriding and customization of fatal event handling
For overriding fatal error handling to use your own, or to add code `hooks` that you want to execute please see the [API.md](docs/API.md) doc.
## 6. Default and Custom logging levels
The default logging levels are `DEBUG`, `INFO`, `WARNING` and `FATAL`. You can define your own logging levels or completely replace the logging levels. Ref: [API.md](docs/API.md)
### 7. Log filtering
Log filtering is handled in g3log if dynamic logging levels are enabled
in the configuration. See the [API.md](docs/API.md) for information. Log filtering can also be handled through the sink as can be seen in [github/Kjellod/g3sinks](https://github.com/KjellKod/g3sinks)
## 8. 3rd party and custom logging sinks
The default logging sink has no external 3rd party dependencies. For more logging sinks please see [github/Kjellod/g3sinks](https://github.com/KjellKod/g3sinks)
- log rotate
- log to syslog
- log to colored terminal output
- log rotate with filter
See the [API.md](docs/API.md) for more information about the simple steps to creating your own logging sink.
## 9. Log instantiation
With the default application name left as is (i.e. "g3log") a creation of the logger could look something like this:
```cpp
const std::string directory = "./";
const std::string name = "TestLogFile";
auto worker = g3::LogWorker::createLogWorker();
auto handle = worker->addDefaultLogger(name, directory);
```
The resulting filename would be something like:
```
./TestLogFile.g3log.20160217-001406.log
```
## <a name="performance">Performance</a>
G3log aims to keep all background logging to sinks with as little log overhead as possible to the logging sink and with as small "worst case latency" as possible. For this reason g3log is a good logger for many systems that deal with critical tasks. Depending on platform the average logging overhead will differ. On my 2010 laptop the average call, when doing extreme performance testing, will be about ~2 us.
The worst case latency is kept stable with no extreme peaks, in spite of any sudden extreme pressure. I have a blog post regarding comparing worst case latency for g3log and other loggers which might be of interest.
You can find it here: https://kjellkod.wordpress.com/2015/06/30/the-worlds-fastest-logger-vs-g3log/
## <a name="continuous_integration">Continuous Integration</a>
The g3log repository is evaluating github actions for executing test coverage, installation and document generation. In case you want to look into change any of these setups the following files are the ones of interest.
See `Actions` for matrix (ubuntu, macos, windows) testing as well as other actions for doc publishing.
## <a name="feedback">Feedback</a>
If you like this logger (or not) it would be nice with some feedback. That way I can improve g3log and it is always nice to hear when and how someone is using it.
If you have ANY questions or problems please do not hesitate in contacting me at
`Hedstrom @ Kjellod. cc`
# <a name="say-thanks">Say Thanks</a>
This logger is available for free and all of its source code is public domain. A great way of saying thanks is to send a donation. It would go a long way not only to show your support but also to boost continued development.
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/g3log/25)
* $5 for a cup of coffee
* $25 for a late evening coding with takeout
Cheers
Kjell *(a.k.a. KjellKod)*
[**introduction**](docs/index.md) | [detailed information](docs/g3log_usage.md) | [Configure & Build](docs/building.md) | [API description](docs/API.md) | [Custom log formatting](docs/API_custom_formatting.md)

53
cmake/g3logConfig.cmake Normal file
View File

@ -0,0 +1,53 @@
#.rst:
# FindG3log
# -------
#
# Find libg3log, G3log is an asynchronous, "crash safe", logger that is easy to use with default logging sinks or you can add your own.
#
# This defines the cmake import target "g3log" you can use like this
#```
# target_link_libraries(YourTarget PUBLIC g3log)
#```
# Variables and features
# ----------------------
# * ``G3LOG`` -- if this environment variable is set, it'll be used as a hint as to where the g3log files are.
# * ``G3LOG_INCLUDE_DIRS`` -- raw cmake variable with include path
# * ``G3LOG_LIBRARIES`` -- raw cmake variable with library link line
# * ``G3LOG_FOUND`` -- check if the lib was found without using the newer ``if(TARGET g3log)...``
include(FindPackageHandleStandardArgs)
include(SelectLibraryConfigurations)
@PACKAGE_INIT@
find_package(Threads REQUIRED)
if (NOT TARGET g3log)
include("${CMAKE_CURRENT_LIST_DIR}/g3logTargets.cmake")
get_target_property(G3LOG_INCLUDE_DIR g3log INTERFACE_INCLUDE_DIRECTORIES)
get_target_property(G3LOG_LIBRARY_DEBUG g3log IMPORTED_IMPLIB_DEBUG)
if (G3LOG_LIBRARY_DEBUG MATCHES ".*-NOTFOUND")
get_target_property(G3LOG_LIBRARY_DEBUG g3log IMPORTED_LOCATION_DEBUG)
endif ()
get_target_property(G3LOG_LIBRARY_RELEASE g3log IMPORTED_IMPLIB_RELEASE)
if (G3LOG_LIBRARY_RELEASE MATCHES ".*-NOTFOUND")
get_target_property(G3LOG_LIBRARY_RELEASE g3log IMPORTED_LOCATION_RELEASE)
endif ()
select_library_configurations(G3LOG)
if (G3LOG_LIBRARY)
list(APPEND G3LOG_LIBRARY Threads::Threads)
if (WIN32)
list(APPEND G3LOG_LIBRARY DbgHelp.lib)
endif ()
endif ()
endif ()
find_package_handle_standard_args(g3log REQUIRED_VARS G3LOG_INCLUDE_DIR G3LOG_LIBRARY)
mark_as_advanced(G3LOG_INCLUDE_DIR G3LOG_LIBRARY)
set(G3LOG_INCLUDE_DIRS ${G3LOG_INCLUDE_DIR})
set(G3LOG_LIBRARIES ${G3LOG_LIBRARY})

BIN
docs/.DS_Store vendored Normal file

Binary file not shown.

1
docs/.ciignore Normal file
View File

@ -0,0 +1 @@

307
docs/API.md Normal file
View File

@ -0,0 +1,307 @@
[introduction](index.md) | [detailed information](g3log_usage.md) | [Configure & Build](building.md) | [**API description**](API.md) | [Custom log formatting](API_custom_formatting.md)
# High Level Description of g3log
The `g3log` logger is an asynchronous, crash-safe logging library designed for C++ applications. It allows for logging messages to various sinks without blocking the main application thread. Below is a high-level overview of how the `g3log` logger works.
## Asynchronous Logging
The logger operates on a separate thread, ensuring that the main application thread is not blocked by I/O operations when logging messages. This is achieved by using a background worker ([`LogWorker`](../src/g3log/logworker.hpp)) that queues log messages and processes them asynchronously.
## LogWorker and Sinks
The `LogWorker` is responsible for managing the logging sinks. A sink is an object that defines where and how log messages are outputted (e.g., to a file, console, or over the network). Users can add custom sinks to the `LogWorker` using the `addSink` method, which takes a unique pointer to a sink object and a function pointer to the method that will save the log message.
## Signal Handling
The logger includes a signal handler for Unix-like systems that captures fatal signals (e.g., `SIGSEGV`, `SIGABRT`) and ensures that all pending log messages are flushed to the sinks before the application exits. The signal handler function ([`signalHandler`](../src/crashhandler_unix.cpp)) is registered to handle these signals and will attempt to generate a stack trace when a fatal signal is received. This stack trace is then logged, providing valuable debugging information.
## Stack Trace Generation
Upon receiving a fatal signal, the `signalHandler` function will call [`stackdump`](../src/crashhandler_unix.cpp) to generate a stack trace. This function uses platform-specific calls to retrieve the stack frames and attempts to demangle the function names to make the stack trace more readable.
## Log Message Formatting
Log messages can be formatted using either a streaming API (e.g., `LOG(INFO) << "message";`) or a printf-like syntax (e.g., `LOGF(INFO, "message %d", value);`). This provides flexibility in how messages are constructed.
## Log Levels
The library supports various log levels (e.g., `DEBUG`, `INFO`, `WARNING`, `FATAL`). Users can define custom log levels or modify the existing ones. The log levels can be dynamically enabled or disabled at runtime if the `G3_DYNAMIC_LOGGING` preprocessor definition is set.
## Crash Safety
In the event of a crash, the logger is designed to be crash-safe by catching fatal events and ensuring that all log messages are flushed to the sinks before the process exits.
## Customization
The library allows for extensive customization, including adding custom log levels, creating custom sinks, and overriding the default signal handling behavior.
## Thread Safety
The `g3log` logger is thread-safe, meaning it can be used from multiple threads without the need for additional synchronization.
## Public Domain Software
The `g3log` code is released into the public domain, allowing users to use, modify, and distribute it freely without restrictions.
## Logging and Fatal Events Explained
_diagrams created with https://mermaid.live_
![G3Log sequence view](event_sequence.png)
# API description
Most of the API that you need for using g3log is described in this readme. For more API documentation and examples please continue to read the [API readme](API.md). Examples of what you will find here are:
## Logging API: LOG calls
LOG calls can follow streaming ```LOG(INFO) << "some text" ``` or printf-like syntax ```LOGF(WARNING, "some number %d", 123); ```
Conditional logging is made with ```LOG_IF(INFO, <boolean-expression>) << " some text" ``` or ```LOGF_IF(WARNING, <boolean-expression>) << " some text".``` Only if the expressions evaluates to ```true``` will the logging take place.
Example:
```LOG_IF(INFO, 1 != 200) << " some text";``` or ```LOG_IF(FATAL, SomeFunctionCall()) << " some text";```
*<a name="fatal_logging">A call using FATAL</a> logging level, such as the ```LOG_IF(FATAL,...)``` example above, will after logging the message at ```FATAL```level also kill the process. It is essentially the same as a ```CHECK(<boolea-expression>) << ...``` with the difference that the ```CHECK(<boolean-expression)``` triggers when the expression evaluates to ```false```.*
## Contract API: CHECK calls
The contract API follows closely the logging API with ```CHECK(<boolean-expression>) << ...``` for streaming or (*) ```CHECKF(<boolean-expression>, ...);``` for printf-style.
If the ```<boolean-expression>``` evaluates to false then the the message for the failed contract will be logged in FIFO order with previously made messages. The process will then shut down after the message is sent to the sinks and the sinks have dealt with the fatal contract message.
```CHECK_F(<boolean-expression>, ...);``` was the the previous API for printf-like CHECK. It is still kept for backwards compatability but is exactly the same as ```CHECKF```
# LOG(fATAL) or CHECK(false)
Fatal logging or failed `CHECK calls follows the same handling.
![CHECK(false) or LOG(FATAL)](fatal_log_sequence.png)
## Logging levels
The default logging levels are ```DEBUG```, ```INFO```, ```WARNING``` and ```FATAL``` (see FATAL usage [above](#fatal_logging)). The logging levels are defined in [loglevels.hpp](https://github.com/KjellKod/g3log/tree/master/src/g3log/loglevels.hpp).
For some windows framework there is a clash with the ```DEBUG``` logging level. One of the CMake [Build options](#build_options) can be used to then change offending default level from ```DEBUG``` TO ```DBUG```.
**CMake option: (default OFF) ** ```cmake -DCHANGE_G3LOG_DEBUG_TO_DBUG=ON ..```
### disable/enabled levels at runtime
Logging levels can be disabled at runtime. The logic for this happens in
[loglevels.hpp](https://github.com/KjellKod/g3log/tree/master/src/g3log/loglevels.hpp), [loglevels.cpp](https://github.com/KjellKod/g3log/tree/master/src/loglevels.cpp) and [g3log.hpp](https://github.com/KjellKod/g3log/tree/master/src/g3log/g3log.hpp).
There is a cmake option to enable the dynamic enable/disable of levels.
When the option is enabled there will be a slight runtime overhead for each ```LOG``` call when the enable/disable status is checked. For most intent and purposes this runtime overhead is negligable.
There is **no** runtime overhead for internally checking if a level is enabled//disabled if the cmake option is turned off. If the dynamic logging cmake option is turned off then all logging levels are enabled.
**CMake option: (default OFF)** ```cmake -DUSE_DYNAMIC_LOGGING_LEVELS=ON ..```
### custom logging levels
Custom logging levels can be created and used. When defining a custom logging level you set the value for it as well as the text for it. You can re-use values for other levels such as *INFO*, *WARNING* etc or have your own values. Any value with equal or higher value than the *FATAL* value will be considered a *FATAL* logging level.
**To keep in mind when adding your own custom levels.**
1. If the cmake option `G3_DYNAMIC_LOGGING` is enabled then you must use `g3::only_change_at_initialization::addLogLevel(...)` to give g3log a record of your logging level and if it is an enabled or disbled logging level.
1. If the cmake `G3_DYNAMIC_LOGGING` is turned OFF, then giving g3log a record of your logging level with 'addLogLevel(...) is **not needed** since no `"disbled/enabled"` check will happen - all logging levels will be considered enabled.
Example:
```cpp
// In CustomLoggingLevels.hpp
#include <g3log/loglevels.hpp>
// all values with a + 1 higher than their closest equivalet
// they could really have the same value as well.
const LEVELS FYI {DEBUG.value + 1, {"For Your Information"}};
const LEVELS CUSTOM {INFO.value + 1, {"CUSTOM"}};
const LEVELS SEVERE {WARNING.value +1, {"SEVERE"}};
const LEVELS DEADLY {FATAL.value + 1, {"DEADLY"}};
```
More examples can be viwed in the [unit tests](https://github.com/KjellKod/g3log/blob/master/test_unit/test_io.cpp).
## Sink <a name="sink_creation">creation</a> and utilization
The default sink for g3log is the one as used in g2log. It is a simple file sink with a limited API. The details for the default file sink can be found in [filesink.hpp](https://github.com/KjellKod/g3log/tree/master/src/g3log/filesink.hpp), [filesink.cpp](https://github.com/KjellKod/g3log/tree/master/src/filesink.cpp), [filesinkhelper.ipp](https://github.com/KjellKod/g3log/tree/master/src/filesinkhelper.ipp)
More sinks can be found at [g3sinks](http://www.github.com/KjellKod/g3sinks) (log rotate, log rotate with filtering on levels)
A logging sink is not required to be a subclass of a specific type. The only requirement of a logging sink is that it can receive a logging message of
### Using the default sink
Sink creation is defined in [logworker.hpp](https://github.com/KjellKod/g3log/tree/master/src/g3log/logworker.hpp) and used in [logworker.cpp](https://github.com/KjellKod/g3log/tree/master/src/logworker.cpp). For in-depth knowlege regarding sink implementation details you can look at [sinkhandle.hpp](https://github.com/KjellKod/g3log/tree/master/src/g3log/sinkhandle.hpp) and [sinkwrapper.hpp](https://github.com/KjellKod/g3log/tree/master/src/g3log/sinkwrapper.hpp)
```cpp
std::unique_ptr<FileSinkHandle> addDefaultLogger(
const std::string& log_prefix
, const std::string& log_directory
, const std::string& default_id = "g3log");
```
With the default id left as is (i.e. "g3log") a creation of the logger in the unit test "test_filechange" would look like this
```cpp
const std::string directory = "./";
const std::string name = "(ReplaceLogFile)";
auto worker = g3::LogWorker::createLogWorker();
auto handle = worker->addDefaultLogger(name, directory);
```
The resulting filename would be something like:
```
./(ReplaceLogFile).g3log.20160217-001406.log
```
## Designate the sink function's log entry receving function
The default log formatting look can be overriden by any sink.
If the sink receiving function calls `toString()` then the default log formatting will be used.
If the sink receiving function calls `toString(&XFunc)` then the `XFunc`will be used instead (see `LogMessage.h/cpp` for code details if it is not clear). (`XFunc` is a place holder for *your* formatting function of choice).
The API for the function-ptr to pass in is
```cpp
std::string (*) (const LogMessage&)
```
or for short as defined in `LogMessage.h`
```cpp
using LogDetailsFunc = std::string (*) (const LogMessage&);
```
## Log format customization
Please see[API_custom_formatting.md](API_custom_formatting.md)
## LOG <a name="log_flushing">flushing</a>
The default file sink will flush each log entry at set intervals. The default buffer size for flushing is set to 100 entries. You can adjust this down to 1, or as high as makes sense for your system. Please see [FileSink](https://github.com/KjellKod/g3log/blob/master/src/g3log/filesink.hpp#L18)
Even more flushing policies and log rotations can be found at g3sinks [logrotate and LogRotateWithFilters](https://github.com/KjellKod/g3sinks/tree/master/sink_logrotate).
At shutdown all enqueued logs will be flushed to the sink.
At a discovered fatal event (SIGSEGV et.al) all enqueued logs will be flushed to the sink.
A programmatically triggered abrupt process exit such as a call to ```exit(0)``` will of course not get the enqueued log entries flushed. Similary a bug that does not trigger a fatal signal but a process exit will also not get the enqueued log entries flushed. G3log can catch several fatal crashes and it deals well with RAII exits but magic is so far out of its' reach.
![log sequence](log_sequence.png)
## G3log and Sink Usage Code Example
Example usage where a [logrotate sink (g3sinks)](https://github.com/KjellKod/g3sinks) is added. In the example it is shown how the logrotate API is called. The logrotate limit is changed from the default to instead be 10MB. The limit is changed by calling the sink handler which passes the function call through to the actual logrotate sink object.
```cpp
// main.cpp
#include <g3log/g3log.hpp>
#include <g3log/logworker.h>
#include <g3sinks/LogRotate.h>
#include <memory>
int main(int argc, char**argv) {
using namespace g3;
std::unique_ptr<LogWorker> logworker{ LogWorker::createLogWorker() };
auto sinkHandle = logworker->addSink(std::make_unique<LogRotate>(),
&LogRotate::save);
// initialize the logger before it can receive LOG calls
initializeLogging(logworker.get());
// You can call in a thread safe manner public functions on the logrotate sink
// The call is asynchronously executed on your custom sink.
const int k10MBInBytes = 10 * 1024 * 1024;
std::future<void> received = sinkHandle->call(&LogRotate::setMaxLogSize, k10MBInBytes);
// Run the main part of the application. This can be anything of course, in this example
// we'll call it "RunApplication". Once this call exits we are in shutdown mode
RunApplication();
// If the LogWorker is initialized then at scope exit the g3::shutDownLogging() will be
// called automatically.
//
// This is important since it protects from LOG calls from static or other entities that will go out of
// scope at a later time.
//
// It can also be called manually if for some reason your setup is different then the one highlighted in
// this example
g3::shutDownLogging();
}
```
## Dynamic Message Sizing <a name="dynamic_message_sizing"></a>
The default build uses a fixed size buffer for formatting messages. The size of this buffer is 2048 bytes. If an incoming message results in a formatted message that is greater than 2048 bytes, it will be bound to 2048 bytes and will have the string ```[...truncated...]``` appended to the end of the bound message. There are cases where one would like to dynamically change the size at runtime. For example, when debugging payloads for a server, it may be desirable to handle larger message sizes in order to examine the whole payload. Rather than forcing the developer to rebuild the server, dynamic message sizing could be used along with a config file which defines the message size at runtime.
This feature supported as a CMake option:
**CMake option: (default OFF)** ```cmake -DUSE_G3_DYNAMIC_MAX_MESSAGE_SIZE=ON ..```
The following is an example of changing the size for the message.
```cpp
g3::only_change_at_initialization::setMaxMessageSize(10000);
```
## Fatal handling
The default behaviour for G3log is to catch several fatal events before they force the process to exit. After <i>catching</i> a fatal event a stack dump is generated and all log entries, up to the point of the stack dump are together with the dump flushed to the sink(s).
![fatal signal](fatal_signal_sequence.png)
### <a name="fatal_handling_linux">Linux/*nix</a>
The default fatal handling on Linux deals with fatal signals. At the time of writing these signals were ```SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGTERM```. The Linux fatal handling is handled in [crashhandler.hpp](https://github.com/KjellKod/g3log/tree/master/src/g3log/crashhandler.hpp) and [crashhandler_unix.cpp](https://github.com/KjellKod/g3log/tree/master/src/crashhandler_unix.cpp)
A signal that commonly is associated with voluntarily process exit is ```SIGINT``` (ctrl + c) G3log does not deal with it.
The fatal signals can be [disabled](#fatal_handling_disabled) or [changed/added ](#fatal_signalhandler_override).
An example of a Linux stackdump as shown in the output from the fatal example <i>g3log-FATAL-sigsegv</i>.
```
***** FATAL SIGNAL RECEIVED *******
"Received fatal signal: SIGSEGV(11) PID: 6571
***** SIGNAL SIGSEGV(11)
******* STACKDUMP *******
stack dump [1] ./g3log-FATAL-sigsegv() [0x42a500]
stack dump [2] /lib/x86_64-linux-gnu/libpthread.so.0+0x10340 [0x7f83636d5340]
stack dump [3] ./g3log-FATAL-sigsegv : example_fatal::tryToKillWithAccessingIllegalPointer(std::unique_ptr<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::default_delete<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >)+0x119 [0x4107b9]
stack dump [4] ./g3log-FATAL-sigsegvmain+0xdec [0x40e51c]
stack dump [5] /lib/x86_64-linux-gnu/libc.so.6__libc_start_main+0xf5 [0x7f8363321ec5]
stack dump [6] ./g3log-FATAL-sigsegv() [0x40ffa2]
Exiting after fatal event (FATAL_SIGNAL). Fatal type: SIGSEGV
Log content flushed sucessfully to sink
"
g3log g3FileSink shutdown at: 16:33:18
```
### <a name="fatal_custom_handling">Custom fatal handling - override defaults</a>
By <a name="fatal_signalhandler_override">default</a> the fatal signals are defined in [https://github.com/KjellKod/g3log/tree/master/src/g3log.cpp](https://github.com/KjellKod/g3log/tree/master/src/g3log.cpp) as
```
SIGABRT
SIGFPE
SIGILL
SIGSEGV
SIGTERM
```
If you want to define your own set of fatal signals, override the default ones, then this can be done as shown in [src/g3log/crashhandler.hpp](https://github.com/KjellKod/g3log/tree/master/src/g3log/crashhandler.hpp)
```cpp
// Example when SIGTERM is skipped due to ZMQ usage
g3::overrideSetupSignals({ {SIGABRT, "SIGABRT"},
{SIGFPE, "SIGFPE"},
{SIGILL, "SIGILL"},
{SIGSEGV, "SIGSEGV"}});
```
### <a name="fatal_pre_hook">Pre fatal hook</a>
You can define a custom call back function that will be called before the fatal signal handling re-emits the `fatal` signal. See [src/g3log/g3log.hpp](https://github.com/KjellKod/g3log/tree/master/src/g3log/g3log.hpp) for details.
```
// Example of how to enforce important shutdown cleanup even in the event of a fatal crash:
g3::setFatalPreLoggingHook([]{ cleanup(); });
```
### <a name="fatal_handling_disabled">Disable fatal handling</a>
Fatal signal handling can be disabled with a CMake option: `ENABLE_FATAL_SIGNALHANDLING`. See [Options.cmake](https://github.com/KjellKod/g3log/Options.cmake) for more details
### <a name="PID1">PID1 Fatal Signal Recommendations</a>
If you are using g3log on a PID1 process then you absolutely should provide your own signal handling (ref: [issue 269](https://github.com/KjellKod/g3log/issues/269)) as g3log re-emits the fatal signal after it has restored the previous signal handler for that signal. PID1 processed do *not* shutdown the process for a normal fatal signal so the choice to exit the PID1 process after such a signal must be taken by the coder - not by g3log.
## <a name="fatal_handling_windows">Windows</a>
Windows fatal handling also deals with fatal signals just like Linux. In addition to fatal signals it also deals with unhandled exceptions, vectored exceptions. Windows fatal handling is handled in [crashhandler.hpp](https://github.com/KjellKod/g3log/tree/master/src/g3log/crashhandler.hpp), [crashhandler_windows.cpp](https://github.com/KjellKod/g3log/tree/master/src/crashhandler_windows.cpp), [stacktrace_windows.hpp](https://github.com/KjellKod/g3log/tree/master/src/g3log/stacktrace_windows.hpp), [stacktrace_windows.cpp](https://github.com/KjellKod/g3log/tree/master/src/stacktrace_windows.cpp)
An example of a Windows stackdump as shown in the output from the fatal example <i>g3log-FATAL-sigsegv</i>.
[introduction](index.md) | [detailed information](g3log_usage.md) | [Configure & Build](building.md) | [**API description**](API.md) | [Custom log formatting](API_custom_formatting.md)

View File

@ -0,0 +1,69 @@
[introduction](index.md) | [detailed information](g3log_usage.md) | [Configure & Build](building.md) | [API description](API.md) | [**Custom log formatting**](API_custom_formatting.md)
# Custom LOG <a name="log_formatting">formatting</a>
### Overriding the Default File Sink's file header
The default file header can be customized in the default file sink in calling
```cpp
FileSink::overrideLogHeader(std::string);
```
### Overriding the Default FileSink's log formatting
The default log formatting is defined in `LogMessage.hpp`
```cpp
static std::string DefaultLogDetailsToString(const LogMessage& msg);
```
### Adding thread ID to the log formatting
An "all details" log formatting function is also defined - this one also adds the "calling thread's ID"
```cpp
static std::string FullLogDetailsToString(const LogMessage& msg);
```
### Override default sink log formatting
For convenience the *Default* sink has a function
for doing exactly this
```cpp
void overrideLogDetails(LogMessage::LogDetailsFunc func);
```
Example code for replacing the default log formatting for "full details" formatting (it adds thread ID)
```cpp
auto worker = g3::LogWorker::createLogWorker();
auto handle= worker->addDefaultLogger(argv[0], path_to_log_file);
g3::initializeLogging(worker.get());
handle->call(&g3::FileSink::overrideLogDetails, &LogMessage::FullLogDetailsToString);
```
See [test_message.cpp](https://github.com/KjellKod/g3log/tree/master/test_unit/test_message.cpp) for details and testing
Example code for overloading the formatting of a custom sink. The log formatting function will be passed into the
`LogMessage::toString(...)` this will override the default log formatting
Example
```cpp
namespace {
std::string MyCustomFormatting(const LogMessage& msg) {
... how you want it ...
}
}
void MyCustomSink::ReceiveLogEntry(LogMessageMover message) {
std::string formatted = message.get().toString(&MyCustomFormatting) << std::flush;
}
...
...
auto worker = g3::LogWorker::createLogWorker();
auto sinkHandle = worker->addSink(std::make_unique<MyCustomSink>(),
&MyCustomSink::ReceiveLogMessage);
// ReceiveLogMessage(...) will used the custom formatting function "MyCustomFormatting(...)
```
[introduction](index.md) | [detailed information](g3log_usage.md) | [Configure & Build](building.md) | [API description](API.md) | [**Custom log formatting**](API_custom_formatting.md)

252
docs/building.md Normal file
View File

@ -0,0 +1,252 @@
[introduction](index.md) | [detailed information](g3log_usage.md) | [**Configure & Build**](building.md) | [API description](API.md) | [Custom log formatting](API_custom_formatting.md)
# <a name="building-g3log">Configure, build, package, install and test g3log</a>
## Example Project with g3log
An example project integration of g3log, both statially and dynamically built can be found at [g3log_example_integration](https://github.com/KjellKod/g3log_example_integration/blob/master/README.md)
## Building it standalone to try out is as easy as:
```
git clone https://github.com/KjellKod/g3log
cd g3log
mkdir build
cd build
```
## <a name="prerequisites">Prerequisites</a>
You also need these tools to build g3log from source:
- CMake (*Required*)
g3log uses CMake as a one-stop solution for configuring, building, installing, packaging and testing on Windows, Linux and OSX.
- Git (*Optional but Recommended*)
When building g3log it uses git to calculate the software version from the commit history of this repository. If you don't want that, or your setup does not have access to git, or you download g3log source archive from the GitHub Releases page so that you do not have the commit history downloaded, you can instead pass in the version as part of the CMake build arguments. See this [_issue_](https://github.com/KjellKod/g3log/issues/311#issuecomment-488829282) for more information.
```
cmake -DVERSION=1.3.2 ..
```
## <a name="configuration">Configuration Options</a>
g3log provides following CMake options (and default values):
```
$ cmake -LAH # List non-advanced cached variables. See `cmake --help` for more details.
...
// Fatal (fatal-crashes/contract) examples
ADD_FATAL_EXAMPLE:BOOL=ON
// g3log performance test
ADD_G3LOG_BENCH_PERFORMANCE:BOOL=OFF
// g3log unit tests
ADD_G3LOG_UNIT_TEST:BOOL=OFF
// Use DBUG logging level instead of DEBUG.
// By default DEBUG is the debugging level
CHANGE_G3LOG_DEBUG_TO_DBUG:BOOL=OFF
// Windows only: Use __FUNCSIG__ instead of the default __FUNCTION__
// to show LOG function location
// WARNING: using this in heavily templated code, like boost can expand
// the function name into massive size
WINDOWS_FUNCSIG:BOOL=OFF
// gcc/clang only: Use __PRETTY_FUNCTION__ instead of the default __FUNCTION__
// to show LOG function location
// WARNING: using this in heavily templated code, like boost can expand
// the function name into massive size
PRETTY_FUNCTION:BOOL=OFF
// Specifies the build type on single-configuration generators.
// Possible values are empty, Debug, Release, RelWithDebInfo, MinSizeRel, …
CMAKE_BUILD_TYPE:STRING=
// Install path prefix, prepended onto install directories.
// This variable defaults to /usr/local on UNIX
// and c:/Program Files/${PROJECT_NAME} on Windows.
CMAKE_INSTALL_PREFIX:PATH=
// The prefix used in the built package.
// On Linux, if this option is not set:
// 1) If CMAKE_INSTALL_PREFIX is given, then it will be
// set with the value of CMAKE_INSTALL_PREFIX by g3log.
// 2) Otherwise, it will be set as /usr/local by g3log.
CPACK_PACKAGING_INSTALL_PREFIX:PATH=
// Enable Visual Studio break point when receiving a fatal exception.
// In __DEBUG mode only
DEBUG_BREAK_AT_FATAL_SIGNAL:BOOL=OFF
// Vectored exception / crash handling with improved stack trace
ENABLE_FATAL_SIGNALHANDLING:BOOL=ON
// Vectored exception / crash handling with improved stack trace
ENABLE_VECTORED_EXCEPTIONHANDLING:BOOL=ON
// iOS version of library.
G3_IOS_LIB:BOOL=OFF
// Log full filename
G3_LOG_FULL_FILENAME:BOOL=OFF
// Build shared library
G3_SHARED_LIB:BOOL=ON
// Build shared runtime library MSVC
G3_SHARED_RUNTIME:BOOL=ON
// Turn ON/OFF log levels.
// An disabled level will not push logs of that level to the sink.
// By default dynamic logging is disabled
USE_DYNAMIC_LOGGING_LEVELS:BOOL=OFF
// Use dynamic memory for message buffer during log capturing
USE_G3_DYNAMIC_MAX_MESSAGE_SIZE:BOOL=OFF
...
```
For additional option context and comments please also see [Options.cmake](https://github.com/KjellKod/g3log/blob/master/Options.cmake)
If you want to leave everything as it was, then you should:
```
cmake ..
```
You may also specify one or more of those options listed above from the command line.
For example, on Windows:
```
cmake .. -G "Visual Studio 15 2017"
-DG3_SHARED_LIB=OFF
-DCMAKE_INSTALL_PREFIX=C:/g3log
-DADD_G3LOG_UNIT_TEST=ON
-DADD_FATAL_EXAMPLE=OFF
```
will use a Visual Studio 2017 solution generator, build g3log as a static library, headers and libraries will be installed to `C:\g3log` when installed from source, enable unit testing, but do not build fatal example.
MinGW users on Windows may find they should use a different generator:
```
cmake .. -G "MinGW Makefiles"
```
By default, headers and libraries will be installed to `/usr/local` on Linux when installed from build tree via `make install`. You may overwrite it by:
```
cmake .. -DCMAKE_INSTALL_PREFIX=/usr
```
This will install g3log to `/usr` instead of `/usr/local`.
Linux/OSX package maintainers may be interested in the `CPACK_PACKAGING_INSTALL_PREFIX`. For example:
```
cmake .. -DCPACK_PACKAGING_INSTALL_PREFIX=/usr/local
```
## <a name="build-commands">Build Commands</a>
Once the configuration is done, you may build g3log with:
```
# Suppose you are still in the `build` directory. I won't repeat it anymore!
cmake --build . --config Release
```
You may also build it with a system-specific way.
On Linux, OSX and MinGW:
```
make
```
On Windows:
```
msbuild g3log.sln /p:Configuration=Release
```
Windows users can also open the generated Visual Studio solution file and build it happily.
## <a name="installing">Installation</a>
Install from source in a CMake way:
```
cmake --build . --target install
```
Linux users may also use:
```
sudo make install
```
You may also create a package first and install g3log with it. See the next section.
## <a name=packaging>Packaging</a>
A CMake way:
```
cmake --build . --config Release --target package
```
or
```
cpack -C Release
```
if the whole library has been built in the previous step.
It will generate a ZIP package on Windows, and a DEB package on Linux.
Linux users may also use a Linux way:
```
make package
```
If you want to use a different package generator, you should specify a `-G` option.
On Windows:
```
cpack -C Release -G NSIS;7Z
```
this will create a installable NSIS package and a 7z package.
*Note:* To use the NSIS generator, you should install [```NSIS```](https://nsis.sourceforge.io/Download) first.
On Linux:
```
cpack -C Release -G TGZ
```
this will create a .tar.gz archive for you.
Once done, you may install or uncompress the package file to the target machine. For example, on Debian or Ubuntu:
```
sudo dpkg -i g3log-<version>-Linux.deb
```
will install the g3log library to `CPACK_PACKAGING_INSTALL_PREFIX`.
## <a name="testing">Testing</a>
By default, tests will be built. To disable unit testing, you should turn off `ADD_G3LOG_UNIT_TEST`.
Suppose the build process has completed, then you can run the tests with:
```
ctest -C Release
```
or:
```
make test
```
for Linux users.
or for a detailed gtest output of all the tests:
```
cd build;
../scripts/runAllTests.sh
```
## <a name="cmake-module">CMake module</a>
g3log comes with a CMake module. Once installed, it can be found under `${CMAKE_INSTALL_PREFIX}/lib/cmake/g3log`. Users can use g3log in a CMake-based project this way:
```
find_package(g3log CONFIG REQUIRED)
target_link_libraries(main PRIVATE g3log)
```
To make sure that CMake can find g3log, you also need to tell CMake where to search for it:
```
cmake .. -DCMAKE_PREFIX_PATH=<g3log's install prefix>
```
## <a name="build_options">Build Options</a>
The build options are defined in the file [Options.cmake](https://github.com/KjellKod/g3log/blob/master/Build.cmake)
build options are generated and saved to a header file. This avoid having to set the define options in the client source code
[introduction](index.md) | [detailed information](g3log_usage.md) | [**Configure & Build**](building.md) | [API description](API.md) | [Custom log formatting](API_custom_formatting.md)

85
docs/codespaces.md Normal file
View File

@ -0,0 +1,85 @@
# Codespaces
You can experiment with codespaces and g3log.
## Learn about Github Codespaces
For an introduction to codespaces you can check out [example c++ codespace](https://github.com/microsoft/vscode-remote-try-cpp/tree/main) and [using-github-codespaces-with-github-cli](https://docs.github.com/en/codespaces/developing-in-a-codespace/using-github-codespaces-with-github-cli)
# Commandline codespaces Quick Reference
1. List all your codespaces `gh codespace list`
2. Create a new codespace `gh codespace create -r OWNER/REPO_NAME [-b BRANCH]`. Ref [docs/github: Creating a codespace for a repository](https://docs.github.com/en/codespaces/developing-in-a-codespace/creating-a-codespace-for-a-repository)
3. View codebase details `gh codespace view`
4. Stop `gh codespace stop -c CODESPACE-NAME`
5. Delete `gh codespace delete -c CODESPACE-NAME`
6. Rebuild `gh codespace rebuild`
7. Rename `gh codespace edit -c CODESPACE-NAME -d DISPLAY-NAME`
8. SSH into REMOTE codespace `gh codespace ssh -c CODESPACE-NAME`
9. Open a remote codespace in CVisual Studio `gh codespace code -c CODESPACE-NAME` (ref: [github:doc cs studio](https://docs.github.com/en/codespaces/developing-in-a-codespace/using-github-codespaces-in-visual-studio-code))
10. Copy local file to/from codespace `gh codespace cp [-r] SOURCE(S) DESTINATION`. Example: Copy a file from the local machine to the $HOME directory of a codespace: `gh codespace cp myfile.txt remote:`. Example Copy a file from a codespace to the current directory on the local machine: `gh codespace cp remote:myfile.txt .` (more information available [here](https://cli.github.com/manual/gh_codespace_cp))
# Try g3log in a local dev container.
Please note that this will build g3log as if it's on a Debian Linux platform.
1. Clone this repository to your local filesystem.
2. Start Visual Studio Code. Press F1 and select the `Dev Containers: Open Folder in Container...` command.
3. Select the cloned copy of this g3log folder, wait for the container to start, and try things out! You should have debian C++ environment at hand.
### Example cmake configuration and build
```
Open a terminal in Visual Studio Code
mkdir debianbuild
cd debianbuild
cmake -DADD_G3LOG_UNIT_TEST=ON -DADD_G3LOG_BENCH_PERFORMANCE=ON ..
make -j
```
### Example runs
1. performance test in the container `./g3log-performance-threaded_mean 4`
2. unit tests `ctest -v`
3. Try a fatal example with dumped stack trace `./g3log-FATAL-contract`
### Example with Debugging.
Without any need to set up environment on your local machine you can also use Codespaces to debug examples, unit tests etc of g3log.
The pesky thing with VSCode, especially with cmake is to set up the launh.json.
It's a little bit easier if you open a VSCode terminal and do the cmake configuration and build there. Then the `launch.json` only needs to
contain information about the pecific executable.
Here we try out the `g3log-FATAL-contract` after cmake configure with `-DCMAKE_BUILD_TYPE=Debug`
```
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
// Remember to build the specific part of cmake with
// "cmake -DCMAKE_BUILD_TYPE=Debug" if you want to be able to debug it.
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Start",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/g3log-FATAL-contract",
"MIMode": "gdb",
"cwd": "${workspaceFolder}/build"
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
]
}
```

15
docs/contributing.md Normal file
View File

@ -0,0 +1,15 @@
# Information for contributing to g3log
## License
[LICENSE](https://github.com/KjellKod/g3log/blob/master/LICENSE)
## Contributing
[CONTRIBUTING.md](https://github.com/KjellKod/g3log/blob/master/CONTRIBUTING.md)
### Code of conduct
[CODE_OF_CONDUCT.md](https://github.com/KjellKod/g3log/blob/master/CODE_OF_CONDUCT.md)
### Pull request template
[PULL_REQUEST_TEMPLATE.md](https://github.com/KjellKod/g3log/blob/master/PULL_REQUEST_TEMPLATE.md)

BIN
docs/event_sequence.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

BIN
docs/fatal_log_sequence.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

221
docs/g3log_usage.md Normal file
View File

@ -0,0 +1,221 @@
[introduction](index.md) | [**detailed information**](g3log_usage.md) | [Configure & Build](building.md) | [API description](API.md) | [Custom log formatting](API_custom_formatting.md)
# How to use g3log
G3log is an asynchronous logger with dynamic sinks
## Example USAGE
#### Optional to use either streaming or printf-like syntax
```
LOG(INFO) << "streaming API is as easy as ABC or " << 123;
LOGF(WARNING, "Printf-style syntax is also %s", "available");
```
## <a name="what-g3log-is">What g3Log is</a>
* ***G3log*** is the acting name for the third version of g2log and it stands for **g3log with dynamic sinks**
* G3log is an asynchronous, "crash-safe" logger. You can read more about it here [[g2log version]](
http://www.codeproject.com/Articles/288827/g2log-An-efficient-asynchronous-logger-using-Cplus)
* You can choose to use the default log receiver which saves all LOG calls to file, **or** you can choose to use your own custom made log receiver(s), **or** both, **or** as many sinks as you need.
#### <a name="#conditional-logging">Conditional logging</a>
int less = 1; int more = 2
LOG_IF(INFO, (less<more)) <<"If [true], then this text will be logged";
// or with printf-like syntax
LOGF_IF(INFO, (less<more), "if %d<%d then this text will be logged", less,more);
#### <a name="design-by-contract">Design-by-Contract</a>
*CHECK(false)* will trigger a "fatal" message. It will be logged, and then the
application will exit.
```
CHECK(less != more); // not FATAL
CHECK(less > more) << "CHECK(false) triggers a FATAL message";
```
### Detailed API documentation
Please look at [API.md](API.md) for detailed API documentation
## <a name="benefits-with-g3log">Benefits you get when using g3log</a>
1. Easy to use, clean syntax and a blazing fast logger.
2. All the slow log I/O disk access is done in a background thread. This ensures that the LOG caller can immediately continue with other tasks and do not have to wait for the LOG call to finish.
3. G3log provides logging, Design-by-Contract [#CHECK], and flush of log to file at
shutdown. Buffered logs will be written to the sink before the application shuts down.
4. It is thread safe, so using it from multiple threads is completely fine.
5. It is *CRASH SAFE*. It will save the made logs to the sink before it shuts down.
The logger will catch certain fatal events *(Linux/OSX: signals, Windows: fatal OS exceptions and signals)* , so if your application crashes due to, say a segmentation fault, *SIGSEGV*, it will log and save the crash and all previously buffered log entries before exiting.
6. It is cross platform. Tested and used by me or by clients on OSX, Windows, Ubuntu, CentOS
7. G3log and G2log are used worldwide in commercial products as well as hobby projects. G2log was introduced in early 2011 and is now retired.
8. The code is given for free as public domain. This gives the option to change, use, and do whatever with it, no strings attached.
9. *[g3log](https://github.com/KjellKod/g3log)* : is made to facilitate easy adding of custom log receivers. Its tested on at least the following platforms with **Linux**(Clang/gcc), **Windows** (mingw, visual studio) and **OSX**. My recommendation is to go with g3log if you have full C++17 support
C++11 support up to version: https://github.com/KjellKod/g3log/releases/tag/1.3.1).
C++14 support up to version: https://github.com/KjellKod/g3log/releases/tag/1.3.4
## <a name="g3log-with-sinks">G3log with sinks</a>
[Sinks](http://en.wikipedia.org/wiki/Sink_(computing)) are receivers of LOG calls. G3log comes with a default sink (*the same as g3log uses*) that can be used to save log to file. A sink can be of *any* class type without restrictions as long as it can either receive a LOG message as a *std::string* **or** as a *g3::LogMessageMover*.
The *std::string* comes pre-formatted. The *g3::LogMessageMover* is a wrapped struct that contains the raw data for custom handling in your own sink.
A sink is *owned* by the g3log and is added to the logger inside a ```std::unique_ptr```. The sink can be called though its public API through a *handler* which will asynchronously forward the call to the receiving sink.
It is <a name="crazy-simple">crazy simple to create a custom sink</a>. This example show what is needed to make a custom sink that is using custom log formatting but only using that
for adding color to the default log formatting. The sink forwards the colored log to cout
```cpp
// in file Customsink.hpp
#pragma once
#include <string>
#include <iostream>
#include <g3log/logmessage.hpp>
struct CustomSink {
// Linux xterm color
// http://stackoverflow.com/questions/2616906/how-do-i-output-coloured-text-to-a-linux-terminal
enum FG_Color {YELLOW = 33, RED = 31, GREEN=32, WHITE = 97};
FG_Color GetColor(const LEVELS level) const {
if (level.value == WARNING.value) { return YELLOW; }
if (level.value == DEBUG.value) { return GREEN; }
if (g3::internal::wasFatal(level)) { return RED; }
return WHITE;
}
void ReceiveLogMessage(g3::LogMessageMover logEntry) {
auto level = logEntry.get()._level;
auto color = GetColor(level);
std::cout << "\033[" << color << "m"
<< logEntry.get().toString() << "\033[m" << std::endl;
}
};
// in main.cpp, main() function
auto sinkHandle = logworker->addSink(std::make_unique<CustomSink>(),
&CustomSink::ReceiveLogMessage);
```
## Adding and Removing Sinks
You can safely remove and add sinks during the running of your program.
**Keep in mind**
- *Initialization of the logger should happen before you have started any other threads that may call the logger.*
- *Destruction of the logger (RAII concept) should happen AFTER shutdown of other threads that are calling the logger.*
**Adding Sinks**
```cpp
auto sinkHandle1 = logworker->addSink(std::make_unique<CustomSink>(),
&CustomSink::ReceiveLogMessage);
auto sinkHandle2 = logworker->addDefaultLogger(argv[0],
path_to_log_file);
logworker->removeSink(std::move(sinkHandle1)); // this will in a thread-safe manner remove the sinkHandle1
logworker->removeAllSinks(); // this will in a thread-safe manner remove any sinks.
```
**More sinks** can be found in the repository **[github.com/KjellKod/g3sinks](https://github.com/KjellKod/g3sinks)**.
## <a name="code-examples">Code Examples</a>
Example usage where a <a name="custom-sink">custom sink</a> is added. A function is called though the sink handler to the actual sink object.
```cpp
// main.cpp
#include <g3log/g3log.hpp>
#include <g3log/logworker.hpp>
#include <memory>
#include "CustomSink.h"
int main(int argc, char**argv) {
using namespace g3;
std::unique_ptr<LogWorker> logworker{ LogWorker::createLogWorker() };
auto sinkHandle = logworker->addSink(std::make_unique<CustomSink>(),
&CustomSink::ReceiveLogMessage);
// initialize the logger before it can receive LOG calls
initializeLogging(logworker.get());
LOG(WARNING) << "This log call, may or may not happend before"
<< "the sinkHandle->call below";
// You can call in a thread safe manner public functions on your sink
// The call is asynchronously executed on your custom sink.
std::future<void> received = sinkHandle->call(&CustomSink::Foo,
param1, param2);
// If the LogWorker is initialized then at scope exit the g3::internal::shutDownLogging() will be called.
// This is important since it protects from LOG calls from static or other entities that will go out of
// scope at a later time.
//
// It can also be called manually:
g3::internal::shutDownLogging();
}
// some_file.cpp : To show how easy it is to get the logger to work
// in other parts of your software
#include <g3log/g3log.hpp>
void SomeFunction() {
...
LOG(INFO) << "Hello World";
}
```
Example usage where a the <a name="default-file-logger">default file logger</a> is used **and** a custom sink is added
```cpp
// main.cpp
#include <g3log/g3log.hpp>
#include <g3log/logworker.hpp>
#include <memory>
#include "CustomSink.h"
int main(int argc, char**argv) {
using namespace g3;
auto worker = LogWorker::createLogWorker();
auto defaultHandler = worker->addDefaultLogger(argv[0],
path_to_log_file);
// logger is initialized
g3::initializeLogging(worker.get());
LOG(DEBUG) << "Make log call, then add another sink";
worker->addSink(std::make_unique<CustomSink>(),
&CustomSink::ReceiveLogMessage);
...
}
```
[introduction](index.md) | [**detailed information**](g3log_usage.md) | [Configure & Build](building.md) | [API description](API.md) | [Custom log formatting](API_custom_formatting.md)

132
docs/index.md Normal file
View File

@ -0,0 +1,132 @@
[**introduction**](index.md) | [detailed information](g3log_usage.md) | [Configure & Build](building.md) | [API description](API.md) | [Custom log formatting](API_custom_formatting.md)
# Welcome to g3log
G3log is an asynchronous logger with three main features:
1. Intuitive `LOG(...)` API
2. `Design-by-contract` `CHECK(...)` functionality
3. Fatal crash handling for graceful shutdown of the logged process without loosing any log details up to the point of the crash
The super quick introduction to g3log can be seen in the steps 1 - 9 below.
For more in-depth information please see the full usage description in [g3log_usage.md](g3log_usage.md). The internal API for more advanced integration with g3log can be accessed in [API.md](API.md)
## 1. Easy usage in files
Avoid deep dependency injection complexity and instead get access to the logger as easy as
```
#include <g3log/g3log.hpp>
```
## 2. Access to streaming and print_f log call syntax
Both streaming syntax `LOG` and print_f `LOGF` syntax are available.
```
LOGF(INFO, "Hi log %d", 123);
LOG(INF) << "Hi log " << 123;
```
## 3. Conditional logging
```
LOG_IF(INFO, (1 < 2)) << "If true this message will be logged";
LOGF_IF(INFO, (1 < 2), "If true, then this %s will be logged", "message");
```
## 4. Design-by-contract framework
```
CHECK(less != more); // not fatal
CHECK_F(less > more, "CHECK(false) will trigger a fatal message")
```
## 5. Handling of fatal
By default g3log will capture fatal events such as `LOG(FATAL)`, `CHECK(false)` and otherwise fatal signals such as:
```
SIGABRT
SIGFPE
SIGILL
SIGSEGV
SIGTERM
```
When a fatal event happens the not-yet written log activity will be flushed to the logging sinks. Only when all logging activity up to the point of the fatal event has happend, will g3log allow the fatal event to proceed and exit the process.
If `object` symbols are available the fatal handler will attempt to push the stacktrace up to the fatal reason to the logging sink.
#### 5b. Overriding and customization of fatal event handling
For overriding fatal error handling to use your own, or to add code `hooks` that you want to execute please see the [API.md](API.md) doc.
## 6. Default and Custom logging levels
The default logging levels are `DEBUG`, `INFO`, `WARNING` and `FATAL`. You can define your own logging levels or completely replace the logging levels. Ref: [API.md](API.md)
### 7. Log filtering
Log filtering is handled in g3log if dynamic logging levels are enabled
in the configuration. See the [API.md](API.md) for information. Log filtering can also be handled through the sink as can be seen in [github/Kjellod/g3sinks](https://github.com/KjellKod/g3sinks)
## 8. 3rd party and custom logging sinks
The default logging sink has no external 3rd party dependencies. For more logging sinks please see [github/Kjellod/g3sinks](https://github.com/KjellKod/g3sinks)
- log rotate
- log to syslog
- log to colored terminal output
- log rotate with filter
See the [API.md](API.md) for more information about the simple steps to creating your own logging sink.
## 9. Log instantiation
With the default application name left as is (i.e. "g3log") a creation of the logger could look something like this:
```cpp
const std::string directory = "./";
const std::string name = "TestLogFile";
auto worker = g3::LogWorker::createLogWorker();
auto handle = worker->addDefaultLogger(name, directory);
```
The resulting filename would be something like:
```
./TestLogFile.g3log.20160217-001406.log
```
## <a name="performance">Performance</a>
G3log aims to keep all background logging to sinks with as little log overhead as possible to the logging sink and with as small "worst case latency" as possible. For this reason g3log is a good logger for many systems that deal with critical tasks. Depending on platform the average logging overhead will differ. On my 2010 laptop the average call, when doing extreme performance testing, will be about ~2 us.
The worst case latency is kept stable with no extreme peaks, in spite of any sudden extreme pressure. I have a blog post regarding comparing worst case latency for g3log and other loggers which might be of interest.
You can find it here: https://kjellkod.wordpress.com/2015/06/30/the-worlds-fastest-logger-vs-g3log/
## <a name="continuos_integration">Continuos Integration</a>
The g3log repository is evaluating both github actions and CircleCI for executing test coverage, installation and document generation. For windows the repo is still relying on appveyor. In case you want to look into change any of these setups the following files are the ones of interest.
```
1. appveyor --> g3log/appveyor.yml
2. circleCI --> g3log/.circleci/config.yml
3. github actions --> g3log/.github/workflows/*.yml
```
## <a name="feedback">Feedback</a>
If you like this logger (or not) it would be nice with some feedback. That way I can improve g3log and it is always nice to hear when and how someone is using it.
If you have ANY questions or problems please do not hesitate in contacting me at
`Hedstrom @ Kjellod. cc`
# <a name="say-thanks">Say Thanks</a>
This logger is available for free and all of its source code is public domain. A great way of saying thanks is to send a donation. It would go a long way not only to show your support but also to boost continued development.
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/g3log/25)
* $5 for a cup of coffee
* $25 for a late evening coding with takeout
Cheers
Kjell *(a.k.a. KjellKod)*
[**introduction**](index.md) | [detailed information](g3log_usage.md) | [Configure & Build](building.md) | [API description](API.md) | [Custom log formatting](API_custom_formatting.md)

BIN
docs/log_sequence.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

46
example/Example.cmake Normal file
View File

@ -0,0 +1,46 @@
# g3log is a KjellKod Logger
# 2015 @author Kjell Hedström, hedstrom@kjellkod.cc
# ==================================================================
# 2015 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own
# risk and comes with no warranties.
#
# This code is yours to share, use and modify with no strings attached
# and no restrictions or obligations.
# ===================================================================
# ==============================================================
# -DUSE_SIMPLE_EXAMPLE=OFF : to turn off the fatal examples
#
#
# Leaving it to ON will create
# g3log-FATAL-sigsegv
# g3log-FATAL-contract
#
# ==============================================================
IF (MSVC OR MINGW)
set(EXAMPLE_PLATFORM_LINK_LIBRIES dbghelp)
ENDIF()
set(DIR_EXAMPLE ${g3log_SOURCE_DIR}/example)
option (ADD_FATAL_EXAMPLE "Fatal (fatal-crashes/contract) examples " ON)
IF (ADD_FATAL_EXAMPLE)
message( STATUS "-DADD_FATAL_EXAMPLE=ON" )
message( STATUS "\t\t[contract][sigsegv][fatal choice] are examples of when g3log comes in handy\n" )
include_directories (${DIR_EXAMPLE})
add_executable(g3log-FATAL-contract ${DIR_EXAMPLE}/main_contract.cpp)
add_executable(g3log-FATAL-sigsegv ${DIR_EXAMPLE}/main_sigsegv.cpp)
add_executable(g3log-FATAL-choice ${DIR_EXAMPLE}/main_fatal_choice.cpp)
target_link_libraries(g3log-FATAL-contract ${G3LOG_LIBRARY} ${EXAMPLE_PLATFORM_LINK_LIBRIES})
target_link_libraries(g3log-FATAL-sigsegv ${G3LOG_LIBRARY} ${EXAMPLE_PLATFORM_LINK_LIBRIES})
target_link_libraries(g3log-FATAL-choice ${G3LOG_LIBRARY} ${EXAMPLE_PLATFORM_LINK_LIBRIES})
ELSE()
message( STATUS "-DADD_SIMPLE_EXAMPLE=OFF" )
ENDIF (ADD_FATAL_EXAMPLE)

69
example/main_contract.cpp Normal file
View File

@ -0,0 +1,69 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#include <g3log/g3log.hpp>
#include <g3log/logworker.hpp>
#include <iomanip>
#include <iostream>
#include <thread>
namespace {
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
const std::string path_to_log_file = "./";
#else
const std::string path_to_log_file = "/tmp/";
#endif
} // namespace
namespace example_fatal {
void killWithContractIfNonEqual(int first, int second) {
CHECK(first == second) << "Test to see if contract works: onetwothree: " << 123 << ". This should be at the end of the log, and will exit this example";
}
} // namespace example_fatal
int main(int argc, char** argv) {
double pi_d = 3.1415926535897932384626433832795;
float pi_f = 3.1415926535897932384626433832795f;
auto worker = g3::LogWorker::createLogWorker();
auto handle = worker->addDefaultLogger(argv[0], path_to_log_file);
g3::initializeLogging(worker.get());
std::future<std::string> log_file_name = handle->call(&g3::FileSink::fileName);
// Exmple of overriding the default formatting of log entry
auto changeFormatting = handle->call(&g3::FileSink::overrideLogDetails, g3::LogMessage::FullLogDetailsToString);
const std::string newHeader = "\t\tLOG format: [YYYY/MM/DD hh:mm:ss uuu* LEVEL THREAD_ID FILE->FUNCTION:LINE] message\n\t\t(uuu*: microseconds fractions of the seconds value)\n\n";
// example of ovrriding the default formatting of header
auto changeHeader = handle->call(&g3::FileSink::overrideLogHeader, newHeader);
changeFormatting.wait();
changeHeader.wait();
std::cout << "* This is an example of g3log. It WILL exit by a failed CHECK(...)" << std::endl;
std::cout << "* that acts as a FATAL trigger. Please see the generated log and " << std::endl;
std::cout << "* compare to the code at:\n* \t g3log/test_example/main_contract.cpp" << std::endl;
std::cout << "*\n* Log file: [" << log_file_name.get() << "]\n\n"
<< std::endl;
LOGF(INFO, "Hi log %d", 123);
LOG(INFO) << "Test SLOG INFO";
LOG(G3LOG_DEBUG) << "Test SLOG DEBUG";
LOG(INFO) << "one: " << 1;
LOG(INFO) << "two: " << 2;
LOG(INFO) << "one and two: " << 1 << " and " << 2;
LOG(G3LOG_DEBUG) << "float 2.14: " << 1000 / 2.14f;
LOG(G3LOG_DEBUG) << "pi double: " << pi_d;
LOG(G3LOG_DEBUG) << "pi float: " << pi_f;
LOG(G3LOG_DEBUG) << "pi float (width 10): " << std::setprecision(10) << pi_f;
LOGF(INFO, "pi float printf:%f", pi_f);
// FATAL SECTION
int smaller = 1;
int larger = 2;
example_fatal::killWithContractIfNonEqual(smaller, larger);
}

View File

@ -0,0 +1,335 @@
/** ==========================================================================
* 2014 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#include <g3log/g3log.hpp>
#include <g3log/logworker.hpp>
#include <cctype>
#include <chrono>
#include <exception>
#include <future>
#include <iostream>
#include <string>
#include <thread>
#include <vector>
#ifndef _MSC_VER
#define NOEXCEPT noexcept
#else
#define NOEXCEPT throw()
#endif
namespace {
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
const std::string path_to_log_file = "./";
#else
const std::string path_to_log_file = "/tmp/";
#endif
void ToLower(std::string& str) {
for (auto& character : str) {
character = std::tolower(character);
}
}
void RaiseSIGABRT() {
raise(SIGABRT);
LOG(G3LOG_DEBUG) << " trigger exit";
LOG(WARNING) << "Expected to have died by now...";
}
void RaiseSIGFPE() {
LOG(G3LOG_DEBUG) << " trigger exit";
LOGF_IF(INFO, (false != true), "Exiting %s SIGFPE", "by");
raise(SIGFPE);
LOG(WARNING) << "Expected to have died by now...";
}
void RaiseSIGSEGV() {
LOG(G3LOG_DEBUG) << " trigger exit";
LOG(G3LOG_DEBUG) << "Exit by SIGSEGV";
raise(SIGSEGV);
LOG(WARNING) << "Expected to have died by now...";
}
void RaiseSIGILL() {
LOG(G3LOG_DEBUG) << " trigger exit";
LOGF(G3LOG_DEBUG, "Exit by %s", "SIGILL");
raise(SIGILL);
LOG(WARNING) << "Expected to have died by now...";
}
void RAiseSIGTERM() {
LOG(G3LOG_DEBUG) << " trigger exit";
LOGF_IF(INFO, (false != true), "Exiting %s SIGFPE", "by");
raise(SIGTERM);
LOG(WARNING) << "Expected to have died by now...";
}
int gShouldBeZero = 1;
void DivisionByZero() {
LOG(G3LOG_DEBUG) << " trigger exit Executing DivisionByZero: gShouldBeZero: " << gShouldBeZero;
LOG(INFO) << "Division by zero is a big no-no";
int value = 3;
auto test = value / gShouldBeZero;
LOG(WARNING) << "Expected to have died by now..., test value: " << test;
}
void IllegalPrintf() {
LOG(G3LOG_DEBUG) << " trigger exit";
LOG(G3LOG_DEBUG) << "Impending doom due to illeteracy";
LOGF(INFO, "2nd attempt at ILLEGAL PRINTF_SYNTAX %d EXAMPLE. %s %s", "hello", 1);
LOG(WARNING) << "Expected to have died by now...";
}
void OutOfBoundsArrayIndexing() {
LOG(G3LOG_DEBUG) << " trigger exit";
std::vector<int> v;
v[0] = 5;
LOG(WARNING) << "Expected to have died by now...";
}
void AccessViolation() {
LOG(G3LOG_DEBUG) << " trigger exit";
char* ptr = 0;
LOG(INFO) << "Death by access violation is imminent";
*ptr = 0;
LOG(WARNING) << "Expected to have died by now...";
}
void NoExitFunction() {
LOG(G3LOG_DEBUG) << " trigger exit";
CHECK(false) << "This function should never be called";
}
void RaiseSIGABRTAndAccessViolation() {
LOG(G3LOG_DEBUG) << " trigger exit";
auto f1 = std::async(std::launch::async, &RaiseSIGABRT);
auto f2 = std::async(std::launch::async, &AccessViolation);
f1.wait();
f2.wait();
}
using deathfunc = void (*)(void);
void Death_x10000(deathfunc func, std::string funcname) NOEXCEPT {
LOG(G3LOG_DEBUG) << " trigger exit";
std::vector<std::future<void>> asyncs;
asyncs.reserve(10000);
for (auto idx = 0; idx < 10000; ++idx) {
asyncs.push_back(std::async(std::launch::async, func));
}
for (const auto& a : asyncs) {
a.wait();
}
std::cout << __FUNCTION__ << " unexpected result. Death by " << funcname << " did not crash and exit the system" << std::endl;
}
void Throw() NOEXCEPT {
LOG(G3LOG_DEBUG) << " trigger exit";
std::future<int> empty;
empty.get();
// --> thows future_error http://en.cppreference.com/w/cpp/thread/future_error
// example of std::exceptions can be found here: http://en.cppreference.com/w/cpp/error/exception
}
void SegFaultAttempt_x10000() NOEXCEPT {
deathfunc f = [] {
char* ptr = 0;
*ptr = 1;
};
Death_x10000(f, "throw uncaught exception... and then some sigsegv calls");
}
void AccessViolation_x10000() {
Death_x10000(&AccessViolation, "AccessViolation");
}
void FailedCHECK() {
LOG(G3LOG_DEBUG) << " trigger exit";
CHECK(false) << "This is fatal";
}
void CallActualExitFunction(std::function<void()> fatal_function) {
fatal_function();
}
void CallExitFunction(std::function<void()> fatal_function) {
CallActualExitFunction(fatal_function);
}
void ExecuteDeathFunction(const bool runInNewThread, int fatalChoice) {
LOG(G3LOG_DEBUG) << "trigger exit";
auto exitFunction = &NoExitFunction;
switch (fatalChoice) {
case 1:
exitFunction = &RaiseSIGABRT;
break;
case 2:
exitFunction = &RaiseSIGFPE;
break;
case 3:
exitFunction = &RaiseSIGSEGV;
break;
case 4:
exitFunction = &RaiseSIGILL;
break;
case 5:
exitFunction = &RAiseSIGTERM;
break;
case 6:
exitFunction = &DivisionByZero;
gShouldBeZero = 0;
DivisionByZero();
break;
case 7:
exitFunction = &IllegalPrintf;
break;
case 8:
exitFunction = &OutOfBoundsArrayIndexing;
break;
case 9:
exitFunction = &AccessViolation;
break;
case 10:
exitFunction = &RaiseSIGABRTAndAccessViolation;
break;
case 11:
exitFunction = &Throw;
break;
case 12:
exitFunction = &FailedCHECK;
break;
case 13:
exitFunction = &AccessViolation_x10000;
break;
case 14:
exitFunction = &SegFaultAttempt_x10000;
break;
default:
break;
}
if (runInNewThread) {
auto dieInNearFuture = std::async(std::launch::async, CallExitFunction, exitFunction);
dieInNearFuture.wait();
} else {
CallExitFunction(exitFunction);
}
std::string unexpected = "Expected to exit by FATAL event. That did not happen (printf choice in Windows?).";
unexpected.append("Choice was: ").append(std::to_string(fatalChoice)).append(", async?: ").append(std::to_string(runInNewThread)).append("\n\n***** TEST WILL RUN AGAIN *****\n\n");
std::cerr << unexpected << std::endl;
LOG(WARNING) << unexpected;
}
bool AskForAsyncDeath() {
std::string option;
while (true) {
option.clear();
std::cout << "Do you want to run the test in a separate thread? [yes/no]" << std::endl;
std::getline(std::cin, option);
ToLower(option);
if (("yes" != option) && ("no" != option)) {
std::cout << "\nInvalid value: [" << option << "]\n\n\n";
} else {
break;
}
}
return ("yes" == option);
}
int ChoiceOfFatalExit() {
std::string option;
int choice = {0};
while (true) {
std::cout << "\n\n\n\nChoose your exit" << std::endl;
std::cout << "By throwing an fatal signal" << std::endl;
std::cout << "or By executing a fatal code snippet" << std::endl;
std::cout << "[1] Signal SIGABRT" << std::endl;
std::cout << "[2] Signal SIGFPE" << std::endl;
std::cout << "[3] Signal SIGSEGV" << std::endl;
std::cout << "[4] Signal IGILL" << std::endl;
std::cout << "[5] Signal SIGTERM" << std::endl;
std::cout << "[6] Division By Zero" << std::endl;
std::cout << "[7] Illegal printf" << std::endl;
std::cout << "[8] Out of bounds array indexing " << std::endl;
std::cout << "[9] Access violation" << std::endl;
std::cout << "[10] Rasing SIGABRT + Access Violation in two separate threads" << std::endl;
std::cout << "[11] Throw a std::future_error" << std::endl;
std::cout << "[12] Just CHECK(false) (in this thread)" << std::endl;
std::cout << "[13] 10,000 Continious crashes with out of bounds array indexing" << std::endl;
std::cout << "[14] 10,000 Continious crashes with segmentation fault attempts" << std::endl;
std::cout << std::flush;
try {
std::getline(std::cin, option);
choice = std::stoi(option);
if (choice <= 0 || choice > 14) {
std::cout << "Invalid choice: [" << option << "\n\n";
} else {
return choice;
}
} catch (...) {
std::cout << "Invalid choice: [" << option << "\n\n";
}
}
}
void ForwardChoiceForFatalExit(bool runInNewThread, int fatalChoice) {
ExecuteDeathFunction(runInNewThread, fatalChoice);
}
void ChooseFatalExit() {
const bool runInNewThread = AskForAsyncDeath();
const int exitChoice = ChoiceOfFatalExit();
ForwardChoiceForFatalExit(runInNewThread, exitChoice);
}
} // namespace
void breakHere() {
std::ostringstream oss;
oss << "Fatal hook function: " << __FUNCTION__ << ":" << __LINE__ << " was called";
oss << " through g3::setFatalPreLoggingHook(). setFatalPreLoggingHook should be called AFTER g3::initializeLogging()" << std::endl;
LOG(G3LOG_DEBUG) << oss.str();
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
__debugbreak();
#endif
}
int main(int argc, char** argv) {
auto worker = g3::LogWorker::createLogWorker();
auto handle = worker->addDefaultLogger(argv[0], path_to_log_file);
g3::initializeLogging(worker.get());
g3::setFatalPreLoggingHook(&breakHere);
std::future<std::string> log_file_name = handle->call(&g3::FileSink::fileName);
std::cout << "**** G3LOG FATAL EXAMPLE ***\n\n"
<< "Choose your type of fatal exit, then "
<< " read the generated log and backtrace.\n"
<< "The logfile is generated at: [" << log_file_name.get() << "]\n\n"
<< std::endl;
LOGF(G3LOG_DEBUG, "Fatal exit example starts now, it's as easy as %d", 123);
LOG(INFO) << "Feel free to read the source code also in g3log/example/main_fatal_choice.cpp";
while (true) {
ChooseFatalExit();
}
LOG(WARNING) << "Expected to exit by fatal event, this code line should never be reached";
CHECK(false) << "Forced death";
return 0;
}

110
example/main_sigsegv.cpp Normal file
View File

@ -0,0 +1,110 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#include <g3log/g3log.hpp>
#include <g3log/logworker.hpp>
#include <iomanip>
#include <iostream>
#include <memory>
#include <thread>
namespace {
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
const std::string path_to_log_file = "./";
#else
const std::string path_to_log_file = "/tmp/";
#endif
} // namespace
namespace example_fatal {
// on Ubunti this caused get a compiler warning with gcc4.6
// from gcc 4.7.2 (at least) it causes a crash (as expected)
// On windows it'll probably crash too.
void tryToKillWithIllegalPrintout() {
std::cout << "\n\n***** Be ready this last example may 'abort' if on Windows/Linux_gcc4.7 " << std::endl
<< std::flush;
std::cout << "************************************************************\n\n"
<< std::endl
<< std::flush;
std::this_thread::sleep_for(std::chrono::seconds(1));
const std::string logging = "logging";
LOGF(G3LOG_DEBUG, "ILLEGAL PRINTF_SYNTAX EXAMPLE. WILL GENERATE compiler warning.\n\nbadly formatted message:[Printf-type %s is the number 1 for many %s]", logging.c_str());
}
// The function above 'tryToKillWithIllegalPrintout' IS system / compiler dependent. Older compilers sometimes did NOT generate a segmentation
// fault as expected by the illegal printf-format usage. just in case we exit by zero division"
void killByZeroDivision(int value) {
int zero = 0; // trying to fool the compiler to automatically warn
LOG(INFO) << "This is a bad operation [value/zero] : " << value / zero;
}
void tryToKillWithAccessingIllegalPointer(std::unique_ptr<std::string> badStringPtr) {
auto badPtr = std::move(badStringPtr);
LOG(INFO) << "Function calls through a nullptr object will trigger segmentation fault";
badStringPtr->append("crashing");
}
} // namespace example_fatal
int main(int argc, char** argv) {
double pi_d = 3.1415926535897932384626433832795;
float pi_f = 3.1415926535897932384626433832795f;
using namespace g3;
std::unique_ptr<LogWorker> logworker{LogWorker::createLogWorker()};
auto sinkHandle = logworker->addSink(std::make_unique<FileSink>(argv[0], path_to_log_file),
&FileSink::fileWrite);
initializeLogging(logworker.get());
std::future<std::string> log_file_name = sinkHandle->call(&FileSink::fileName);
std::cout << "* This is an example of g3log. It WILL exit by a FATAL trigger" << std::endl;
std::cout << "* Please see the generated log and compare to the code at" << std::endl;
std::cout << "* g3log/test_example/main.cpp" << std::endl;
std::cout << "*\n* Log file: [" << log_file_name.get() << "]\n\n"
<< std::endl;
LOGF(INFO, "Hi log %d", 123);
LOG(INFO) << "Test SLOG INFO";
LOG(G3LOG_DEBUG) << "Test SLOG DEBUG";
LOG(INFO) << "one: " << 1;
LOG(INFO) << "two: " << 2;
LOG(INFO) << "one and two: " << 1 << " and " << 2;
LOG(G3LOG_DEBUG) << "float 2.14: " << 1000 / 2.14f;
LOG(G3LOG_DEBUG) << "pi double: " << pi_d;
LOG(G3LOG_DEBUG) << "pi float: " << pi_f;
LOG(G3LOG_DEBUG) << "pi float (width 10): " << std::setprecision(10) << pi_f;
LOGF(INFO, "pi float printf:%f", pi_f);
//
// START: LOG Entris that were in the CodeProject article
//
//LOG(UNKNOWN_LEVEL) << "This log attempt will cause a compiler error";
LOG(INFO) << "Simple to use with streaming syntax, easy as abc or " << 123;
LOGF(WARNING, "Printf-style syntax is also %s", "available");
LOG_IF(INFO, (1 < 2)) << "If true this text will be logged";
LOGF_IF(INFO, (1 < 2), "if %d<%d : then this text will be logged", 1, 2);
LOG_IF(FATAL, (2 > 3)) << "This message should NOT throw";
LOGF(G3LOG_DEBUG, "This API is popular with some %s", "programmers");
LOGF_IF(G3LOG_DEBUG, (1 < 2), "If true, then this %s will be logged", "message");
// OK --- on Ubunti this caused get a compiler warning with gcc4.6
// from gcc 4.7.2 (at least) it causes a crash (as expected)
// On windows itll probably crash
example_fatal::tryToKillWithIllegalPrintout();
// try 2
std::unique_ptr<std::string> badStringPtr;
example_fatal::tryToKillWithAccessingIllegalPointer(std::move(badStringPtr));
// what happened? OK. let us just exit with SIGFPE
int value = 1; // system dependent but it SHOULD never reach this line
example_fatal::killByZeroDivision(value);
return 0;
}

View File

@ -1,276 +0,0 @@
# CMakeLists.txt cmake configuration for g2log test
# g2log is a KjellKod Logger
# 2011 @author Kjell Hedström, hedstrom@kjellkod.cc
# ==================================================================
# 2010 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own
# risk and comes with no warranties.
#
# This code is yours to share, use and modify with no strings attached
# and no restrictions or obligations.
# ===================================================================
# Below are details for compiling on Windows and Linux
# by default only an example g2log binary is created
# the performance and unit tests creation can be enabled by switching their
# OPTIONs from OFF to ON --- See below at around line 110
# 2012-05-29: justthread is no longer necessary on Windows (vs2011) and
# linux (gcc4.7.1)
# WINDOWS == README: Example how to setup environment + running an example
# Below written for VS11 (2012)
# 1. please use the "Visual Studio Command Prompt 11 (2012)"
# 2. from the g2log folder
# mkdir build
# cd build;
# 3. cmake -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 11" ..
# the "Visual Studio 11" .. does not require just::thread!
# 4. msbuild g2log_by_kjellkod.sln /p:Configuration=Release
# 5. Release\g2log-FATAL-example.exe
#
#
# . LINUX:To try this out from folder g2log:
# mkdir build
# cd build
# cmake .. # create makefiles in g2log/build directory
# make # link active_object, g2log and example code to get an "example" executable
# ./g2log-FATAL-example
# ============================================================================
cmake_minimum_required (VERSION 2.8)
ENABLE_LANGUAGE(CXX)
set(CMAKE_BUILD_TYPE Release)
project (g2log_by_kjellkod)
set(LOG_SRC ${g2log_by_kjellkod_SOURCE_DIR}/src)
set(DIR_UNIT_TEST ${g2log_by_kjellkod_SOURCE_DIR}/test_unit)
set(DIR_EXAMPLE ${g2log_by_kjellkod_SOURCE_DIR}/test_example)
set(DIR_PERFORMANCE ${g2log_by_kjellkod_SOURCE_DIR}/test_performance)
MESSAGE(" LOG_SRC = : ${LOG_SRC}")
include_directories(${LOG_SRC})
SET(ACTIVE_CPP0xx_DIR "Release")
# Detect 64 or 32 bit
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
# 64-bit project
SET(64_BIT_OS TRUE)
MESSAGE("A 64-bit OS detected")
else()
SET(64_BIT_OS FALSE)
MESSAGE("A 32-bit OS detected")
endif()
IF(UNIX)
MESSAGE("")
MESSAGE("cmake for *NIX ")
MESSAGE("if cmake finishes OK, do make")
MESSAGE("then run './g2log-FATAL-example' or whatever performance test you feel like trying")
MESSAGE("")
set(PLATFORM_LINK_LIBRIES rt)
# justthread not needed from gcc4.7.1
# set(PLATFORM_LINK_LIBRIES justthread rt)
# -rdynamic is needed for correct stack dumps with demangling
# -D_GLIBCXX_USE_NANOSLEEP is needed for this_thread sleep (unit testing)
set(CMAKE_CXX_FLAGS "-Wall -rdynamic -Wunused -std=c++11 ${CMAKE_CXX_FLAGS_DEBUG} -pthread -D_GLIBCXX_USE_NANOSLEEP")
set(SRC_PLATFORM_SPECIFIC ${LOG_SRC}/crashhandler_unix.cpp)
# -- justthread not needed for gcc4.7.1
# set(CMAKE_CXX_FLAGS "-Wall -rdynamic -Wunused -std=c++0x ${CMAKE_CXX_FLAGS_DEBUG} -pthread -I/usr/include/justthread")
# -- justhtread not needed for gcc4.7.1
# include_directories("/usr/include/justthread")
ENDIF(UNIX)
if (MSVC)
# VC11 bug: http://code.google.com/p/googletest/issues/detail?id=408
# add_definition(-D_VARIADIC_MAX=10)
# https://github.com/anhstudios/swganh/pull/186/files
ADD_DEFINITIONS (/D_VARIADIC_MAX=10)
MESSAGE(STATUS "- MSVC: Set variadic max to 10 for MSVC compatibility")
# Remember to set set target properties if using GTEST similar to done below on target "unit_test"
# "set_target_properties(unit_test PROPERTIES COMPILE_DEFINITIONS "GTEST_USE_OWN_TR1_TUPLE=0")
endif ()
#Visual Studio 2010 -- must use justthread. For now hardcoded for x64
IF(MSVC10)
MESSAGE("")
MESSAGE("Windows: Please run the command [cmake -DCMAKE_BUILD_TYPE=Release -G \"Visual Studio 10\" ..]")
MESSAGE("if cmake finishes OK, do 'msbuild g2log_by_kjellkod.sln /p:Configuration=Release'")
MESSAGE("then run 'Release\\g2log-FATAL-example.exe' or whatever performance test you feel like trying")
MESSAGE("")
set(PLATFORM_LINK_LIBRIES $ENV{PROGRAMFILES}/JustSoftwareSolutions/JustThread/lib/justthread_vc10_mdd.lib)
#set(PLATFORM_LINK_LIBRIES $ENV{PROGRAMFILES}/JustSoftwareSolutions/JustThread/lib/justthread_vc10x64_mdd.lib)
set(SRC_PLATFORM_SPECIFIC ${LOG_SRC}/crashhandler_win.cpp)
include_directories("$ENV{PROGRAMFILES}/JustSoftwareSolutions/JustThread/include")
ENDIF(MSVC10)
# Visual Studio 2011 -- std::thread etc are included with the Visual Studio package, so justthread dependencies are removed
IF(MSVC11)
MESSAGE("")
MESSAGE("Windows: Please run the command [cmake -DCMAKE_BUILD_TYPE=Release -G \"Visual Studio 11\" ..]")
MESSAGE("if cmake finishes OK, do 'msbuild g2log_by_kjellkod.sln /p:Configuration=Release'")
MESSAGE("then run 'Release\\g2log-FATAL-example.exe' or whatever performance test you feel like trying")
MESSAGE("")
set(SRC_PLATFORM_SPECIFIC ${LOG_SRC}/crashhandler_win.cpp)
ENDIF(MSVC11)
# GENERIC STEPS
# CODE SOURCES these +
set(SRC_CPP ${LOG_SRC}/g2logworker.cpp ${LOG_SRC}/g2log.cpp ${LOG_SRC}/g2time.cpp)
set(SRC_H ${LOG_SRC}/g2logworker.h ${LOG_SRC}/g2log.h ${LOG_SRC}/crashhandler.h ${LOG_SRC}/g2time.h ${LOG_SRC}/g2future.h)
set(SRC_FILES ${SRC_CPP} ${SRC_H} ${SRC_PLATFORM_SPECIFIC})
# add a ActiveObject library
add_library(lib_activeobject ${LOG_SRC}/active.cpp ${LOG_SRC}/active.h ${LOG_SRC}/shared_queue.h)
set_target_properties(lib_activeobject PROPERTIES LINKER_LANGUAGE CXX)
# add a g2log library
include_directories(src)
include_directories(${LOG_SRC})
MESSAGE(" LOG_SRC = : ${LOG_SRC}")
MESSAGE(" g2logger files: [${SRC_FILES}]")
add_library(lib_g2logger ${SRC_FILES})
set_target_properties(lib_g2logger PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(lib_g2logger lib_activeobject)
# ============================================================================
# OPTIONS: Turn OFF the ones that is of no interest to you
# ---- by default all is OFF: except 'g2log-FATAL-example -----
# ---- the reason for this is that
# ----- 1) the performance tests were only thoroughly tested on Ubuntu, not windows-
# (g2log windows/linux, but Google's glog only on linux)
#
# 2) The unit test were tested windows/linux,. but must be unzipped
# before it can be "cmake'd" and compiled --- leaving it as OFF for now
# ============================================================================
# 1. a simple test example 'g2log-FATAL-example'
option (USE_SIMPLE_EXAMPLE
"Create simple binaries that runs a few LOG calls" ON)
# 2. performance test (average + worst case) for KjellKod's g2log
option (USE_G2LOG_PERFORMANCE
"Create performance tests for g2log" OFF)
# 3. performance test for Google's glog
option (USE_GOOGLE_GLOG_PERFORMANCE
"Create performance tests for Google's glog (remember to install glog, snapshot available at g2log/3rdParty/glog)" OFF)
# 4. unit test for g2log
option (USE_G2LOG_UNIT_TEST
"Create unit test for g2log (remember to unzip Google's gtest framework, available at g2log/3rdParty/gtest)" ON)
# ===============================================================================================
#
# BELOW : Creating executables depending on OPTIONS above
#
# ==============================================================================================
# 1. create the the example EXECUTABLE - hook in the test_example's CMakeLists.txt file
if (USE_SIMPLE_EXAMPLE)
MESSAGE(" g2log-FATAL-example option ON")
include_directories (${DIR_EXAMPLE})
add_executable(g2log-FATAL-example ${DIR_EXAMPLE}/main.cpp)
target_link_libraries(g2log-FATAL-example lib_activeobject lib_g2logger ${PLATFORM_LINK_LIBRIES})
endif (USE_SIMPLE_EXAMPLE)
# =========================
# 2. create the g2log's performance tests
if (USE_G2LOG_PERFORMANCE)
MESSAGE(" g2log performance tests option ON")
include_directories (${DIR_PERFORMANCE})
# MEAN PERFORMANCE TEST
add_executable(g2log-performance-threaded_mean
${DIR_PERFORMANCE}/main_threaded_mean.cpp ${DIR_PERFORMANCE}/performance.h)
# Turn on G2LOG performance flag
set_target_properties(g2log-performance-threaded_mean PROPERTIES COMPILE_DEFINITIONS "G2LOG_PERFORMANCE=1")
target_link_libraries(g2log-performance-threaded_mean lib_activeobject lib_g2logger ${PLATFORM_LINK_LIBRIES})
# WORST CASE PERFORMANCE TEST
add_executable(g2log-performance-threaded_worst ${DIR_PERFORMANCE}//main_threaded_worst.cpp ${DIR_PERFORMANCE}/performance.h)
# Turn on G2LOG performance flag
set_target_properties(g2log-performance-threaded_worst PROPERTIES COMPILE_DEFINITIONS "G2LOG_PERFORMANCE=1")
target_link_libraries(g2log-performance-threaded_worst lib_activeobject lib_g2logger ${PLATFORM_LINK_LIBRIES})
endif (USE_G2LOG_PERFORMANCE)
# =========================
# 3. create the Google glog's performance test
if (USE_GOOGLE_GLOG_PERFORMANCE)
MESSAGE(" Google's glog performance tests option ON")
include_directories (${DIR_PERFORMANCE})
#Linux is easy!
if(UNIX)
set(GLOG_LIB glog)
# create the the GOOGLE MEAN_PERFORMANCE executable
add_executable(google_glog-performance-threaded_mean ${DIR_PERFORMANCE}/main_threaded_mean.cpp ${DIR_PERFORMANCE}/performance.h)
set_target_properties(google_glog-performance-threaded_mean PROPERTIES COMPILE_DEFINITIONS "GOOGLE_GLOG_PERFORMANCE=1")
target_link_libraries(google_glog-performance-threaded_mean lib_activeobject ${GLOG_LIB} ${PLATFORM_LINK_LIBRIES})
# create the the GOOGLE MEAN_PERFORMANCE executable
add_executable(google_glog-performance-threaded_worst ${DIR_PERFORMANCE}/main_threaded_worst.cpp ${DIR_PERFORMANCE}/performance.h)
set_target_properties(google_glog-performance-threaded_worst PROPERTIES COMPILE_DEFINITIONS "GOOGLE_GLOG_PERFORMANCE=1")
target_link_libraries(google_glog-performance-threaded_worst lib_activeobject ${GLOG_LIB} ${PLATFORM_LINK_LIBRIES})
endif(UNIX)
# GLOG on Linux is easy - but for Windows trickier,. and it doesn't work (as of yet)
if(WIN32)
MESSAGE("******************************************************")
MESSAGE("*** SORRY- Google glog on windows is not preconfigured")
MESSAGE("*** You have to do this yourself: ref CMakeLists.txt")
MESSAGE("******************************************************")
MESSAGE("")
#set(GLOG_DIR ../3rdParty/glog/glog-0.3.1)
#include_directories(${GLOG_DIR}/src/windows)
endif(WIN32)
endif (USE_GOOGLE_GLOG_PERFORMANCE)
# ===============================================================================================
# 4. create the unit tests for g2log --- ONLY TESTED THE UNIT TEST ON LINUX
if (USE_G2LOG_UNIT_TEST)
MESSAGE(" g2log unit testing option ON")
# SETUP for GTEST
set(GTEST_DIR ../3rdParty/gtest/gtest-1.6.0__stripped)
set(GTEST_INCLUDE_DIRECTORIES ${GTEST_DIR}/include ${GTEST_DIR} ${GTEST_DIR}/src)
include_directories(${GTEST_INCLUDE_DIRECTORIES})
add_library(gtest_160_lib ${GTEST_DIR}/src/gtest-all.cc ${GTEST_DIR}/src/gtest_main.cc)
enable_testing(true)
add_executable(g2log-unit_test ../test_main/test_main.cpp ${DIR_UNIT_TEST}/test_io.cpp ${DIR_UNIT_TEST}/test_configuration.cpp)
# obs see this: http://stackoverflow.com/questions/9589192/how-do-i-change-the-number-of-template-arguments-supported-by-msvcs-stdtupl
set_target_properties(g2log-unit_test PROPERTIES COMPILE_DEFINITIONS "_VARIADIC_MAX=10")
# and this: http://stackoverflow.com/questions/2257464/google-test-and-visual-studio-2010-rc
set_target_properties(g2log-unit_test PROPERTIES COMPILE_DEFINITIONS "GTEST_USE_OWN_TR1_TUPLE=0")
target_link_libraries(g2log-unit_test lib_activeobject lib_g2logger gtest_160_lib ${PLATFORM_LINK_LIBRIES})
add_executable(g2log-unit_test_filechange ${DIR_UNIT_TEST}/test_filechange.cpp)
set_target_properties(g2log-unit_test_filechange PROPERTIES COMPILE_DEFINITIONS "_VARIADIC_MAX=10")
set_target_properties(g2log-unit_test_filechange PROPERTIES COMPILE_DEFINITIONS "GTEST_USE_OWN_TR1_TUPLE=0")
target_link_libraries(g2log-unit_test_filechange lib_activeobject lib_g2logger gtest_160_lib ${PLATFORM_LINK_LIBRIES})
endif (USE_G2LOG_UNIT_TEST)

View File

@ -1,59 +0,0 @@
/** ==========================================================================
* 2010 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================
*
* Example of a Active Object, using C++11 std::thread mechanisms to make it
* safe for thread communication.
*
* This was originally published at http://sites.google.com/site/kjellhedstrom2/active-object-with-cpp0x
* and inspired from Herb Sutter's C++11 Active Object
* http://herbsutter.com/2010/07/12/effective-concurrency-prefer-using-active-objects-instead-of-naked-threads
*
* The code below uses JustSoftware Solutions Inc std::thread implementation
* http://www.justsoftwaresolutions.co.uk
*
* Last update 2012-10-10, by Kjell Hedstrom,
* e-mail: hedstrom at kjellkod dot cc
* linkedin: http://linkedin.com/se/kjellkod */
#include "active.h"
#include <cassert>
using namespace kjellkod;
Active::Active(): done_(false){}
Active::~Active() {
Callback quit_token = std::bind(&Active::doDone, this);
send(quit_token); // tell thread to exit
thd_.join();
}
// Add asynchronously a work-message to queue
void Active::send(Callback msg_){
mq_.push(msg_);
}
// Will wait for msgs if queue is empty
// A great explanation of how this is done (using Qt's library):
// http://doc.qt.nokia.com/stable/qwaitcondition.html
void Active::run() {
while (!done_) {
// wait till job is available, then retrieve it and
// executes the retrieved job in this thread (background)
Callback func;
mq_.wait_and_pop(func);
func();
}
}
// Factory: safe construction of object before thread start
std::unique_ptr<Active> Active::createActive(){
std::unique_ptr<Active> aPtr(new Active());
aPtr->thd_ = std::thread(&Active::run, aPtr.get());
return aPtr;
}

View File

@ -1,57 +0,0 @@
/** ==========================================================================
* 2010 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================
*
* Example of a Active Object, using C++11 std::thread mechanisms to make it
* safe for thread communication.
*
* This was originally published at http://sites.google.com/site/kjellhedstrom2/active-object-with-cpp0x
* and inspired from Herb Sutter's C++11 Active Object
* http://herbsutter.com/2010/07/12/effective-concurrency-prefer-using-active-objects-instead-of-naked-threads
*
* The code below uses JustSoftware Solutions Inc std::thread implementation
* http://www.justsoftwaresolutions.co.uk
*
* Last update 2012-10-10, by Kjell Hedstrom,
* e-mail: hedstrom at kjellkod dot cc
* linkedin: http://linkedin.com/se/kjellkod */
#ifndef ACTIVE_H_
#define ACTIVE_H_
#include <thread>
#include <functional>
#include <condition_variable>
#include <mutex>
#include <memory>
#include "shared_queue.h"
namespace kjellkod {
typedef std::function<void()> Callback;
class Active {
private:
Active(const Active&); // c++11 feature not yet in vs2010 = delete;
Active& operator=(const Active&); // c++11 feature not yet in vs2010 = delete;
Active(); // Construction ONLY through factory createActive();
void doDone(){done_ = true;}
void run();
shared_queue<Callback> mq_;
std::thread thd_;
bool done_; // finished flag to be set through msg queue by ~Active
public:
virtual ~Active();
void send(Callback msg_);
static std::unique_ptr<Active> createActive(); // Factory: safe construction & thread start
};
} // end namespace kjellkod
#endif

View File

@ -1,37 +0,0 @@
#ifndef CRASH_HANDLER_H_
#define CRASH_HANDLER_H_
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
#include <string>
#include <csignal>
namespace g2
{
// PRIVATE-INTERNAL API
namespace internal
{
/** \return signal_name. Ref: signum.h and \ref installSignalHandler */
std::string signalName(int signal_number);
/** Re-"throw" a fatal signal, previously caught. This will exit the application
* This is an internal only function. Do not use it elsewhere. It is triggered
* from g2log, g2LogWorker after flushing messages to file */
void exitWithDefaultSignalHandler(int signal_number);
} // end g2::interal
// PUBLIC API:
/** Install signal handler that catches FATAL C-runtime or OS signals
SIGABRT ABORT (ANSI), abnormal termination
SIGFPE Floating point exception (ANSI): http://en.wikipedia.org/wiki/SIGFPE
SIGILL ILlegal instruction (ANSI)
SIGSEGV Segmentation violation i.e. illegal memory reference
SIGTERM TERMINATION (ANSI) */
void installSignalHandler();
}
#endif // CRASH_HANDLER_H_

View File

@ -1,188 +0,0 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
#include "crashhandler.h"
#include "g2log.h"
#include <csignal>
#include <cstring>
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
// or? gcc on windows I guess,.
#error "crashhandler_unix.cpp used but it's a windows system"
#endif
#include <unistd.h> // getpid,
#include <execinfo.h>
#include <ucontext.h>
#include <cxxabi.h>
#include <cstdlib>
namespace
{
// Dump of stack,. then exit through g2log background worker
// ALL thanks to this thread at StackOverflow. Pretty much borrowed from:
// Ref: http://stackoverflow.com/questions/77005/how-to-generate-a-stacktrace-when-my-gcc-c-app-crashes
void crashHandler(int signal_number, siginfo_t *info, void *unused_context)
{
const size_t max_dump_size = 50;
void* dump[max_dump_size];
size_t size = backtrace(dump, max_dump_size);
char** messages = backtrace_symbols(dump, size); // overwrite sigaction with caller's address
std::ostringstream oss;
oss << "Received fatal signal: " << g2::internal::signalName(signal_number);
oss << "(" << signal_number << ")" << std::endl;
oss << "\tPID: " << getpid() << std::endl;
// dump stack: skip first frame, since that is here
for(size_t idx = 1; idx < size && messages != nullptr; ++idx)
{
char *mangled_name = 0, *offset_begin = 0, *offset_end = 0;
// find parantheses and +address offset surrounding mangled name
for (char *p = messages[idx]; *p; ++p)
{
if (*p == '(')
{
mangled_name = p;
}
else if (*p == '+')
{
offset_begin = p;
}
else if (*p == ')')
{
offset_end = p;
break;
}
}
// if the line could be processed, attempt to demangle the symbol
if (mangled_name && offset_begin && offset_end &&
mangled_name < offset_begin)
{
*mangled_name++ = '\0';
*offset_begin++ = '\0';
*offset_end++ = '\0';
int status;
char * real_name = abi::__cxa_demangle(mangled_name, 0, 0, &status);
// if demangling is successful, output the demangled function name
if (status == 0)
{
oss << "\tstack dump [" << idx << "] " << messages[idx] << " : " << real_name << "+";
oss << offset_begin << offset_end << std::endl;
}
// otherwise, output the mangled function name
else
{
oss << "\tstack dump [" << idx << "] " << messages[idx] << mangled_name << "+";
oss << offset_begin << offset_end << std::endl;
}
free(real_name); // mallocated by abi::__cxa_demangle(...)
}
else
{
// no demangling done -- just dump the whole line
oss << "\tstack dump [" << idx << "] " << messages[idx] << std::endl;
}
} // END: for(size_t idx = 1; idx < size && messages != nullptr; ++idx)
free(messages);
{ // Local scope, trigger send
using namespace g2::internal;
std::ostringstream fatal_stream;
fatal_stream << "\n\n***** FATAL TRIGGER RECEIVED ******* " << std::endl;
fatal_stream << oss.str() << std::endl;
fatal_stream << "\n***** RETHROWING SIGNAL " << signalName(signal_number) << "(" << signal_number << ")" << std::endl;
FatalMessage fatal_message(fatal_stream.str(),FatalMessage::kReasonOS_FATAL_SIGNAL, signal_number);
FatalTrigger trigger(fatal_message); std::ostringstream oss;
std::cerr << fatal_message.message_ << std::endl << std::flush;
} // message sent to g2LogWorker
// wait to die -- will be inside the FatalTrigger
}
} // end anonymous namespace
// Redirecting and using signals. In case of fatal signals g2log should log the fatal signal
// and flush the log queue and then "rethrow" the signal to exit
namespace g2
{
// References:
// sigaction : change the default action if a specific signal is received
// http://linux.die.net/man/2/sigaction
// http://publib.boulder.ibm.com/infocenter/aix/v6r1/index.jsp?topic=%2Fcom.ibm.aix.basetechref%2Fdoc%2Fbasetrf2%2Fsigaction.html
//
// signal: http://linux.die.net/man/7/signal and
// http://msdn.microsoft.com/en-us/library/xdkz3x12%28vs.71%29.asp
//
// memset + sigemptyset: Maybe unnecessary to do both but there seems to be some confusion here
// ,plenty of examples when both or either are used
// http://stackoverflow.com/questions/6878546/why-doesnt-parent-process-return-to-the-exact-location-after-handling-signal_number
namespace internal
{
std::string signalName(int signal_number)
{
switch(signal_number)
{
case SIGABRT: return "SIGABRT";break;
case SIGFPE: return "SIGFPE"; break;
case SIGSEGV: return "SIGSEGV"; break;
case SIGILL: return "SIGILL"; break;
case SIGTERM: return "SIGTERM"; break;
default:
std::ostringstream oss;
oss << "UNKNOWN SIGNAL(" << signal_number << ")";
return oss.str();
}
}
// Triggered by g2log->g2LogWorker after receiving a FATAL trigger
// which is LOG(FATAL), CHECK(false) or a fatal signal our signalhandler caught.
// --- If LOG(FATAL) or CHECK(false) the signal_number will be SIGABRT
void exitWithDefaultSignalHandler(int signal_number)
{
std::cerr << "Exiting - FATAL SIGNAL: " << signal_number << " " << std::flush;
struct sigaction action;
memset(&action, 0, sizeof(action)); //
sigemptyset(&action.sa_mask);
action.sa_handler = SIG_DFL; // take default action for the signal
sigaction(signal_number, &action, NULL);
kill(getpid(), signal_number);
abort(); // should never reach this
}
} // end g2::internal
void installSignalHandler()
{
struct sigaction action;
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_sigaction = &crashHandler; // callback to crashHandler for fatal signals
// sigaction to use sa_sigaction file. ref: http://www.linuxprogrammingblog.com/code-examples/sigaction
action.sa_flags = SA_SIGINFO;
// do it verbose style - install all signal actions
if(sigaction(SIGABRT, &action, NULL) < 0)
perror("sigaction - SIGABRT");
if(sigaction(SIGFPE, &action, NULL) < 0)
perror("sigaction - SIGFPE");
if(sigaction(SIGILL, &action, NULL) < 0)
perror("sigaction - SIGILL");
if(sigaction(SIGSEGV, &action, NULL) < 0)
perror("sigaction - SIGSEGV");
if(sigaction(SIGTERM, &action, NULL) < 0)
perror("sigaction - SIGTERM");
}
} // end namespace g2

View File

@ -1,92 +0,0 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
#include "crashhandler.h"
#include "g2log.h"
#include <csignal>
#include <cstring>
#include <cstdlib>
#if !(defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
#error "crashhandler_win.cpp used but not on a windows system"
#endif
#include <process.h> // getpid
#define getpid _getpid
namespace
{
void crashHandler(int signal_number)
{
using namespace g2::internal;
std::ostringstream fatal_stream;
fatal_stream << "\n\n***** FATAL TRIGGER RECEIVED ******* " << std::endl;
fatal_stream << "\n***** RETHROWING SIGNAL " << signalName(signal_number) << "(" << signal_number << ")" << std::endl;
FatalMessage fatal_message(fatal_stream.str(),FatalMessage::kReasonOS_FATAL_SIGNAL, signal_number);
FatalTrigger trigger(fatal_message); std::ostringstream oss;
std::cerr << fatal_message.message_ << std::endl << std::flush;
} // scope exit - message sent to LogWorker, wait to die...
} // end anonymous namespace
namespace g2
{
namespace internal
{
std::string signalName(int signal_number)
{
switch(signal_number)
{
case SIGABRT: return "SIGABRT";break;
case SIGFPE: return "SIGFPE"; break;
case SIGSEGV: return "SIGSEGV"; break;
case SIGILL: return "SIGILL"; break;
case SIGTERM: return "SIGTERM"; break;
default:
std::ostringstream oss;
oss << "UNKNOWN SIGNAL(" << signal_number << ")";
return oss.str();
}
}
// Triggered by g2log::LogWorker after receiving a FATAL trigger
// which is LOG(FATAL), CHECK(false) or a fatal signal our signalhandler caught.
// --- If LOG(FATAL) or CHECK(false) the signal_number will be SIGABRT
void exitWithDefaultSignalHandler(int signal_number)
{
// Restore our signalhandling to default
if(SIG_ERR == signal (SIGABRT, SIG_DFL))
perror("signal - SIGABRT");
if(SIG_ERR == signal (SIGFPE, SIG_DFL))
perror("signal - SIGABRT");
if(SIG_ERR == signal (SIGSEGV, SIG_DFL))
perror("signal - SIGABRT");
if(SIG_ERR == signal (SIGILL, SIG_DFL))
perror("signal - SIGABRT");
if(SIG_ERR == signal (SIGTERM, SIG_DFL))
perror("signal - SIGABRT");
raise(signal_number);
}
} // end g2::internal
void installSignalHandler()
{
if(SIG_ERR == signal (SIGABRT, crashHandler))
perror("signal - SIGABRT");
if(SIG_ERR == signal (SIGFPE, crashHandler))
perror("signal - SIGFPE");
if(SIG_ERR == signal (SIGSEGV, crashHandler))
perror("signal - SIGSEGV");
if(SIG_ERR == signal (SIGILL, crashHandler))
perror("signal - SIGILL");
if(SIG_ERR == signal (SIGTERM, crashHandler))
perror("signal - SIGTERM");
}
} // end namespace g2

View File

@ -1,70 +0,0 @@
#ifndef G2FUTURE_H
#define G2FUTURE_H
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================
* Filename:g2future.h
* Helper functionality to put packaged_tasks in standard container. This
* is especially helpful for background thread processing a la async but through
* an actor pattern (active object), thread pool or similar.
* Created: 2012 by Kjell Hedström
*
* COMMUNITY THANKS:
* The code below is in large thanks to exemplifying code snippets from StackOverflow
* question/answer: http://stackoverflow.com/questions/6230893/developing-c-concurrency-library-with-futures-or-similar-paradigm
* and a discussion between Lars Gullik Bjønnes and Jonathan Wakely's at: http://gcc.gnu.org/ml/gcc-help/2011-11/msg00052.html
*
* Both are highly recommended reads if you are interested in c++ concurrency library
* - Kjell, 2012
*
* PUBLIC DOMAIN and NOT under copywrite protection.
* ********************************************* */
#include <future>
#include "active.h"
namespace g2 {
// A straightforward technique to move around packaged_tasks.
// Instances of std::packaged_task are MoveConstructible and MoveAssignable, but
// not CopyConstructible or CopyAssignable. To put them in a std container they need
// to be wrapped and their internals "moved" when tried to be copied.
template<typename Moveable>
struct PretendToBeCopyable
{
explicit PretendToBeCopyable(Moveable&& m) : move_only_(std::move(m)) {}
PretendToBeCopyable(PretendToBeCopyable& p) : move_only_(std::move(p.move_only_)){}
PretendToBeCopyable(PretendToBeCopyable&& p) : move_only_(std::move(p.move_only_)){} // = default; // so far only on gcc
void operator()() { move_only_(); } // execute
private:
Moveable move_only_;
};
// Generic helper function to avoid repeating the steps for managing
// asynchronous task job (by active object) that returns a future results
// could of course be made even more generic if done more in the way of
// std::async, ref: http://en.cppreference.com/w/cpp/thread/async
//
// Example usage:
// std::unique_ptr<Active> bgWorker{Active::createActive()};
// ...
// auto msg_call=[=](){return ("Hello from the Background");};
// auto future_msg = g2::spawn_task(msg_lambda, bgWorker.get());
template <typename Func>
std::future<typename std::result_of<Func()>::type> spawn_task(Func func, kjellkod::Active* worker)
{
typedef typename std::result_of<Func()>::type result_type;
typedef std::packaged_task<result_type()> task_type;
task_type task(std::move(func));
std::future<result_type> result = task.get_future();
worker->send(PretendToBeCopyable<task_type>(std::move(task)));
return std::move(result);
}
} // end namespace g2
#endif // G2FUTURE_H

View File

@ -1,232 +0,0 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================
*
* Filename:g2log.cpp Framework for Logging and Design By Contract
* Created: 2011 by Kjell Hedström
*
* PUBLIC DOMAIN and Not copywrited since it was built on public-domain software and at least in "spirit" influenced
* from the following sources
* 1. kjellkod.cc ;)
* 2. Dr.Dobbs, Petru Marginean: http://drdobbs.com/article/printableArticle.jhtml?articleId=201804215&dept_url=/cpp/
* 3. Dr.Dobbs, Michael Schulze: http://drdobbs.com/article/printableArticle.jhtml?articleId=225700666&dept_url=/cpp/
* 4. Google 'glog': http://google-glog.googlecode.com/svn/trunk/doc/glog.html
* 5. Various Q&A at StackOverflow
* ********************************************* */
#include "g2log.h"
#include <iostream>
#include <sstream>
#include <string>
#include <stdexcept> // exceptions
#include <cstdio> // vsnprintf
#include <cassert>
#include <mutex>
#include "g2logworker.h"
#include "crashhandler.h"
#include <signal.h>
#include <thread>
namespace g2
{
namespace constants
{
const int kMaxMessageSize = 2048;
const std::string kTruncatedWarningText = "[...truncated...]";
}
namespace internal
{
static g2LogWorker* g_logger_instance = nullptr; // instantiated and OWNED somewhere else (main)
static std::mutex g_logging_init_mutex;
bool isLoggingInitialized(){return g_logger_instance != nullptr; }
/** thanks to: http://www.cplusplus.com/reference/string/string/find_last_of/
* Splits string at the last '/' or '\\' separator
* example: "/mnt/something/else.cpp" --> "else.cpp"
* "c:\\windows\\hello.h" --> hello.h
* "this.is.not-a-path.h" -->"this.is.not-a-path.h" */
std::string splitFileName(const std::string& str)
{
size_t found;
found = str.find_last_of("(/\\");
return str.substr(found+1);
}
} // end namespace g2::internal
void initializeLogging(g2LogWorker *bgworker)
{
static bool once_only_signalhandler = false;
std::lock_guard<std::mutex> lock(internal::g_logging_init_mutex);
CHECK(!internal::isLoggingInitialized());
CHECK(bgworker != nullptr);
internal::g_logger_instance = bgworker;
if(false == once_only_signalhandler)
{
installSignalHandler();
once_only_signalhandler = true;
}
}
g2LogWorker* shutDownLogging()
{
std::lock_guard<std::mutex> lock(internal::g_logging_init_mutex);
CHECK(internal::isLoggingInitialized());
g2LogWorker *backup = internal::g_logger_instance;
internal::g_logger_instance = nullptr;
return backup;
}
namespace internal
{
// The default, initial, handling to send a 'fatal' event to g2logworker
// the caller will stay here, eternally, until the software is aborted
void callFatalInitial(FatalMessage message)
{
internal::g_logger_instance->fatal(message);
}
// By default this function pointer goes to \ref callFatalInitial;
void (*g_fatal_to_g2logworker_function_ptr)(FatalMessage) = callFatalInitial;
// Replaces the g2log.cpp/g_fatal_to_g2logworker_function_ptr through
// g2log::changeFatalInitHandler
void unitTestFatalInitHandler(g2::internal::FatalMessage fatal_message)
{
assert(internal::g_logger_instance != nullptr);
internal::g_logger_instance->save(fatal_message.message_); // calling 'save' instead of 'fatal'
throw std::runtime_error(fatal_message.message_);
}
// In case of unit-testing - a replacement 'fatal function' can be called
void changeFatalInitHandlerForUnitTesting()
{
g_fatal_to_g2logworker_function_ptr = unitTestFatalInitHandler;
}
LogContractMessage::LogContractMessage(const std::string &file, const int line,
const std::string& function, const std::string &boolean_expression)
: LogMessage(file, line, function, "FATAL")
, expression_(boolean_expression)
{}
LogContractMessage::~LogContractMessage()
{
std::ostringstream oss;
if(0 == expression_.compare(k_fatal_log_expression))
{
oss << "\n[ *******\tEXIT trigger caused by LOG(FATAL): \n\t";
}
else
{
oss << "\n[ *******\tEXIT trigger caused by broken Contract: CHECK(" << expression_ << ")\n\t";
}
log_entry_ = oss.str();
}
LogMessage::LogMessage(const std::string &file, const int line, const std::string& function, const std::string &level)
: file_(file)
, line_(line)
, function_(function)
, level_(level)
{}
LogMessage::~LogMessage()
{
using namespace internal;
std::ostringstream oss;
const bool fatal = (0 == level_.compare("FATAL"));
oss << level_ << " [" << splitFileName(file_);
if(fatal)
oss << " at: " << function_ ;
oss << " L: " << line_ << "]\t";
const std::string str(stream_.str());
if(!str.empty())
{
oss << '"' << str << '"';
}
log_entry_ += oss.str();
if(!isLoggingInitialized() )
{
std::cerr << "Did you forget to call g2::InitializeLogging(g2LogWorker*) in your main.cpp?" << std::endl;
std::cerr << log_entry_ << std::endl << std::flush;
throw std::runtime_error("Logger not initialized with g2::InitializeLogging(g2LogWorker*) for msg:\n" + log_entry_);
}
if(fatal) // os_fatal is handled by crashhandlers
{
{ // local scope - to trigger FatalMessage sending
FatalMessage::FatalType fatal_type(FatalMessage::kReasonFatal);
FatalMessage fatal_message(log_entry_, fatal_type, SIGABRT);
FatalTrigger trigger(fatal_message);
std::cerr << log_entry_ << "\t******* ]" << std::endl << std::flush;
} // will send to worker
}
internal::g_logger_instance->save(log_entry_); // message saved
}
// represents the actual fatal message
FatalMessage::FatalMessage(std::string message, FatalType type, int signal_id)
: message_(message)
, type_(type)
, signal_id_(signal_id){}
// used to RAII trigger fatal message sending to g2LogWorker
FatalTrigger::FatalTrigger(const FatalMessage &message)
: message_(message){}
// at destruction, flushes fatal message to g2LogWorker
FatalTrigger::~FatalTrigger()
{
// either we will stay here eternally, or it's in unit-test mode
// then we throw a std::runtime_error (and never hit sleep)
g_fatal_to_g2logworker_function_ptr(message_);
while(true){std::this_thread::sleep_for(std::chrono::seconds(1));}
}
void LogMessage::messageSave(const char *printf_like_message, ...)
{
char finished_message[constants::kMaxMessageSize];
va_list arglist;
va_start(arglist, printf_like_message);
const int nbrcharacters = vsnprintf(finished_message, sizeof(finished_message), printf_like_message, arglist);
va_end(arglist);
if (nbrcharacters <= 0)
{
stream_ << "\n\tERROR LOG MSG NOTIFICATION: Failure to parse successfully the message";
stream_ << '"' << printf_like_message << '"' << std::endl;
}
else if (nbrcharacters > constants::kMaxMessageSize)
{
stream_ << finished_message << constants::kTruncatedWarningText;
}
else
{
stream_ << finished_message;
}
}
} // end of namespace g2::internal
} // end of namespace g2

View File

@ -1,242 +0,0 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================
*
* Filename:g2log.h Framework for Logging and Design By Contract
* Created: 2011 by Kjell Hedström
*
* PUBLIC DOMAIN and Not copywrited since it was built on public-domain software and influenced
* at least in "spirit" from the following sources
* 1. kjellkod.cc ;)
* 2. Dr.Dobbs, Petru Marginean: http://drdobbs.com/article/printableArticle.jhtml?articleId=201804215&dept_url=/cpp/
* 3. Dr.Dobbs, Michael Schulze: http://drdobbs.com/article/printableArticle.jhtml?articleId=225700666&dept_url=/cpp/
* 4. Google 'glog': http://google-glog.googlecode.com/svn/trunk/doc/glog.html
* 5. Various Q&A at StackOverflow
* ********************************************* */
#ifndef G2LOG_H
#define G2LOG_H
#include <string>
#include <sstream>
#include <iostream>
#include <cstdarg>
#include <chrono>
class g2LogWorker;
#if !(defined(__PRETTY_FUNCTION__))
#define __PRETTY_FUNCTION__ __FUNCTION__
#endif
// Levels for logging, made so that it would be easy to change, remove, add levels -- KjellKod
const int DEBUG = 0, INFO = 1, WARNING = 2, FATAL = 3;
static const std::string k_fatal_log_expression = ""; // using LogContractMessage but no boolean expression
// GCC Predefined macros: http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
// and http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html
//
// The ## macro is helpful as it gives compile time error in case there's a typo
// Example: MYLEVEL doesn't exist so LOG(MYLEVEL) << "bla bla bla"; would
// generate a compile error when it is rolled out by the
// macro as G2_LOG_MYLEVEL, since "#define G2_LOG_MYLEVEL" doesn't exist
// BELOW -- LOG stream syntax
#define G2_LOG_DEBUG g2::internal::LogMessage(__FILE__,__LINE__,__PRETTY_FUNCTION__,"DEBUG")
#define G2_LOG_INFO g2::internal::LogMessage(__FILE__,__LINE__,__PRETTY_FUNCTION__,"INFO")
#define G2_LOG_WARNING g2::internal::LogMessage(__FILE__,__LINE__,__PRETTY_FUNCTION__,"WARNING")
#define G2_LOG_FATAL g2::internal::LogContractMessage(__FILE__,__LINE__,__PRETTY_FUNCTION__,k_fatal_log_expression)
// LOG(level) is the API for the stream log
#define LOG(level) G2_LOG_##level.messageStream()
// conditional stream log
#define LOG_IF(level, boolean_expression) \
if(true == boolean_expression) \
G2_LOG_##level.messageStream()
// Design By Contract, stream API. Throws std::runtime_eror if contract breaks
#define CHECK(boolean_expression) \
if (false == (boolean_expression)) \
g2::internal::LogContractMessage(__FILE__, __LINE__, __PRETTY_FUNCTION__, #boolean_expression).messageStream()
// BELOW -- LOG "printf" syntax
/**
* For details please see this
* REFERENCE: http://www.cppreference.com/wiki/io/c/printf_format
* \verbatim
*
There are different %-codes for different variable types, as well as options to
limit the length of the variables and whatnot.
Code Format
%[flags][width][.precision][length]specifier
SPECIFIERS
----------
%c character
%d signed integers
%i signed integers
%e scientific notation, with a lowercase e
%E scientific notation, with a uppercase E
%f floating point
%g use %e or %f, whichever is shorter
%G use %E or %f, whichever is shorter
%o octal
%s a string of characters
%u unsigned integer
%x unsigned hexadecimal, with lowercase letters
%X unsigned hexadecimal, with uppercase letters
%p a pointer
%n the argument shall be a pointer to an integer into which is placed the number of characters written so far
For flags, width, precision etc please see the above references.
EXAMPLES:
{
LOGF(INFO, "Characters: %c %c \n", 'a', 65);
LOGF(INFO, "Decimals: %d %ld\n", 1977, 650000L); // printing long
LOGF(INFO, "Preceding with blanks: %10d \n", 1977);
LOGF(INFO, "Preceding with zeros: %010d \n", 1977);
LOGF(INFO, "Some different radixes: %d %x %o %#x %#o \n", 100, 100, 100, 100, 100);
LOGF(INFO, "floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416);
LOGF(INFO, "Width trick: %*d \n", 5, 10);
LOGF(INFO, "%s \n", "A string");
return 0;
}
And here is possible output
: Characters: a A
: Decimals: 1977 650000
: Preceding with blanks: 1977
: Preceding with zeros: 0000001977
: Some different radixes: 100 64 144 0x64 0144
: floats: 3.14 +3e+000 3.141600E+000
: Width trick: 10
: A string \endverbatim */
#define G2_LOGF_INFO g2::internal::LogMessage(__FILE__, __LINE__, __PRETTY_FUNCTION__,"INFO")
#define G2_LOGF_DEBUG g2::internal::LogMessage(__FILE__, __LINE__, __PRETTY_FUNCTION__,"DEBUG")
#define G2_LOGF_WARNING g2::internal::LogMessage(__FILE__, __LINE__, __PRETTY_FUNCTION__,"WARNING")
#define G2_LOGF_FATAL g2::internal::LogContractMessage(__FILE__, __LINE__, __PRETTY_FUNCTION__,k_fatal_log_expression)
// LOGF(level,msg,...) is the API for the "printf" like log
#define LOGF(level, printf_like_message, ...) \
G2_LOGF_##level.messageSave(printf_like_message, __VA_ARGS__);
// conditional log printf syntax
#define LOGF_IF(level,boolean_expression, printf_like_message, ...) \
if(true == boolean_expression) \
G2_LOG_##level.messageSave(printf_like_message, __VA_ARGS__);
// Design By Contract, printf-like API syntax with variadic input parameters. Throws std::runtime_eror if contract breaks */
#define CHECK_F(boolean_expression, printf_like_message, ...) \
if (false == (boolean_expression)) \
g2::internal::LogContractMessage(__FILE__, __LINE__, __PRETTY_FUNCTION__,#boolean_expression).messageSave(printf_like_message, __VA_ARGS__);
/** namespace for LOG() and CHECK() frameworks
* Histroy lesson:
* Why the names 'g2' and 'g2log'?:
* --> The framework was made in my own free time as PUBLIC DOMAIN but the first commercial project to use it
* used 'g2' as an internal denominator for the current project. g2 as in 'generation 2'. I decided to keep the g2 and g2log names to
* give credit to the people in that project (you know who you are :) and I guess also for 'sentimental' reasons.
* That a big influence was google's glog is just a happy concidence or subconscious choice. Either way g2log became the name for this logger.
* --- Thanks for a great 2011 and good luck with 'g2' --- KjellKod */
namespace g2
{
/** Should be called at very first startup of the software with \ref g2LogWorker pointer. Ownership of the \ref g2LogWorker is
* the responsibilkity of the caller */
void initializeLogging(g2LogWorker *logger);
/** Shutdown the logging by making the pointer to the background logger to nullptr
* The \ref pointer to the g2LogWorker is owned by the instantniater \ref initializeLogging
* and is not deleted. By restoring the ptr to nullptr we can re-initialize it later again. This is
* kept for test reasons and should normally not be used */
g2LogWorker* shutDownLogging();
// defined here but should't not have to be used outside the g2log
namespace internal
{
typedef const std::string& LogEntry;
/** By default the g2log will call g2LogWorker::fatal(...) which will abort() the system after flushing
* the logs to file. This makes unit test of FATAL level cumbersome. A work around is to change the 'fatal call'
* which can be done here */
void changeFatalInitHandlerForUnitTesting();
// TODO: LogEntry och FatalMessage borde kunna slås ihop till samma!
/** Trigger for flushing the message queue and exiting the application
A thread that causes a FatalMessage will sleep forever until the
application has exited (after message flush) */
struct FatalMessage
{
enum FatalType {kReasonFatal, kReasonOS_FATAL_SIGNAL};
FatalMessage(std::string message, FatalType type, int signal_id);
std::string message_;
FatalType type_;
int signal_id_;
};
// Will trigger a FatalMessage sending
struct FatalTrigger
{
FatalTrigger(const FatalMessage& message);
~FatalTrigger();
FatalMessage message_;
};
// Log message for 'printf-like' or stream logging, it's a temporary message constructions
class LogMessage
{
public:
LogMessage(const std::string &file, const int line, const std::string& function, const std::string &level);
virtual ~LogMessage(); // at destruction will flush the message
std::ostringstream& messageStream(){return stream_;}
// The __attribute__ generates compiler warnings if illegal "printf" format
// IMPORTANT: You muse enable the compiler flag '-Wall' for this to work!
// ref: http://www.unixwiz.net/techtips/gnu-c-attributes.html
//
//If the compiler does not support attributes, disable them
#ifndef __GNUC__
#define __attribute__(x)
#endif
// Coder note: Since it's C++ and not C EVERY CLASS FUNCTION always get a first
// compiler given argument 'this' this must be supplied as well, hence '2,3'
// ref: http://www.codemaestro.com/reviews/18 -- ref KjellKod
void messageSave(const char *printf_like_message, ...)
__attribute__((format(printf,2,3) ));
protected:
const std::string file_;
const int line_;
const std::string function_;
const std::string level_;
std::ostringstream stream_;
std::string log_entry_;
};
// 'Design-by-Contract' temporary messsage construction
class LogContractMessage : public LogMessage
{
public:
LogContractMessage(const std::string &file, const int line,
const std::string &function, const std::string &boolean_expression);
virtual ~LogContractMessage(); // at destruction will flush the message
protected:
const std::string expression_;
};
} // end namespace internal
} // end namespace g2
#endif // G2LOG_H

View File

@ -1,287 +0,0 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================
* Filename:g2LogWorker.cpp Framework for Logging and Design By Contract
* Created: 2011 by Kjell Hedström
*
* PUBLIC DOMAIN and Not under copywrite protection. First published at KjellKod.cc
* ********************************************* */
#include "g2logworker.h"
#include <fstream>
#include <sstream>
#include <cassert>
#include <algorithm>
#include <string>
#include <chrono>
#include <future>
#include <functional>
#include "active.h"
#include "g2log.h"
#include "crashhandler.h"
#include "g2time.h"
#include "g2future.h"
using namespace g2;
using namespace g2::internal;
namespace
{
static const std::string date_formatted = "%Y/%m/%d";
static const std::string time_formatted = "%H:%M:%S";
static const std::string file_name_time_formatted = "%Y%m%d-%H%M%S";
// check for filename validity - filename should not be part of PATH
bool isValidFilename(const std::string prefix_filename)
{
std::string illegal_characters("/,|<>:#$%{}()[]\'\"^!?+* ");
size_t pos = prefix_filename.find_first_of(illegal_characters,0);
if(pos != std::string::npos)
{
std::cerr << "Illegal character [" << prefix_filename.at(pos) << "] in logname prefix: " << "[" << prefix_filename << "]" << std::endl;
return false;
}
else if (prefix_filename.empty())
{
std::cerr << "Empty filename prefix is not allowed" << std::endl;
return false;
}
return true;
}
// Clean up the path if put in by mistake in the prefix
std::string prefixSanityFix(const std::string& prefix)
{
std::string real_prefix = prefix;
std::remove( real_prefix.begin(), real_prefix.end(), '/');
std::remove( real_prefix.begin(), real_prefix.end(), '\\');
std::remove( real_prefix.begin(), real_prefix.end(), '.');
if(!isValidFilename(real_prefix))
{
return "";
}
return real_prefix;
}
std::string createLogFileName(const std::string& verified_prefix)
{
std::stringstream oss_name;
oss_name.fill('0');
oss_name << verified_prefix << ".g2log.";
oss_name << g2::localtime_formatted(g2::systemtime_now(), file_name_time_formatted);
oss_name << ".log";
return oss_name.str();
}
bool openLogFile(const std::string& complete_file_with_path, std::ofstream& outstream)
{
std::ios_base::openmode mode = std::ios_base::out; // for clarity: it's really overkill since it's an ofstream
mode |= std::ios_base::trunc;
outstream.open(complete_file_with_path, mode);
if(!outstream.is_open())
{
std::ostringstream ss_error;
ss_error << "FILE ERROR: could not open log file:[" << complete_file_with_path << "]";
ss_error << "\n\t\t std::ios_base state = " << outstream.rdstate();
std::cerr << ss_error.str().c_str() << std::endl << std::flush;
outstream.close();
return false;
}
std::ostringstream ss_entry;
// Day Month Date Time Year: is written as "%a %b %d %H:%M:%S %Y" and formatted output as : Wed Sep 19 08:28:16 2012
ss_entry << "\t\tg2log created log file at: "<< g2::localtime_formatted(g2::systemtime_now(), "%a %b %d %H:%M:%S %Y") << "\n";
ss_entry << "\t\tLOG format: [YYYY/MM/DD hh:mm:ss.uuu* LEVEL FILE:LINE] message\n\n"; // TODO: if(header)
outstream << ss_entry.str() << std::flush;
outstream.fill('0');
return true;
}
std::unique_ptr<std::ofstream> createLogFile(const std::string& file_with_full_path)
{
std::unique_ptr<std::ofstream> out(new std::ofstream);
std::ofstream& stream(*(out.get()));
bool success_with_open_file = openLogFile(file_with_full_path, stream);
if(false == success_with_open_file)
{
out.release(); // nullptr contained ptr<file> signals error in creating the log file
}
return out;
}
} // end anonymous namespace
/** The Real McCoy Background worker, while g2LogWorker gives the
* asynchronous API to put job in the background the g2LogWorkerImpl
* does the actual background thread work */
struct g2LogWorkerImpl
{
g2LogWorkerImpl(const std::string& log_prefix, const std::string& log_directory);
~g2LogWorkerImpl();
void backgroundFileWrite(g2::internal::LogEntry message);
void backgroundExitFatal(g2::internal::FatalMessage fatal_message);
std::string backgroundChangeLogFile(const std::string& directory);
std::string backgroundFileName();
std::string log_file_with_path_;
std::string log_prefix_backup_; // needed in case of future log file changes of directory
std::unique_ptr<kjellkod::Active> bg_;
std::unique_ptr<std::ofstream> outptr_;
steady_time_point steady_start_time_;
private:
g2LogWorkerImpl& operator=(const g2LogWorkerImpl&); // c++11 feature not yet in vs2010 = delete;
g2LogWorkerImpl(const g2LogWorkerImpl& other); // c++11 feature not yet in vs2010 = delete;
std::ofstream& filestream(){return *(outptr_.get());}
};
//
// Private API implementation : g2LogWorkerImpl
g2LogWorkerImpl::g2LogWorkerImpl(const std::string& log_prefix, const std::string& log_directory)
: log_file_with_path_(log_directory)
, log_prefix_backup_(log_prefix)
, bg_(kjellkod::Active::createActive())
, outptr_(new std::ofstream)
, steady_start_time_(std::chrono::steady_clock::now()) // TODO: ha en timer function steadyTimer som har koll på start
{
log_prefix_backup_ = prefixSanityFix(log_prefix);
if(!isValidFilename(log_prefix_backup_))
{
// illegal prefix, refuse to start
std::cerr << "g2log: forced abort due to illegal log prefix [" << log_prefix <<"]" << std::endl << std::flush;
abort();
}
std::string file_name = createLogFileName(log_prefix_backup_);
log_file_with_path_ = log_directory + file_name;
outptr_ = createLogFile(log_file_with_path_);
assert((nullptr != outptr_) && "cannot open log file at startup");
}
g2LogWorkerImpl::~g2LogWorkerImpl()
{
std::ostringstream ss_exit;
bg_.reset(); // flush the log queue
ss_exit << "\n\t\tg2log file shutdown at: " << g2::localtime_formatted(g2::systemtime_now(), time_formatted);
filestream() << ss_exit.str() << std::flush;
}
void g2LogWorkerImpl::backgroundFileWrite(LogEntry message)
{
using namespace std;
std::ofstream& out(filestream());
auto system_time = g2::systemtime_now();
auto steady_time = std::chrono::steady_clock::now();
out << "\n" << g2::localtime_formatted(system_time, date_formatted);
out << " " << g2::localtime_formatted(system_time, time_formatted); // TODO: time kommer från LogEntry
out << "." << chrono::duration_cast<std::chrono::microseconds>(steady_time - steady_start_time_).count(); //microseconds TODO: ta in min g2clocka här StopWatch
out << "\t" << message << std::flush;
}
void g2LogWorkerImpl::backgroundExitFatal(FatalMessage fatal_message)
{
backgroundFileWrite(fatal_message.message_);
backgroundFileWrite("Log flushed successfully to disk \nExiting");
std::cerr << "g2log exiting after receiving fatal event" << std::endl;
std::cerr << "Log file at: [" << log_file_with_path_ << "]\n" << std::endl << std::flush;
filestream().close();
exitWithDefaultSignalHandler(fatal_message.signal_id_);
perror("g2log exited after receiving FATAL trigger. Flush message status: "); // should never reach this point
}
std::string g2LogWorkerImpl::backgroundChangeLogFile(const std::string& directory)
{
std::string file_name = createLogFileName(log_prefix_backup_);
std::string prospect_log = directory + file_name;
std::unique_ptr<std::ofstream> log_stream = createLogFile(prospect_log);
if(nullptr == log_stream)
{
backgroundFileWrite("Unable to change log file. Illegal filename or busy? Unsuccessful log name was:" + prospect_log);
return ""; // no success
}
std::ostringstream ss_change;
ss_change << "\n\tChanging log file from : " << log_file_with_path_;
ss_change << "\n\tto new location: " << prospect_log << "\n";
backgroundFileWrite(ss_change.str().c_str());
ss_change.str("");
// setting the new log as active
std::string old_log = log_file_with_path_;
log_file_with_path_ = prospect_log;
outptr_ = std::move(log_stream);
ss_change << "\n\tNew log file. The previous log file was at: ";
ss_change << old_log;
backgroundFileWrite(ss_change.str());
return log_file_with_path_;
}
std::string g2LogWorkerImpl::backgroundFileName()
{
return log_file_with_path_;
}
//
// ***** BELOW g2LogWorker *****
// Public API implementation
//
g2LogWorker::g2LogWorker(const std::string& log_prefix, const std::string& log_directory)
: pimpl_(new g2LogWorkerImpl(log_prefix, log_directory))
, log_file_with_path_(pimpl_->log_file_with_path_)
{
assert((pimpl_ != nullptr) && "shouild never happen");
}
g2LogWorker::~g2LogWorker()
{
pimpl_.reset();
std::cerr << "\nExiting, log location: " << log_file_with_path_ << std::endl << std::flush;
}
void g2LogWorker::save(g2::internal::LogEntry msg)
{
pimpl_->bg_->send(std::bind(&g2LogWorkerImpl::backgroundFileWrite, pimpl_.get(), msg));
}
void g2LogWorker::fatal(g2::internal::FatalMessage fatal_message)
{
pimpl_->bg_->send(std::bind(&g2LogWorkerImpl::backgroundExitFatal, pimpl_.get(), fatal_message));
}
std::future<std::string> g2LogWorker::changeLogFile(const std::string& log_directory)
{
kjellkod::Active* bgWorker = pimpl_->bg_.get();
//auto future_result = g2::spawn_task(std::bind(&g2LogWorkerImpl::backgroundChangeLogFile, pimpl_.get(), log_directory), bgWorker);
auto bg_call = [this, log_directory]() {return pimpl_->backgroundChangeLogFile(log_directory);};
auto future_result = g2::spawn_task(bg_call, bgWorker);
return std::move(future_result);
}
std::future<std::string> g2LogWorker::logFileName()
{
kjellkod::Active* bgWorker = pimpl_->bg_.get();
auto bg_call=[&](){return pimpl_->backgroundFileName();};
auto future_result = g2::spawn_task(bg_call ,bgWorker);
return std::move(future_result);
}

View File

@ -1,57 +0,0 @@
#ifndef G2_LOG_WORKER_H_
#define G2_LOG_WORKER_H_
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================
* Filename:g2logworker.h Framework for Logging and Design By Contract
* Created: 2011 by Kjell Hedström
*
* PUBLIC DOMAIN and Not copywrited. First published at KjellKod.cc
* ********************************************* */
#include <memory>
#include <future>
#include <string>
#include "g2log.h"
struct g2LogWorkerImpl;
/**
* \param log_prefix is the 'name' of the binary, this give the log name 'LOG-'name'-...
* \param log_directory gives the directory to put the log files */
class g2LogWorker
{
public:
g2LogWorker(const std::string& log_prefix, const std::string& log_directory);
virtual ~g2LogWorker();
/// pushes in background thread (asynchronously) input messages to log file
void save(g2::internal::LogEntry entry);
/// Will push a fatal message on the queue, this is the last message to be processed
/// this way it's ensured that all existing entries were flushed before 'fatal'
/// Will abort the application!
void fatal(g2::internal::FatalMessage fatal_message);
/// Attempt to change the current log file to another name/location.
/// returns filename with full path if successful, else empty string
std::future<std::string> changeLogFile(const std::string& log_directory);
/// Probably only needed for unit-testing or specific log management post logging
/// request to get log name is processed in FIFO order just like any other background job.
std::future<std::string> logFileName();
private:
std::unique_ptr<g2LogWorkerImpl> pimpl_;
const std::string log_file_with_path_;
g2LogWorker(const g2LogWorker&); // c++11 feature not yet in vs2010 = delete;
g2LogWorker& operator=(const g2LogWorker&); // c++11 feature not yet in vs2010 = delete;
};
#endif // LOG_WORKER_H_

View File

@ -1,78 +0,0 @@
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================
* Filename:g2time.cpp cross-platform, thread-safe replacement for C++11 non-thread-safe
* localtime (and similar)
* Created: 2012 by Kjell Hedström
*
* PUBLIC DOMAIN and Not under copywrite protection. First published for g2log at KjellKod.cc
* ********************************************* */
#include "g2time.h"
#include <sstream>
#include <string>
#include <chrono>
#include <thread>
#include <ctime>
#include <iomanip>
namespace g2 { namespace internal {
// This mimics the original "std::put_time(const std::tm* tmb, const charT* fmt)"
// This is needed since latest version (at time of writing) of gcc4.7 does not implement this library function yet.
// return value is SIMPLIFIED to only return a std::string
std::string put_time(const struct tm* tmb, const char* c_time_format)
{
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
std::ostringstream oss;
oss.fill('0');
oss << std::put_time(const_cast<struct tm*>(tmb), c_time_format); // BOGUS hack done for VS2012: C++11 non-conformant since it SHOULD take a "const struct tm* "
return oss.str();
#else // LINUX
const size_t size = 1024;
char buffer[size]; // OBS: kolla om inte std::put_time finns. This is way more buffer space then we need
auto success = std::strftime(buffer, size, c_time_format, tmb); // Ta över denna funktion till BitBucket/code/g2log sen då denna är utvecklingsbranchen
if (0 == success)
return c_time_format; // error return result indeterminate due to buffer overflow - should throw instead?
return buffer; // implicit conversion to std::string
#endif
}
} // internal
} // g2
namespace g2
{
std::time_t systemtime_now()
{
system_time_point system_now = std::chrono::system_clock::now();
return std::chrono::system_clock::to_time_t(system_now);
}
tm localtime(const std::time_t& time)
{
struct tm tm_snapshot;
#if !(defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
localtime_r(&time, &tm_snapshot); // POSIX
#else
localtime_s(&tm_snapshot, &time); // windsows
#endif
return tm_snapshot;
}
/// returns a std::string with content of time_t as localtime formatted by input format string
/// * format string must conform to std::put_time
/// This is similar to std::put_time(std::localtime(std::time_t*), time_format.c_str());
std::string localtime_formatted(const std::time_t& time_snapshot, const std::string& time_format)
{
std::tm t = localtime(time_snapshot); // could be const, but cannot due to VS2012 is non conformant for C++11's std::put_time (see above)
std::stringstream buffer;
buffer << g2::internal::put_time(&t, time_format.c_str()); // format example: //"%Y/%m/%d %H:%M:%S");
return buffer.str();
}
} // g2

View File

@ -1,45 +0,0 @@
#ifndef G2_TIME_H_
#define G2_TIME_H_
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================
* Filename:g2time.h cross-platform, thread-safe replacement for C++11 non-thread-safe
* localtime (and similar)
* Created: 2012 by Kjell Hedström
*
* PUBLIC DOMAIN and Not under copywrite protection. First published for g2log at KjellKod.cc
* ********************************************* */
#include <ctime>
#include <string>
#include <chrono>
// FYI:
// namespace g2::internal ONLY in g2time.cpp
// std::string put_time(const struct tm* tmb, const char* c_time_format)
namespace g2
{
typedef std::chrono::steady_clock::time_point steady_time_point;
typedef std::chrono::time_point<std::chrono::system_clock> system_time_point;
typedef std::chrono::milliseconds milliseconds;
typedef std::chrono::microseconds microseconds;
// wrap for std::chrono::system_clock::now()
std::time_t systemtime_now();
/** return time representing POD struct (ref ctime + wchar) that is normally
* retrieved with std::localtime. g2::localtime is threadsafe which std::localtime is not.
* g2::localtime is probably used together with @ref g2::systemtime_now */
tm localtime(const std::time_t& time);
/** format string must conform to std::put_time's demands.
* WARNING: At time of writing there is only so-so compiler support for
* std::put_time. A possible fix if your c++11 library is not updated is to
* modify this to use std::strftime instead */
std::string localtime_formatted(const std::time_t& time_snapshot, const std::string& time_format) ;
}
#endif

View File

@ -1,77 +0,0 @@
/** ==========================================================================
* 2010 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================
*
* Example of a normal std::queue protected by a mutex for operations,
* making it safe for thread communication, using std::mutex from C++0x with
* the help from the std::thread library from JustSoftwareSolutions
* ref: http://www.stdthread.co.uk/doc/headers/mutex.html
*
* This exampel was totally inspired by Anthony Williams lock-based data structures in
* Ref: "C++ Concurrency In Action" http://www.manning.com/williams */
#ifndef SHARED_QUEUE
#define SHARED_QUEUE
#include <queue>
#include <mutex>
#include <exception>
#include <condition_variable>
/** Multiple producer, multiple consumer thread safe queue
* Since 'return by reference' is used this queue won't throw */
template<typename T>
class shared_queue
{
std::queue<T> queue_;
mutable std::mutex m_;
std::condition_variable data_cond_;
shared_queue& operator=(const shared_queue&); // c++11 feature not yet in vs2010 = delete;
shared_queue(const shared_queue& other); // c++11 feature not yet in vs2010 = delete;
public:
shared_queue(){}
void push(T item){
std::lock_guard<std::mutex> lock(m_);
queue_.push(item);
data_cond_.notify_one();
}
/// \return immediately, with true if successful retrieval
bool try_and_pop(T& popped_item){
std::lock_guard<std::mutex> lock(m_);
if(queue_.empty()){
return false;
}
popped_item=std::move(queue_.front());
queue_.pop();
return true;
}
/// Try to retrieve, if no items, wait till an item is available and try again
void wait_and_pop(T& popped_item){
std::unique_lock<std::mutex> lock(m_); // note: unique_lock is needed for std::condition_variable::wait
while(queue_.empty())
{ // The 'while' loop below is equal to
data_cond_.wait(lock); //data_cond_.wait(lock, [](bool result){return !queue_.empty();});
}
popped_item=std::move(queue_.front());
queue_.pop();
}
bool empty() const{
std::lock_guard<std::mutex> lock(m_);
return queue_.empty();
}
unsigned size() const{
std::lock_guard<std::mutex> lock(m_);
return queue_.size();
}
};
#endif

View File

@ -1,97 +0,0 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
#include "g2logworker.h"
#include "g2log.h"
#include <iomanip>
#include <thread>
namespace
{
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
const std::string path_to_log_file = "./";
#else
const std::string path_to_log_file = "/tmp/";
#endif
}
namespace example_fatal
{
void killWithContractFailureIfNonEqual(int first, int second)
{
CHECK(first == second) << "Test to see if contract works: onetwothree: " << 123 << ". This should be at the end of the log, and will exit this example";
}
// on Ubunti this caused get a compiler warning with gcc4.6
// from gcc 4.7.2 (at least) it causes a crash (as expected)
// On windows it'll probably crash too.
void tryToKillWithIllegalPrintout()
{
std::cout << "\n\n***** Be ready this last example may 'abort' if on Windows/Linux_gcc4.7 " << std::endl << std::flush;
std::cout << "************************************************************\n\n" << std::endl << std::flush;
std::this_thread::sleep_for(std::chrono::seconds(1));
const std::string logging = "logging";
LOGF(DEBUG, "ILLEGAL PRINTF_SYNTAX EXAMPLE. WILL GENERATE compiler warning.\n\nbadly formatted message:[Printf-type %s is the number 1 for many %s]", logging.c_str());
}
} // example fatal
int main(int argc, char** argv)
{
double pi_d = 3.1415926535897932384626433832795;
float pi_f = 3.1415926535897932384626433832795f;
g2LogWorker logger(argv[0], path_to_log_file);
g2::initializeLogging(&logger);
std::future<std::string> log_file_name = logger.logFileName();
std::cout << "*** This is an example of g2log " << std::endl;
std::cout << "*** It WILL exit by a FATAL trigger in the end" << std::endl;
std::cout << "*** Please see the generated log and compare to " << std::endl;
std::cout << "*** the code at g2log/test_example/main.cpp" << std::endl;
std::cout << "\n*** Log file: [" << log_file_name.get() << "]\n\n" << std::endl;
LOGF(INFO, "Hi log %d", 123);
LOG(INFO) << "Test SLOG INFO";
LOG(DEBUG) << "Test SLOG DEBUG";
LOG(INFO) << "one: " << 1;
LOG(INFO) << "two: " << 2;
LOG(INFO) << "one and two: " << 1 << " and " << 2;
LOG(DEBUG) << "float 2.14: " << 1000/2.14f;
LOG(DEBUG) << "pi double: " << pi_d;
LOG(DEBUG) << "pi float: " << pi_f;
LOG(DEBUG) << "pi float (width 10): " << std::setprecision(10) << pi_f;
LOGF(INFO, "pi float printf:%f", pi_f);
//
// START: LOG Entris that were in the article
//
//LOG(UNKNOWN_LEVEL) << "This log attempt will cause a compiler error";
LOG(INFO) << "Simple to use with streaming syntax, easy as abc or " << 123;
LOGF(WARNING, "Printf-style syntax is also %s", "available");
LOG_IF(INFO, (1 < 2)) << "If true this text will be logged";
LOGF_IF(INFO, (1<2), "if %d<%d : then this text will be logged", 1,2);
LOG_IF(FATAL, (2>3)) << "This message should NOT throw";
LOGF(DEBUG, "This API is popular with some %s", "programmers");
LOGF_IF(DEBUG, (1<2), "If true, then this %s will be logged", "message");
// OK --- on Ubunti this caused get a compiler warning with gcc4.6
// from gcc 4.7.2 (at least) it causes a crash (as expected)
// On windows itll probably crash
// ---- IF you want to try 'FATAL' contract failure please comment away
// ----- the 'illegalPrinout' call below
example_fatal::tryToKillWithIllegalPrintout();
CHECK(1<2) << "SHOULD NOT SEE THIS MESSAGE"; // non-failure contract
std::cout << "\n\n***** Be ready this last example WILL trigger 'abort' (if not done earlier)" << std::endl;
// exit by contract failure. See the dumped log, the function
// that caused the fatal exit should be shown in the stackdump
int smaller = 1;
int larger = 2;
example_fatal::killWithContractFailureIfNonEqual(smaller, larger);
}

View File

@ -1,98 +0,0 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
// through CMakeLists.txt #define of GOOGLE_GLOG_PERFORMANCE and G2LOG_PERFORMANCE
#include "performance.h"
#include <thread>
#if defined(G2LOG_PERFORMANCE)
const std::string title = "G2LOG";
#elif defined(GOOGLE_GLOG_PERFORMANCE)
const std::string title = "GOOGLE__GLOG";
#else
#error G2LOG_PERFORMANCE or GOOGLE_GLOG_PERFORMANCE was not defined
#endif
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
const std::string g_path = "./";
#else
const std::string g_path = "/tmp/";
#endif
using namespace g2_test;
int main(int argc, char** argv)
{
size_t number_of_threads =0;
if(argc == 2)
{
number_of_threads = atoi(argv[1]);
}
if(argc != 2 || number_of_threads == 0)
{
std::cerr << "USAGE is: " << argv[0] << " number_threads" << std::endl;
return 1;
}
std::ostringstream thread_count_oss;
thread_count_oss << number_of_threads;
const std::string g_prefix_log_name = title + "-performance-" + thread_count_oss.str() + "threads-MEAN_LOG";
const std::string g_measurement_dump= g_path + g_prefix_log_name + "_RESULT.txt";
std::ostringstream oss;
oss << "\n\n" << title << " performance " << number_of_threads << " threads MEAN times\n";
oss << "Each thread running #: " << g_loop << " * " << g_iterations << " iterations of log entries" << std::endl; // worst mean case is about 10us per log entry
const size_t xtra_margin = 2;
oss << "*** It can take som time. Please wait: Approximate wait time on MY PC was: " <<number_of_threads* (long long) (g_iterations * 10 * xtra_margin / 1000000 ) << " seconds" << std::endl;
writeTextToFile(g_measurement_dump, oss.str(), kAppend);
oss.str(""); // clear the stream
#if defined(G2LOG_PERFORMANCE)
g2LogWorker* logger = new g2LogWorker(g_prefix_log_name, g_path);
g2::initializeLogging(logger);
#elif defined(GOOGLE_GLOG_PERFORMANCE)
google::InitGoogleLogging(argv[0]);
#endif
auto start_time = std::chrono::steady_clock::now();
std::thread* threads = new std::thread[number_of_threads];
// kiss: just loop, create threads, store them then join
// could probably do this more elegant with lambdas
for(size_t idx = 0; idx < number_of_threads; ++idx)
{
std::ostringstream count;
count << idx+1;
std::string thread_name = title + "_T" + count.str();
std::cout << "Creating thread: " << thread_name << std::endl;
threads[idx] = std::thread(doLogWrites,thread_name);
}
for(size_t idx = 0; idx < number_of_threads; ++idx)
{
threads[idx].join();
}
auto application_end_time = std::chrono::steady_clock::now();
delete [] threads;
#if defined(G2LOG_PERFORMANCE)
delete logger; // will flush anything in the queue to file
#elif defined(GOOGLE_GLOG_PERFORMANCE)
google::ShutdownGoogleLogging();
#endif
auto worker_end_time = std::chrono::steady_clock::now();
auto application_time_us = std::chrono::duration_cast<microsecond>(application_end_time - start_time).count();
auto total_time_us = std::chrono::duration_cast<microsecond>(worker_end_time - start_time).count();
oss << "\n" << g_iterations << " log entries took: [" << total_time_us / 1000000 << " s] to write to disk"<< std::endl;
oss << "[Application(" << number_of_threads << "):\t\t:" << application_time_us/1000 << " ms]" << std::endl;
oss << "[Background thread to finish\t:" << total_time_us/1000 << " ms]" << std::endl;
oss << "\nAverage time per log entry:" << std::endl;
oss << "[Application: " << application_time_us/(number_of_threads*g_iterations) << " us]" << std::endl;
oss << "[Background+Application: " << total_time_us/(number_of_threads*g_iterations) << " us]" << std::endl;
writeTextToFile(g_measurement_dump,oss.str(), kAppend);
std::cout << "Result can be found at:" << g_measurement_dump << std::endl;
return 0;
}

View File

@ -1,162 +0,0 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
// through CMakeLists.txt #define of GOOGLE_GLOG_PERFORMANCE and G2LOG_PERFORMANCE
#include "performance.h"
#include <thread>
#include <vector>
#include <map>
#include <algorithm>
#include <cmath>
#if defined(G2LOG_PERFORMANCE)
const std::string title = "G2LOG";
#elif defined(GOOGLE_GLOG_PERFORMANCE)
const std::string title = "GOOGLE__GLOG";
#else
#error G2LOG_PERFORMANCE or GOOGLE_GLOG_PERFORMANCE was not defined
#endif
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
const std::string g_path = "./";
#else
const std::string g_path = "/tmp/";
#endif
using namespace g2_test;
//
// OK: The code below isn't pretty but it works. Lots and lots of log entries
// to keep track of!
//
int main(int argc, char** argv)
{
size_t number_of_threads =0;
if(argc == 2)
{
number_of_threads = atoi(argv[1]);
}
if(argc != 2 || number_of_threads == 0)
{
std::cerr << "USAGE is: " << argv[0] << " number_threads" << std::endl;
return 1;
}
std::ostringstream thread_count_oss;
thread_count_oss << number_of_threads;
const std::string g_prefix_log_name = title + "-performance-" + thread_count_oss.str() + "threads-WORST_LOG";
const std::string g_measurement_dump= g_path + g_prefix_log_name + "_RESULT.txt";
const std::string g_measurement_bucket_dump= g_path + g_prefix_log_name + "_RESULT_buckets.txt";
std::ostringstream oss;
oss << "\n\n" << title << " performance " << number_of_threads << " threads WORST (PEAK) times\n";
oss << "Each thread running #: " << g_loop << " * " << g_iterations << " iterations of log entries" << std::endl; // worst mean case is about 10us per log entry
const size_t xtra_margin = 2;
oss << "*** It can take som time. Please wait: Approximate wait time on MY PC was: " << number_of_threads * (long long) (g_iterations * 10 * xtra_margin / 1000000 ) << " seconds" << std::endl;
writeTextToFile(g_measurement_dump, oss.str(), kAppend);
oss.str(""); // clear the stream
#if defined(G2LOG_PERFORMANCE)
g2LogWorker* logger = new g2LogWorker(g_prefix_log_name, g_path);
g2::initializeLogging(logger);
#elif defined(GOOGLE_GLOG_PERFORMANCE)
google::InitGoogleLogging(argv[0]);
#endif
std::thread* threads = new std::thread[number_of_threads];
std::vector<long long>* threads_result = new std::vector<long long>[number_of_threads];
// kiss: just loop, create threads, store them then join
// could probably do this more elegant with lambdas
for(size_t idx = 0; idx < number_of_threads; ++idx)
{
threads_result[idx].reserve(g_iterations);
}
auto start_time = std::chrono::steady_clock::now();
for(size_t idx = 0; idx < number_of_threads; ++idx)
{
std::ostringstream count;
count << idx+1;
std::string thread_name = title + "_T" + count.str();
std::cout << "Creating thread: " << thread_name << std::endl;
threads[idx] = std::thread(measurePeakDuringLogWrites,thread_name, std::ref(threads_result[idx]));
}
// wait for thread finishing
for(size_t idx = 0; idx < number_of_threads; ++idx)
{
threads[idx].join();
}
auto application_end_time = std::chrono::steady_clock::now();
delete [] threads;
#if defined(G2LOG_PERFORMANCE)
delete logger; // will flush anything in the queue to file
#elif defined(GOOGLE_GLOG_PERFORMANCE)
google::ShutdownGoogleLogging();
#endif
auto worker_end_time = std::chrono::steady_clock::now();
auto application_time_us = std::chrono::duration_cast<microsecond>(application_end_time - start_time).count();
auto total_time_us = std::chrono::duration_cast<microsecond>(worker_end_time - start_time).count();
oss << "\n" << g_iterations << " log entries took: [" << total_time_us / 1000000 << " s] to write to disk"<< std::endl;
oss << "[Application(" << number_of_threads << "_threads+overhead time for measurement):\t" << application_time_us/1000 << " ms]" << std::endl;
oss << "[Background thread to finish:\t\t\t\t" << total_time_us/1000 << " ms]" << std::endl;
oss << "\nAverage time per log entry:" << std::endl;
oss << "[Application: " << application_time_us/(number_of_threads*g_iterations) << " us]" << std::endl;
for(size_t idx = 0; idx < number_of_threads; ++idx)
{
std::vector<long long>& t_result = threads_result[idx];
oss << "[Application t" << idx+1 << " worst took: " << (*std::max_element(t_result.begin(), t_result.end())) / 1000 << " ms]" << std::endl;
}
writeTextToFile(g_measurement_dump,oss.str(), kAppend);
std::cout << "Result can be found at:" << g_measurement_dump << std::endl;
// now split the result in buckets of 10ms each so that it's obvious how the peaks go
std::vector<long long> all_measurements;
all_measurements.reserve(g_iterations * number_of_threads);
for(size_t idx = 0; idx < number_of_threads; ++idx)
{
std::vector<long long>& t_result = threads_result[idx];
all_measurements.insert(all_measurements.end(), t_result.begin(), t_result.end());
}
delete [] threads_result; // finally get rid of them
std::sort (all_measurements.begin(), all_measurements.end());
std::map<long long, long long> value_amounts;
// for(long long& idx : all_measurements) --- didn't work?!
for(auto iter = all_measurements.begin(); iter != all_measurements.end(); ++iter)
{
auto value = (*iter)/1000; // convert to ms
//auto bucket=floor(value*10+0.5)/10;
++value_amounts[value]; // asuming size_t is default 0 when initialized
}
oss.str("");
oss << "Number of values rounted to milliseconds and put to [millisecond bucket] were dumped to file: " << g_measurement_bucket_dump << std::endl;
oss << "Format: bucket_of_ms, number_of_values_in_bucket\n\n" << std::endl;
std::cout << oss.str() << std::endl;
for(auto iter = value_amounts.begin(); iter != value_amounts.end(); ++iter)
{
oss << iter->first << "\t, " << iter->second << std::endl;
}
writeTextToFile(g_measurement_bucket_dump,oss.str(), kAppend, false);
return 0;
}

View File

@ -1,195 +0,0 @@
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
#include <gtest/gtest.h>
#include <chrono>
#include <thread>
#include <future>
#include <string>
#include <exception>
#include <functional>
#include <memory>
#include "g2time.h"
#include "g2future.h"
TEST(Configuration, LOG)
{ // ref: http://www.cplusplus.com/reference/clibrary/ctime/strftime/
// ref: http://en.cppreference.com/w/cpp/io/manip/put_time
// Day Month Date Time Year: is written as "%a %b %d %H:%M:%S %Y" and formatted output as : Wed Sep 19 08:28:16 2012
// --- WARNING: The try/catch setup does NOT work,. but for fun and for fake-clarity I leave it
// --- For formatting options to std::put_time that are NOT YET implemented on Windows fatal errors/assert will occurr
// --- the last example is such an example.
try
{
std::cout << g2::localtime_formatted(g2::systemtime_now(), "%a %b %d %H:%M:%S %Y") << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << g2::localtime_formatted(g2::systemtime_now(), "%%Y/%%m/%%d %%H:%%M:%%S = %Y/%m/%d %H:%M:%S") << std::endl;
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
std::cerr << "Formatting options skipped due to VS2012, C++11 non-conformance for" << std::endl;
std::cerr << " some formatting options. The skipped code was:\n\t\t %EX %Ec, \n(see http://en.cppreference.com/w/cpp/io/manip/put_time for details)" << std::endl;
#else
std::cout << "C++11 new formatting options:\n" << g2::localtime_formatted(g2::systemtime_now(), "%%EX: %EX\n%%z: %z\n%%Ec: %Ec") << std::endl;
#endif
}
// This does not work. Other kinds of fatal exits (on Windows) seems to be used instead of exceptions
// Maybe a signal handler catch would be better? --- TODO: Make it better, both failing and correct
catch(...)
{
ADD_FAILURE() << "On this platform the library does not support given (C++11?) specifiers";
return;
}
ASSERT_TRUE(true); // no exception. all good
}
std::future<std::string> sillyFutureReturn()
{
std::packaged_task<std::string()> task([](){return std::string("Hello Future");}); // wrap the function
std::future<std::string> result = task.get_future(); // get a future
std::thread(std::move(task)).detach(); // launch on a thread
std::cout << "Waiting...";
result.wait();
return result; // already wasted
}
TEST(Configuration, FutureSilly)
{
std::string hello = sillyFutureReturn().get();
ASSERT_STREQ(hello.c_str(), "Hello Future");
}
struct MsgType
{
std::string msg_;
MsgType(std::string m): msg_(m){};
std::string msg(){return msg_;}
};
TEST(TestOf_CopyableCall, Expecting_SmoothSailing)
{
using namespace kjellkod;
const std::string str("Hello from struct");
MsgType type(str);
std::unique_ptr<Active> bgWorker(Active::createActive());
std::future<std::string> fstring =
g2::spawn_task(std::bind(&MsgType::msg, type), bgWorker.get());
ASSERT_STREQ(str.c_str(), fstring.get().c_str());
}
TEST(TestOf_CopyableLambdaCall, Expecting_AllFine)
{
using namespace kjellkod;
std::unique_ptr<Active> bgWorker(Active::createActive());
// lambda task
const std::string str_standalone("Hello from standalone");
auto msg_lambda=[=](){return (str_standalone+str_standalone);};
std::string expected(str_standalone+str_standalone);
auto fstring_standalone = g2::spawn_task(msg_lambda, bgWorker.get());
ASSERT_STREQ(expected.c_str(), fstring_standalone.get().c_str());
}
template<typename F>
std::future<typename std::result_of<F()>::type> ObsoleteSpawnTask(F f)
{
typedef typename std::result_of<F()>::type result_type;
typedef std::packaged_task<result_type()> task_type;
task_type task(std::move(f));
std::future<result_type> result = task.get_future();
std::vector<std::function<void()>> vec;
vec.push_back(g2::PretendToBeCopyable<task_type>(std::move(task)));
std::thread(std::move(vec.back())).detach();
result.wait();
return std::move(result);
}
TEST(TestOf_ObsoleteSpawnTaskWithStringReturn, Expecting_FutureString)
{
std::string str("Hello");
std::string expected(str+str);
auto msg_lambda=[=](){return (str+str);};
auto future_string = ObsoleteSpawnTask(msg_lambda);
ASSERT_STREQ(expected.c_str(), future_string.get().c_str());
}
// gcc thread example below
// tests code below copied from mail-list conversion between
// Lars Gullik Bjønnes and Jonathan Wakely
// http://gcc.gnu.org/ml/gcc-help/2011-11/msg00052.html
// --------------------------------------------------------------
namespace WORKING
{
using namespace g2;
#include <gtest/gtest.h>
#include <iostream>
#include <future>
#include <thread>
#include <vector>
std::vector<std::function<void()>> vec;
template<typename F>
std::future<typename std::result_of<F()>::type> spawn_task(F f)
{
typedef typename std::result_of<F()>::type result_type;
typedef std::packaged_task<result_type()> task_type;
task_type task(std::move(f));
std::future<result_type> res = task.get_future();
vec.push_back(
PretendToBeCopyable<task_type>(
std::move(task)));
std::thread([]()
{
auto task = std::move(vec.back());
vec.pop_back();
task();
}
).detach();
return std::move(res);
}
double get_res()
{
return 42.2;
}
std::string msg2(){return "msg2";}
} // WORKING
TEST(Yalla, Testar)
{
using namespace WORKING;
auto f = spawn_task(get_res);
std::cout << "Res = " << f.get() << std::endl;
auto f2 = spawn_task(msg2);
std::cout << "Res2 = " << f2.get() << std::endl;
ASSERT_TRUE(true);
}

View File

@ -1,188 +0,0 @@
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
#include <gtest/gtest.h>
#include <memory>
#include <fstream>
#include <string>
#include <memory>
#include <future>
#include <queue>
#include <algorithm>
#include <mutex>
#include <thread>
#include "g2log.h"
#include "g2logworker.h"
namespace { // anonymous
const char* name_path_1 = "./some_fake_DirectoryOrName_1_";
const char* name_path_2 = "./some_fake_DirectoryOrName_3_";
g2LogWorker* g_logger_ptr = nullptr;
bool isTextAvailableInContent(const std::string &total_text,std::string msg_to_find)
{
std::string content(total_text);
size_t location = content.find(msg_to_find);
return (location != std::string::npos);
}
std::string readFileToText(std::string filename)
{
std::ifstream in;
in.open(filename.c_str(),std::ios_base::in);
if(!in.is_open())
{
return ""; // error just return empty string - test will 'fault'
}
std::ostringstream oss;
oss << in.rdbuf();
std::string content(oss.str());
return content;
}
bool removeFile(std::string path_to_file)
{
return (0 == std::remove(path_to_file.c_str()));
}
class LogFileCleaner // RAII cluttering files cleanup
{
private:
std::vector<std::string> logs_to_clean_;
std::mutex g_mutex;
public:
size_t size(){return logs_to_clean_.size();}
virtual ~LogFileCleaner() {
std::lock_guard<std::mutex> lock(g_mutex);
{
for (std::string p : logs_to_clean_)
{
if(false == removeFile(p))
{
ADD_FAILURE() << "UNABLE to remove: " << p.c_str() << std::endl;
}
}
logs_to_clean_.clear();
} // mutex
}
void addLogToClean(std::string path_to_log) {
std::lock_guard<std::mutex> lock(g_mutex);
{
if (std::find(logs_to_clean_.begin(), logs_to_clean_.end(), path_to_log.c_str()) == logs_to_clean_.end())
logs_to_clean_.push_back(path_to_log);
}
}
}; LogFileCleaner* g_cleaner_ptr = nullptr;
std::string changeDirectoryOrName(std::string new_file_to_create)
{
static std::mutex m;
static int count;
std::lock_guard<std::mutex> lock(m);
{
std::string add_count = std::to_string(++count) + "_";
auto new_log = g_logger_ptr->changeLogFile(new_file_to_create+add_count).get();
if(!new_log.empty()) g_cleaner_ptr->addLogToClean(new_log);
return new_log;
}
}
} // anonymous
// TODO: this must change. Initialization of this is done here! and not in a special test_main.cpp
// which MAY be OK ... however it is also very redundant with test_io
TEST(TestOf_GetFileName, Expecting_ValidLogFile)
{
LOG(INFO) << "test_filechange, Retrieving file name: ";
ASSERT_NE(g_logger_ptr, nullptr);
std::future<std::string> f_get_old_name = g_logger_ptr->logFileName();
ASSERT_TRUE(f_get_old_name.valid());
ASSERT_FALSE(f_get_old_name.get().empty());
}
TEST(TestOf_ChangingLogFile, Expecting_NewLogFileUsed)
{
auto old_log = g_logger_ptr->logFileName().get();
std::string name = changeDirectoryOrName(name_path_1);
auto new_log = g_logger_ptr->changeLogFile(name).get();
}
TEST(TestOf_ManyThreadsChangingLogFileName, Expecting_EqualNumberLogsCreated)
{
auto old_log = g_logger_ptr->logFileName().get();
if(!old_log.empty()) g_cleaner_ptr->addLogToClean(old_log);
LOG(INFO) << "SoManyThreadsAllDoingChangeFileName";
std::vector<std::thread> threads;
auto max = 2;
auto size = g_cleaner_ptr->size();
for(auto count = 0; count < max; ++count)
{
std::string drive = ((count % 2) == 0) ? "./_threadEven_" : "./_threaOdd_";
threads.push_back(std::thread(changeDirectoryOrName, drive));
}
for(auto& thread : threads)
thread.join();
// check that all logs were created
ASSERT_EQ(size+max, g_cleaner_ptr->size());
}
TEST(TestOf_IllegalLogFileName, Expecting_NoChangeToOriginalFileName)
{
std::string original = g_logger_ptr->logFileName().get();
std::cerr << "Below WILL print 'FiLE ERROR'. This is part of the testing and perfectly OK" << std::endl;
std::cerr << "****" << std::endl;
std::future<std::string> perhaps_a_name = g_logger_ptr->changeLogFile("XY:/"); // does not exist
ASSERT_TRUE(perhaps_a_name.get().empty());
std::cerr << "****" << std::endl;
std::string post_illegal = g_logger_ptr->logFileName().get();
ASSERT_STREQ(original.c_str(), post_illegal.c_str());
}
int main(int argc, char *argv[])
{
LogFileCleaner cleaner;
g_cleaner_ptr = &cleaner;
int return_value = 1;
std::string last_log_file;
{
g2LogWorker logger("ReplaceLogFile", name_path_2);
testing::InitGoogleTest(&argc, argv);
g_logger_ptr = &logger; // ugly but fine for this test
g2::initializeLogging(g_logger_ptr);
cleaner.addLogToClean(g_logger_ptr->logFileName().get());
return_value = RUN_ALL_TESTS();
last_log_file = g_logger_ptr->logFileName().get();
g2::shutDownLogging();
}
std::cout << "FINISHED WITH THE TESTING" << std::endl;
// cleaning up
cleaner.addLogToClean(last_log_file);
return return_value;
}

View File

@ -1,404 +0,0 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
#include <gtest/gtest.h>
#include "g2log.h"
#include "g2logworker.h"
#include <memory>
#include <string>
#include <fstream>
#include <cstdio>
namespace
{
const int k_wait_time = 5; // 5s wait between LOG/CHECK FATAL till we say it's too long time
const std::string log_directory = "./";
bool verifyContent(const std::string &total_text,std::string msg_to_find)
{
std::string content(total_text);
size_t location = content.find(msg_to_find);
return (location != std::string::npos);
}
std::string readFileToText(std::string filename)
{
std::ifstream in;
in.open(filename.c_str(),std::ios_base::in);
if(!in.is_open())
{
return ""; // error just return empty string - test will 'fault'
}
std::ostringstream oss;
oss << in.rdbuf();
std::string content(oss.str());
return content;
}
} // end anonymous namespace
// RAII temporarily replace of logger
// and restoration of original logger at scope end
struct RestoreLogger
{
RestoreLogger();
~RestoreLogger();
void reset();
std::unique_ptr<g2LogWorker> logger_;
std::string logFile(){return log_file_;}
private:
std::string log_file_;
};
RestoreLogger::RestoreLogger()
: logger_(new g2LogWorker("UNIT_TEST_LOGGER", log_directory))
{
g2::initializeLogging(logger_.get());
g2::internal::changeFatalInitHandlerForUnitTesting();
std::future<std::string> filename(logger_->logFileName());
EXPECT_TRUE(filename.valid());
log_file_ = filename.get();
}
RestoreLogger::~RestoreLogger()
{
reset();
g2::shutDownLogging();
EXPECT_EQ(0, remove(log_file_.c_str()));
}
void RestoreLogger::reset()
{
logger_.reset();
}
// LOG
TEST(LOGTest, LOG)
{
std::string file_content;
{
RestoreLogger logger;
LOG(INFO) << "test LOG(INFO)";
logger.reset(); // force flush of logger
file_content = readFileToText(logger.logFile());
SCOPED_TRACE("LOG_INFO"); // Scope exit be prepared for destructor failure
}
ASSERT_TRUE(verifyContent(file_content, "test LOG(INFO)"));
}
namespace {
const std::string t_info = "test INFO ";
const std::string t_info2 = "test INFO 123";
const std::string t_debug = "test DEBUG ";
const std::string t_debug2 = "test DEBUG 1.123456";
const std::string t_warning = "test WARNING ";
const std::string t_warning2 = "test WARNING yello";
}
// printf-type log
TEST(LogTest, LOG_F)
{
std::string file_content;
{
RestoreLogger logger;
std::cout << "logfilename: " << logger.logFile() << std::flush << std::endl;
LOGF(INFO, std::string(t_info + "%d").c_str(), 123);
LOGF(DEBUG, std::string(t_debug + "%f").c_str(), 1.123456);
LOGF(WARNING, std::string(t_warning + "%s").c_str(), "yello");
logger.reset(); // force flush of logger
file_content = readFileToText(logger.logFile());
SCOPED_TRACE("LOG_INFO"); // Scope exit be prepared for destructor failure
}
ASSERT_TRUE(verifyContent(file_content, t_info2));
ASSERT_TRUE(verifyContent(file_content, t_debug2));
ASSERT_TRUE(verifyContent(file_content, t_warning2));
}
// stream-type log
TEST(LogTest, LOG)
{
std::string file_content;
{
RestoreLogger logger;
LOG(INFO) << t_info << 123;
LOG(DEBUG) << t_debug << std::setprecision(7) << 1.123456f;
LOG(WARNING) << t_warning << "yello";
logger.reset(); // force flush of logger
file_content = readFileToText(logger.logFile());
SCOPED_TRACE("LOG_INFO"); // Scope exit be prepared for destructor failure
}
ASSERT_TRUE(verifyContent(file_content, t_info2));
ASSERT_TRUE(verifyContent(file_content, t_debug2));
ASSERT_TRUE(verifyContent(file_content, t_warning2));
}
TEST(LogTest, LOG_F_IF)
{
std::string file_content;
{
RestoreLogger logger;
LOGF_IF(INFO, (2 == 2), std::string(t_info + "%d").c_str(), 123);
LOGF_IF(DEBUG, (2 != 2), std::string(t_debug + "%f").c_str(), 1.123456);
logger.reset(); // force flush of logger
file_content = readFileToText(logger.logFile());
SCOPED_TRACE("LOG_IF"); // Scope exit be prepared for destructor failure
}
ASSERT_TRUE(verifyContent(file_content, t_info2));
ASSERT_FALSE(verifyContent(file_content, t_debug2));
}
TEST(LogTest, LOG_IF)
{
std::string file_content;
{
RestoreLogger logger;
LOG_IF(INFO, (2 == 2)) << t_info << 123;
LOG_IF(DEBUG, (2 != 2)) << t_debug << std::setprecision(7) << 1.123456f;
logger.reset(); // force flush of logger
file_content = readFileToText(logger.logFile());
SCOPED_TRACE("LOG_IF"); // Scope exit be prepared for destructor failure
}
ASSERT_TRUE(verifyContent(file_content, t_info2));
ASSERT_FALSE(verifyContent(file_content, t_debug2));
}
TEST(LogTest, LOGF__FATAL)
{
RestoreLogger logger;
try
{
LOGF(FATAL, "This message should throw %d",0);
}
catch (std::exception const &e)
{
logger.reset();
std::string file_content = readFileToText(logger.logFile());
std::cerr << file_content << std::endl << std::flush;
if(verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, "This message should throw"))
{
SUCCEED();
return;
}
else
{
ADD_FAILURE() << "Didn't throw exception as expected";
}
}
ADD_FAILURE() << "Didn't throw exception at ALL";
}
TEST(LogTest, LOG_FATAL)
{
RestoreLogger logger;
try
{
LOG(FATAL) << "This message should throw";
}
catch (std::exception const &e)
{
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if(verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, "This message should throw"))
{
SUCCEED();
return;
}
else
{
ADD_FAILURE() << "Didn't throw exception as expected";
}
}
ADD_FAILURE() << "Didn't throw exception at ALL";
}
TEST(LogTest, LOGF_IF__FATAL)
{
RestoreLogger logger;
try
{
LOGF_IF(FATAL, (2<3), "This message%sshould throw"," ");
}
catch (std::exception const &e)
{
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if(verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, "This message should throw"))
{
SUCCEED();
return;
}
else
{
ADD_FAILURE() << "Didn't throw exception as expected";
}
}
ADD_FAILURE() << "Didn't throw exception at ALL";
}
TEST(LogTest, LOG_IF__FATAL)
{
RestoreLogger logger;
try
{
LOG_IF(WARNING, (0 != t_info.compare(t_info))) << "This message should NOT be written";
LOG_IF(FATAL, (0 != t_info.compare(t_info2))) << "This message should throw";
}
catch (std::exception const &e)
{
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if(verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, "This message should throw") &&
(false == verifyContent(file_content, "This message should NOT be written")))
{
SUCCEED();
return;
}
else
{
ADD_FAILURE() << "Didn't throw exception as expected";
}
}
ADD_FAILURE() << "Didn't throw exception at ALL";
}
TEST(LogTest, LOG_IF__FATAL__NO_THROW)
{
RestoreLogger logger;
try
{
LOG_IF(FATAL, (2>3)) << "This message%sshould NOT throw";
}
catch (std::exception const &e)
{
std::cerr << e.what() << std::endl;
logger.reset();
ADD_FAILURE() << "Didn't throw exception as expected";
}
logger.reset();
SUCCEED();
}
// CHECK_F
TEST(CheckTest, CHECK_F__thisWILL_PrintErrorMsg)
{
RestoreLogger logger;
try
{
CHECK(1 == 2);
}
catch (std::exception const &e)
{
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if(verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL"))
{
SUCCEED();
return;
}
}
ADD_FAILURE() << "Didn't throw exception as expected";
}
TEST(CHECK_F_Test, CHECK_F__thisWILL_PrintErrorMsg)
{
RestoreLogger logger;
std::string msg = "This message is added to throw %s and %s";
std::string msg2 = "This message is added to throw message and log";
std::string arg1 = "message";
std::string arg2 = "log";
try
{
CHECK_F(1 >= 2, msg.c_str(), arg1.c_str(), arg2.c_str());
}
catch (std::exception const &e)
{
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if(verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, msg2))
{
SUCCEED();
return;
}
}
ADD_FAILURE() << "Didn't throw exception as expected";
}
TEST(CHECK_Test, CHECK__thisWILL_PrintErrorMsg)
{
RestoreLogger logger;
std::string msg = "This message is added to throw %s and %s";
std::string msg2 = "This message is added to throw message and log";
std::string arg1 = "message";
std::string arg2 = "log";
try
{
CHECK(1 >= 2) << msg2;
}
catch (std::exception const &e)
{
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if(verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, msg2))
{
SUCCEED();
return;
}
}
ADD_FAILURE() << "Didn't throw exception as expected";
}
TEST(CHECK, CHECK_ThatWontThrow)
{
RestoreLogger logger;
std::string msg = "This %s should never appear in the %s";
std::string msg2 = "This message should never appear in the log";
std::string arg1 = "message";
std::string arg2 = "log";
try
{
CHECK(1 == 1);
CHECK_F(1==1, msg.c_str(), "message", "log");
}
catch (std::exception const &e)
{
std::cerr << e.what() << std::endl;
ADD_FAILURE() << "Should never have thrown";
}
std::string file_content = readFileToText(logger.logFile());
ASSERT_FALSE(verifyContent(file_content, msg2));
}

219
iOS.cmake Normal file
View File

@ -0,0 +1,219 @@
# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake
# files which are included with CMake 2.8.4
# It has been altered for iOS development
# Options:
#
# IOS_PLATFORM = OS (default) or SIMULATOR or SIMULATOR64
# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders
# OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch.
# SIMULATOR - used to build for the Simulator platforms, which have an x86 arch.
#
# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder
# By default this location is automatcially chosen based on the IOS_PLATFORM value above.
# If set manually, it will override the default location and force the user of a particular Developer Platform
#
# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder
# By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value.
# In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path.
# If set manually, this will force the use of a specific SDK version
# Macros:
#
# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE)
# A convenience macro for setting xcode specific properties on targets
# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1")
#
# find_host_package (PROGRAM ARGS)
# A macro used to find executable programs on the host system, not within the iOS environment.
# Thanks to the android-cmake project for providing the command
# Standard settings
set (CMAKE_SYSTEM_NAME Darwin)
set (CMAKE_SYSTEM_VERSION 1)
set (UNIX True)
set (APPLE True)
set (IOS True)
# Required as of cmake 2.8.10
set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE)
# Allow external setting of CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET. This is clumsy
# but it provides flexibility of not having to hardcode the deployment version in the file or have
# numerous copies of the file
if ($ENV{CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET})
set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET $ENV{CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET})
endif ($ENV{CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET})
# Determine the cmake host system version so we know where to find the iOS SDKs
find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin)
if (CMAKE_UNAME)
exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION)
string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}")
endif (CMAKE_UNAME)
# Use clang. Use xcrun to determine the location
EXEC_PROGRAM(xcrun ARGS -find clang OUTPUT_VARIABLE APPLE_CLANG)
EXEC_PROGRAM(xcrun ARGS -find clang++ OUTPUT_VARIABLE APPLE_CLANGPP)
set(CMAKE_C_COMPILER ${APPLE_CLANG})
set(CMAKE_CXX_COMPILER ${APPLE_CLANGPP})
set(CMAKE_AR ar CACHE FILEPATH "" FORCE)
# Skip the platform compiler checks for cross compiling
set (CMAKE_CXX_COMPILER_WORKS TRUE)
set (CMAKE_C_COMPILER_WORKS TRUE)
# All iOS/Darwin specific settings - some may be redundant
set (CMAKE_SHARED_LIBRARY_PREFIX "lib")
set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
set (CMAKE_SHARED_MODULE_PREFIX "lib")
set (CMAKE_SHARED_MODULE_SUFFIX ".so")
set (CMAKE_MODULE_EXISTS 1)
set (CMAKE_DL_LIBS "")
set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ")
set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}")
set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}")
# Hidden visibilty is required for cxx on iOS
set (CMAKE_C_FLAGS_INIT "")
set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden")
set (CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "" CACHE STRING "Force unset of CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN" FORCE)
set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}")
set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}")
set (CMAKE_PLATFORM_HAS_INSTALLNAME 1)
set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names")
set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names")
set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,")
set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,")
set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a")
set (CMAKE_MACOSX_BUNDLE ON)
set (CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED OFF)
# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree
# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache
# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun)
# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex
if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool)
endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
# Setup iOS platform unless specified manually with IOS_PLATFORM
if (NOT DEFINED IOS_PLATFORM)
set (IOS_PLATFORM "OS")
endif (NOT DEFINED IOS_PLATFORM)
set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform")
# Setup building for arm64 or not
if (NOT DEFINED BUILD_ARM64)
set (BUILD_ARM64 true)
endif (NOT DEFINED BUILD_ARM64)
set (BUILD_ARM64 ${BUILD_ARM64} CACHE STRING "Build arm64 arch or not")
# Check the platform selection and setup for developer root
if (${IOS_PLATFORM} STREQUAL "OS")
set (IOS_PLATFORM_LOCATION "iPhoneOS.platform")
# This causes the installers to properly locate the output libraries
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos")
elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR")
set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform")
# This causes the installers to properly locate the output libraries
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator")
elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR64")
set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform")
# This causes the installers to properly locate the output libraries
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator")
else (${IOS_PLATFORM} STREQUAL "OS")
message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR")
endif (${IOS_PLATFORM} STREQUAL "OS")
# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT
# Note Xcode 4.3 changed the installation location, choose the most recent one available
exec_program(/usr/bin/xcode-select ARGS -print-path OUTPUT_VARIABLE CMAKE_XCODE_DEVELOPER_DIR)
set (XCODE_POST_43_ROOT "${CMAKE_XCODE_DEVELOPER_DIR}/Platforms/${IOS_PLATFORM_LOCATION}/Developer")
set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer")
if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
if (EXISTS ${XCODE_POST_43_ROOT})
set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT})
elseif(EXISTS ${XCODE_PRE_43_ROOT})
set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT})
endif (EXISTS ${XCODE_POST_43_ROOT})
endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform")
# Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT
if (NOT DEFINED CMAKE_IOS_SDK_ROOT)
file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*")
if (_CMAKE_IOS_SDKS)
list (SORT _CMAKE_IOS_SDKS)
list (REVERSE _CMAKE_IOS_SDKS)
list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT)
else (_CMAKE_IOS_SDKS)
message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.")
endif (_CMAKE_IOS_SDKS)
message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}")
endif (NOT DEFINED CMAKE_IOS_SDK_ROOT)
set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK")
# Set the sysroot default to the most recent SDK
set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support")
# set the architecture for iOS
if (${IOS_PLATFORM} STREQUAL "OS")
set (IOS_ARCH armv7 armv7s arm64 arm64e)
elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR")
set (IOS_ARCH i386)
elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR64")
set (IOS_ARCH x86_64)
endif (${IOS_PLATFORM} STREQUAL "OS")
set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS")
# Set the find root to the iOS developer roots and to user defined paths
set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string "iOS find search path root")
# default to searching for frameworks first
set (CMAKE_FIND_FRAMEWORK FIRST)
# set up the default search directories for frameworks
set (CMAKE_SYSTEM_FRAMEWORK_PATH
${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks
${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks
${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks
)
# only search the iOS sdks, not the remainder of the host filesystem
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# This little macro lets you set any XCode specific property
macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE)
set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE})
endmacro (set_xcode_property)
# This macro lets you find executable programs on the host system
macro (find_host_package)
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
set (IOS FALSE)
find_package(${ARGN})
set (IOS TRUE)
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endmacro (find_host_package)

121
iOSBuild.cmake Normal file
View File

@ -0,0 +1,121 @@
if(IOS_PLATFORM)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/Binaries)
endif(IOS_PLATFORM)
if(G3_IOS_LIB)
if (CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET)
set (ENV{CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET} ${CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET})
endif(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET)
set(TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/iOS.cmake")
set(SIM_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/build.i386" CACHE INTERNAL "")
set(SIM_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "")
set(SIM64_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/build.x86_64" CACHE INTERNAL "")
set(SIM64_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "")
set(ARM_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/build.arm" CACHE INTERNAL "")
set(ARM_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "")
file(MAKE_DIRECTORY ${SIM_BINARY_DIR})
execute_process(WORKING_DIRECTORY ${SIM_BINARY_DIR}
COMMAND ${CMAKE_COMMAND}
-GXcode
-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE}
-DIOS_PLATFORM=SIMULATOR
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DADD_FATAL_EXAMPLE=OFF
-DADD_G3LOG_BENCH_PERFORMANCE=OFF
-DADD_G3LOG_UNIT_TEST=OFF
-DG3_SHARED_LIB=OFF
-DCHANGE_G3LOG_DEBUG_TO_DBUG=ON
-DUSE_G3_DYNAMIC_MAX_MESSAGE_SIZE=${USE_G3_DYNAMIC_MAX_MESSAGE_SIZE}
-DENABLE_FATAL_SIGNALHANDLING=${ENABLE_FATAL_SIGNALHANDLING}
"${SIM_SOURCE_DIR}"
)
file(MAKE_DIRECTORY ${SIM64_BINARY_DIR})
execute_process(WORKING_DIRECTORY ${SIM64_BINARY_DIR}
COMMAND ${CMAKE_COMMAND}
-GXcode
-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE}
-DIOS_PLATFORM=SIMULATOR64
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DADD_FATAL_EXAMPLE=OFF
-DG3_SHARED_LIB=OFF
-DADD_G3LOG_BENCH_PERFORMANCE=OFF
-DADD_G3LOG_UNIT_TEST=OFF
-DCHANGE_G3LOG_DEBUG_TO_DBUG=ON
-DUSE_G3_DYNAMIC_MAX_MESSAGE_SIZE=${USE_G3_DYNAMIC_MAX_MESSAGE_SIZE}
-DENABLE_FATAL_SIGNALHANDLING=${ENABLE_FATAL_SIGNALHANDLING}
"${SIM64_SOURCE_DIR}"
)
file(MAKE_DIRECTORY ${ARM_BINARY_DIR})
execute_process(WORKING_DIRECTORY ${ARM_BINARY_DIR}
COMMAND ${CMAKE_COMMAND}
-GXcode
-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE}
-DIOS_PLATFORM=OS
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DADD_FATAL_EXAMPLE=OFF
-DG3_SHARED_LIB=OFF
-DADD_G3LOG_BENCH_PERFORMANCE=OFF
-DADD_G3LOG_UNIT_TEST=OFF
-DCHANGE_G3LOG_DEBUG_TO_DBUG=ON
-DUSE_G3_DYNAMIC_MAX_MESSAGE_SIZE=${USE_G3_DYNAMIC_MAX_MESSAGE_SIZE}
-DENABLE_FATAL_SIGNALHANDLING=${ENABLE_FATAL_SIGNALHANDLING}
"${ARM_SOURCE_DIR}"
)
## Simulator i386 version
add_custom_target(sim
COMMAND ${CMAKE_COMMAND}
--build ${SIM_BINARY_DIR}
--config ${CMAKE_BUILD_TYPE}
COMMENT "Building for i386 (simulator)"
VERBATIM
)
## Simulator x86_64 version
add_custom_target(sim64
COMMAND ${CMAKE_COMMAND}
--build ${SIM64_BINARY_DIR}
--config ${CMAKE_BUILD_TYPE}
COMMENT "Building for x86_64 (simulator)"
VERBATIM
)
## ARM version
add_custom_target(arm
COMMAND ${CMAKE_COMMAND}
--build ${ARM_BINARY_DIR}
--config ${CMAKE_BUILD_TYPE}
COMMENT "Building for armv7, armv7s, arm64, arm64e"
VERBATIM
)
set(LIB_G3 libg3log.a)
add_custom_command(
OUTPUT ${LIB_G3}
COMMAND lipo -create
-output "${CMAKE_CURRENT_BINARY_DIR}/${LIB_G3}"
${SIM_BINARY_DIR}/Binaries/${CMAKE_BUILD_TYPE}/${LIB_G3}
${SIM64_BINARY_DIR}/Binaries/${CMAKE_BUILD_TYPE}/${LIB_G3}
${ARM_BINARY_DIR}/Binaries/${CMAKE_BUILD_TYPE}/${LIB_G3}
DEPENDS
sim
sim64
arm
"${SIM_BINARY_DIR}/Binaries/${CMAKE_BUILD_TYPE}/${LIB_G3}"
"${SIM64_BINARY_DIR}/Binaries/${CMAKE_BUILD_TYPE}/${LIB_G3}"
"${ARM_BINARY_DIR}/Binaries/${CMAKE_BUILD_TYPE}/${LIB_G3}"
VERBATIM
)
add_custom_target(g3log ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${LIB_G3})
endif(G3_IOS_LIB)

17
mkdocs.yml Normal file
View File

@ -0,0 +1,17 @@
site_name: G3log, an asynchronous "crash-safe" logger
site_author: 'Kjell Hedstrom'
site_url: https://kjellkod.github.io/g3log/
theme:
name: material
docs_dir: docs/
nav:
- Introduction to G3log: index.md
- G3log usage: g3log.md
- API description: API.md
- API for custom log formatting: API_custom_formatting.md
- Configure, Build, Package, Install and Test: building.md
- License and contribution: contributing.md

View File

@ -0,0 +1,18 @@
#!/bin/bash
set -ev
set -x
apt-get update -y
apt-get install -y apt-utils | true
apt-get install -y software-properties-common | true
apt-get install -y python-software-properties
apt-get update -y
add-apt-repository -y ppa:jonathonf/gcc
apt-get update -y
apt-get install -y cmake software-properties-common git make
apt-get install -y gcc-7 g++-7
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 90
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 90
apt-get install -y unzip zlib1g-dev
apt-get install -y libboost-all-dev

27
scripts/buildAndRunTests.sh Executable file
View File

@ -0,0 +1,27 @@
#!/bin/bash
set -ev
set -x
mkdir -p build_travis
cd build_travis
cmake -DADD_G3LOG_BENCH_PERFORMANCE=ON -DPRETTY_FUNCTION=ON -DADD_G3LOG_UNIT_TEST=ON -DCMAKE_INSTALL_PREFIX=./install -DCPACK_PACKAGING_INSTALL_PREFIX=/opt/g3log ..
cmake --build . --target install
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
cpack -G "ZIP"
unzip g3log-*-Darwin.zip
fi
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
cpack -G "DEB;TGZ"
tar zxvf g3log-*-Linux.tar.gz
fi
# LINUX OR OSX
makeArg=`grep -c ^processor /proc/cpuinfo || sysctl -n hw.ncpu`
make -j$makeArg
ctest -V

328
src/crashhandler_unix.cpp Normal file
View File

@ -0,0 +1,328 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#include "g3log/crashhandler.hpp"
#include "g3log/logcapture.hpp"
#include "g3log/loglevels.hpp"
#include "g3log/logmessage.hpp"
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
#error "crashhandler_unix.cpp used but it's a windows system"
#endif
#include <cxxabi.h>
#include <execinfo.h>
#include <unistd.h>
#include <atomic>
#include <csignal>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <map>
#include <mutex>
#include <sstream>
#include <thread>
// Linux/Clang, OSX/Clang, OSX/gcc
#if (defined(__clang__) || defined(__APPLE__))
#include <sys/ucontext.h>
#else
#include <ucontext.h>
#endif
namespace {
std::atomic<bool> gBlockForFatal{true};
const std::map<int, std::string> kSignals = {
{SIGABRT, "SIGABRT"},
{SIGFPE, "SIGFPE"},
{SIGILL, "SIGILL"},
{SIGSEGV, "SIGSEGV"},
{SIGTERM, "SIGTERM"},
};
std::map<int, std::string> gSignals = kSignals;
std::map<int, struct sigaction> gSavedSigActions;
bool shouldDoExit() {
static std::atomic<uint64_t> firstExit{0};
auto const count = firstExit.fetch_add(1, std::memory_order_relaxed);
return (0 == count);
}
// Dump of stack,. then exit through g3log background worker
// ALL thanks to this thread at StackOverflow. Pretty much borrowed from:
// Ref: http://stackoverflow.com/questions/77005/how-to-generate-a-stacktrace-when-my-gcc-c-app-crashes
void signalHandler(int signal_number, siginfo_t* info, void* /*unused_context*/) {
using namespace g3::internal;
// Only one signal will be allowed past this point
if (false == shouldDoExit()) {
while (shouldBlockForFatalHandling()) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
{
const auto dump = stackdump();
std::ostringstream fatal_stream;
const auto fatal_reason = exitReasonName(g3::internal::FATAL_SIGNAL, signal_number);
fatal_stream << "Received fatal signal: " << fatal_reason;
fatal_stream << "(" << signal_number << ")\tPID: " << getpid() << std::endl;
fatal_stream << "\n***** SIGNAL " << fatal_reason << "(signo= " << signal_number << " si_errno= " << info->si_errno << " si_code = " << info->si_code << ")" << std::endl;
LogCapture trigger(FATAL_SIGNAL, static_cast<g3::SignalType>(signal_number), dump.c_str());
trigger.stream() << fatal_stream.str();
} // message sent to g3LogWorker
// wait to die
}
//
// Installs FATAL signal handler that is enough to handle most fatal events
// on *NIX systems
void installSignalHandler() {
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
struct sigaction action;
sigemptyset(&action.sa_mask);
action.sa_sigaction = &signalHandler; // callback to crashHandler for fatal signals
// sigaction to use sa_sigaction file. ref: http://www.linuxprogrammingblog.com/code-examples/sigaction
action.sa_flags = SA_SIGINFO;
// do it verbose style - install all signal actions
for (const auto& sig_pair : gSignals) {
struct sigaction old_action;
memset(&old_action, 0, sizeof(old_action));
if (sigaction(sig_pair.first, &action, &old_action) < 0) {
std::string signalerror = "sigaction - " + sig_pair.second;
perror(signalerror.c_str());
} else {
gSavedSigActions[sig_pair.first] = old_action;
}
}
#endif
}
} // end anonymous namespace
// Redirecting and using signals. In case of fatal signals g3log should log the fatal signal
// and flush the log queue and then "rethrow" the signal to exit
namespace g3 {
// References:
// sigaction : change the default action if a specific signal is received
// http://linux.die.net/man/2/sigaction
// http://publib.boulder.ibm.com/infocenter/aix/v6r1/index.jsp?topic=%2Fcom.ibm.aix.basetechref%2Fdoc%2Fbasetrf2%2Fsigaction.html
//
// signal: http://linux.die.net/man/7/signal and
// http://msdn.microsoft.com/en-us/library/xdkz3x12%28vs.71%29.asp
//
// memset + sigemptyset: Maybe unnecessary to do both but there seems to be some confusion here
// ,plenty of examples when both or either are used
// http://stackoverflow.com/questions/6878546/why-doesnt-parent-process-return-to-the-exact-location-after-handling-signal_number
namespace internal {
bool shouldBlockForFatalHandling() {
return gBlockForFatal;
}
/// Generate stackdump. Or in case a stackdump was pre-generated and non-empty just use that one
/// i.e. the latter case is only for Windows and test purposes
std::string stackdump(const char* rawdump) {
if (nullptr != rawdump && !std::string(rawdump).empty()) {
return {rawdump};
}
const size_t max_dump_size = 50;
void* dump[max_dump_size];
const size_t size = backtrace(dump, max_dump_size);
char** messages = backtrace_symbols(dump, static_cast<int>(size)); // overwrite sigaction with caller's address
// dump stack: skip first frame, since that is here
std::ostringstream oss;
for (size_t idx = 1; idx < size && messages != nullptr; ++idx) {
std::string strMessage{messages[idx]};
std::string mangled_name, offset;
/// first look for format that includes brackets "(mangled_name+offset)""
const auto firstBracket = strMessage.find_last_of('(');
const auto secondBracket = strMessage.find_last_of(')');
if (firstBracket != strMessage.npos && secondBracket != strMessage.npos) {
const auto betweenBrackets = strMessage.substr(firstBracket + 1, secondBracket - firstBracket - 1);
const auto plusSign = betweenBrackets.find_first_of('+');
if (plusSign != betweenBrackets.npos) {
mangled_name = betweenBrackets.substr(0, plusSign);
offset = betweenBrackets.substr(plusSign + 1, betweenBrackets.npos);
}
} else {
/// we did not found brackets, looking for "_mangled_name + offset"
const auto plusSign = strMessage.find_first_of('+');
const auto lastUnderscore = strMessage.rfind(" _");
if (plusSign != strMessage.npos && lastUnderscore != strMessage.npos) {
mangled_name = strMessage.substr(lastUnderscore + 1, plusSign - lastUnderscore - 2);
offset = strMessage.substr(plusSign + 2, strMessage.npos);
}
}
// if the line could be processed, attempt to demangle the symbol
if (!mangled_name.empty() && !offset.empty()) {
int status;
char* real_name = abi::__cxa_demangle(mangled_name.c_str(), 0, 0, &status);
// if demangling is successful, output the demangled function name
if (status == 0) {
oss << "\tstack dump [" << idx << "] " << real_name << " + " << offset << std::endl;
} // otherwise, output the mangled function name
else {
oss << "\tstack dump [" << idx << "] " << mangled_name << " + " << offset << std::endl;
}
free(real_name); // mallocated by abi::__cxa_demangle(...)
} else {
// no demangling done -- just dump the whole line
oss << "\tstack dump [" << idx << "] " << strMessage << std::endl;
}
} // END: for(size_t idx = 1; idx < size && messages != nullptr; ++idx)
free(messages);
return oss.str();
}
/// string representation of signal ID
std::string exitReasonName(const LEVELS& level, g3::SignalType fatal_id) {
int signal_number = static_cast<int>(fatal_id);
switch (signal_number) {
case SIGABRT:
return "SIGABRT";
break;
case SIGFPE:
return "SIGFPE";
break;
case SIGSEGV:
return "SIGSEGV";
break;
case SIGILL:
return "SIGILL";
break;
case SIGTERM:
return "SIGTERM";
break;
default:
std::ostringstream oss;
oss << "UNKNOWN SIGNAL(" << signal_number << ") for " << level.text;
return oss.str();
}
}
// Triggered by g3log->g3LogWorker after receiving a FATAL trigger
// which is LOG(FATAL), CHECK(false) or a fatal signal our signalhandler caught.
// --- If LOG(FATAL) or CHECK(false) the signal_number will be SIGABRT
void exitWithDefaultSignalHandler(const LEVELS& level, g3::SignalType fatal_signal_id) {
const int signal_number = static_cast<int>(fatal_signal_id);
// Restore all saved signal handlers. If handling a signal which causes exiting
// than let the original signal handlers to handle other signals.
for (const auto& sig : gSignals) {
restoreSignalHandler(sig.first);
}
std::cerr << "\n\n"
<< __FUNCTION__ << ":" << __LINE__ << ". Exiting due to " << level.text << ", " << signal_number << " \n\n"
<< std::flush;
raise(signal_number);
// When running as PID1 the above kill doesn't have any effect (execution simply passes through it, contrary
// to a non-PID1 process where execution stops at kill and switches over to signal handling). Also as PID1
// we must unblock the thread that received the original signal otherwise the process will never terminate.
gBlockForFatal = false;
exit(signal_number);
}
// This function is intended to be async-signal-safe. Using write and STDERR_FILENO should be
// safe in a signal handler. ref: http://pubs.opengroup.org/onlinepubs/009695399/functions/write.html
// This function is intended to be async-signal-safe.
// It writes an error message to stderr using the write system call,
// which is listed as async-signal-safe by POSIX.
size_t writeErrorMessage(const char* message) {
if (message == nullptr) {
return 0;
}
// Calculate the length of the message without using std library strlen or similar
// this is to ensure async-signal-safe by POSIX
size_t length = 0;
for (const char* p = message; *p != '\0'; ++p) {
++length;
}
// Write the message to STDERR_FILENO in a single call.
// This assumes that the message is not too large for a single write.
auto bytes_written = write(STDERR_FILENO, message, length);
return bytes_written;
}
// restores the signal handler back to default
void restoreFatalHandlingToDefault() {
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
overrideSetupSignals(kSignals);
#endif
}
} // namespace internal
std::string signalToStr(int signal_number) {
std::string signal_name;
const char* signal_name_sz = strsignal(signal_number);
// From strsignal(3): On some systems (but not on Linux), NULL may instead
// be returned for an invalid signal number.
if (nullptr == signal_name_sz) {
signal_name = "Unknown signal " + std::to_string(signal_number);
} else {
signal_name = signal_name_sz;
}
return signal_name;
}
void restoreSignalHandler(int signal_number) {
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
auto old_action_it = gSavedSigActions.find(signal_number);
if (old_action_it == gSavedSigActions.end()) {
return;
}
if (sigaction(signal_number, &(old_action_it->second), nullptr) < 0) {
auto signalname = std::string("sigaction - ") + signalToStr(signal_number);
// https://man7.org/linux/man-pages/man7/signal-safety.7.html (see signal-safety)
internal::writeErrorMessage(signalname.c_str());
}
gSavedSigActions.erase(old_action_it);
#endif
}
// This will override the default signal handler setup and instead
// install a custom set of signals to handle
void overrideSetupSignals(const std::map<int, std::string> overrideSignals) {
static std::mutex signalLock;
std::lock_guard<std::mutex> guard(signalLock);
for (const auto& sig : gSignals) {
restoreSignalHandler(sig.first);
}
gSignals = overrideSignals;
installCrashHandler(); // installs all the signal handling for gSignals
}
// installs the signal handling for whatever signal set that is currently active
// If you want to setup your own signal handling then
// You should instead call overrideSetupSignals()
void installCrashHandler() {
installSignalHandler();
}
} // end namespace g3

View File

@ -0,0 +1,249 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#if !(defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
#error "crashhandler_windows.cpp used but not on a windows system"
#endif
#include <process.h> // getpid
#include <windows.h>
#include <atomic>
#include <csignal>
#include <cstring>
#include <sstream>
#include "g3log/crashhandler.hpp"
#include "g3log/g3log.hpp"
#include "g3log/logcapture.hpp"
#include "g3log/stacktrace_windows.hpp"
#define getpid _getpid
namespace {
std::atomic<bool> gBlockForFatal{true};
LPTOP_LEVEL_EXCEPTION_FILTER g_previous_unexpected_exception_handler = nullptr;
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
thread_local bool g_installed_thread_signal_handler = false;
#endif
#if !(defined(DISABLE_VECTORED_EXCEPTIONHANDLING))
void* g_vector_exception_handler = nullptr;
#endif
// called for fatal signals SIGABRT, SIGFPE, SIGSEGV, SIGILL, SIGTERM
void signalHandler(int signal_number) {
using namespace g3::internal;
std::string dump = stacktrace::stackdump();
std::ostringstream fatal_stream;
fatal_stream << "\n***** Received fatal signal " << g3::internal::exitReasonName(g3::internal::FATAL_SIGNAL, signal_number);
fatal_stream << "(" << signal_number << ")\tPID: " << getpid() << std::endl;
LogCapture trigger(FATAL_SIGNAL, static_cast<g3::SignalType>(signal_number), dump.c_str());
trigger.stream() << fatal_stream.str();
// Trigger debug break point, if we're in debug. This breakpoint CAN cause a slowdown when it happens.
// Be patient. The "Debug" dialog should pop-up eventually if you doing it in Visual Studio.
// For fatal signals only, not exceptions.
// This is a way to tell the IDE (if in dev mode) that it can stop at this breakpoint
// Note that at this time the fatal log event with stack trace is NOT yet flushed to the logger
// This call will do nothing unless we're in DEBUG and "DEBUG_BREAK_AT_FATAL_SIGNAL" is enabled
// ref: g3log/Options.cmake
#if (!defined(NDEBUG) && defined(DEBUG_BREAK_AT_FATAL_SIGNAL))
__debugbreak();
#endif
} // scope exit - message sent to LogWorker, wait to die...
// Unhandled exception catching
LONG WINAPI exceptionHandling(EXCEPTION_POINTERS* info, const std::string& handler) {
std::string dump = stacktrace::stackdump(info);
std::ostringstream fatal_stream;
const g3::SignalType exception_code = info->ExceptionRecord->ExceptionCode;
fatal_stream << "\n***** " << handler << ": Received fatal exception " << g3::internal::exitReasonName(g3::internal::FATAL_EXCEPTION, exception_code);
fatal_stream << "\tPID: " << getpid() << std::endl;
const auto fatal_id = static_cast<g3::SignalType>(exception_code);
LogCapture trigger(g3::internal::FATAL_EXCEPTION, fatal_id, dump.c_str());
trigger.stream() << fatal_stream.str();
// FATAL Exception: It doesn't necessarily stop here. we pass on continue search
// if no one else will catch that then it's goodbye anyhow.
// The RISK here is if someone is catching this and returning "EXCEPTION_EXECUTE_HANDLER"
// but does not shutdown then the software will be running with g3log shutdown.
// .... However... this must be seen as a bug from standard handling of fatal exceptions
// https://msdn.microsoft.com/en-us/library/6wxdsc38.aspx
return EXCEPTION_CONTINUE_SEARCH;
}
// Unhandled exception catching
LONG WINAPI unexpectedExceptionHandling(EXCEPTION_POINTERS* info) {
g3::internal::restoreFatalHandlingToDefault();
return exceptionHandling(info, "Unexpected Exception Handler");
}
/// Setup through (Windows API) AddVectoredExceptionHandler
/// Ref: http://blogs.msdn.com/b/zhanli/archive/2010/06/25/c-tips-addvectoredexceptionhandler-addvectoredcontinuehandler-and-setunhandledexceptionfilter.aspx
#if !(defined(DISABLE_VECTORED_EXCEPTIONHANDLING))
LONG WINAPI vectorExceptionHandling(PEXCEPTION_POINTERS p) {
const g3::SignalType exception_code = p->ExceptionRecord->ExceptionCode;
if (false == stacktrace::isKnownException(exception_code)) {
// The unknown exception is ignored. Since it is not a Windows
// fatal exception generated by the OS we leave the
// responsibility to deal with this by the client software.
return EXCEPTION_CONTINUE_SEARCH;
} else {
g3::internal::restoreFatalHandlingToDefault();
return exceptionHandling(p, "Vectored Exception Handler");
}
}
#endif
} // end anonymous namespace
namespace g3 {
namespace internal {
// For windows exceptions this might ONCE be set to false, in case of a
// windows exceptions and not a signal
bool shouldBlockForFatalHandling() {
return gBlockForFatal;
}
/// Generate stackdump. Or in case a stackdump was pre-generated and
/// non-empty just use that one. i.e. the latter case is only for
/// Windows and test purposes
std::string stackdump(const char* dump) {
if (nullptr != dump && !std::string(dump).empty()) {
return {dump};
}
return stacktrace::stackdump();
}
/// string representation of signal ID or Windows exception id
std::string exitReasonName(const LEVELS& level, g3::SignalType fatal_id) {
if (level == g3::internal::FATAL_EXCEPTION) {
return stacktrace::exceptionIdToText(fatal_id);
}
switch (fatal_id) {
case SIGABRT:
return "SIGABRT";
break;
case SIGFPE:
return "SIGFPE";
break;
case SIGSEGV:
return "SIGSEGV";
break;
case SIGILL:
return "SIGILL";
break;
case SIGTERM:
return "SIGTERM";
break;
default:
std::ostringstream oss;
oss << "UNKNOWN SIGNAL(" << fatal_id << ")";
return oss.str();
}
}
// Triggered by g3log::LogWorker after receiving a FATAL trigger
// which is LOG(FATAL), CHECK(false) or a fatal signal our signalhandler caught.
// --- If LOG(FATAL) or CHECK(false) the signal_number will be SIGABRT
void exitWithDefaultSignalHandler(const LEVELS& level, g3::SignalType fatal_signal_id) {
restoreFatalHandlingToDefault();
// For windows exceptions we want to continue the possibility of
// exception handling now when the log and stacktrace are flushed
// to sinks. We therefore avoid to kill the process here. Instead
// it will be the exceptionHandling functions above that
// will let exception handling continue with: EXCEPTION_CONTINUE_SEARCH
if (g3::internal::FATAL_EXCEPTION == level) {
gBlockForFatal = false;
return;
}
// for a signal however, we exit through that fatal signal
const int signal_number = static_cast<int>(fatal_signal_id);
raise(signal_number);
}
// FYI: Concept of async-signal-safe operations does not exist on windows
// we stick to perror for lack of better alternatives.
size_t writeErrorMessage(const char* message) {
perror(message);
return std::strlen(message);
}
// Restore back to default fatal event handling
void restoreFatalHandlingToDefault() {
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
SetUnhandledExceptionFilter(g_previous_unexpected_exception_handler);
#if !(defined(DISABLE_VECTORED_EXCEPTIONHANDLING))
RemoveVectoredExceptionHandler(g_vector_exception_handler);
#endif
if (SIG_ERR == signal(SIGABRT, SIG_DFL))
internal::writeErrorMessage("signal - SIGABRT");
if (SIG_ERR == signal(SIGFPE, SIG_DFL))
internal::writeErrorMessage("signal - SIGABRT");
if (SIG_ERR == signal(SIGSEGV, SIG_DFL))
internal::writeErrorMessage("signal - SIGABRT");
if (SIG_ERR == signal(SIGILL, SIG_DFL))
internal::writeErrorMessage("signal - SIGABRT");
if (SIG_ERR == signal(SIGTERM, SIG_DFL))
internal::writeErrorMessage("signal - SIGABRT");
#endif
}
void installSignalHandler() {
g3::installSignalHandlerForThread();
}
} // namespace internal
/// SIGFPE, SIGILL, and SIGSEGV handling must be installed per thread
/// on Windows. This is automatically done if you do at least one LOG(...) call
/// you can also use this function call, per thread so make sure these three
/// fatal signals are covered in your thread (even if you don't do a LOG(...) call
void installSignalHandlerForThread() {
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
if (!g_installed_thread_signal_handler) {
g_installed_thread_signal_handler = true;
if (SIG_ERR == signal(SIGTERM, signalHandler))
internal::writeErrorMessage("signal - SIGTERM");
if (SIG_ERR == signal(SIGABRT, signalHandler))
internal::writeErrorMessage("signal - SIGABRT");
if (SIG_ERR == signal(SIGFPE, signalHandler))
internal::writeErrorMessage("signal - SIGFPE");
if (SIG_ERR == signal(SIGSEGV, signalHandler))
internal::writeErrorMessage("signal - SIGSEGV");
if (SIG_ERR == signal(SIGILL, signalHandler))
internal::writeErrorMessage("signal - SIGILL");
}
#endif
}
void installCrashHandler() {
internal::installSignalHandler();
g_previous_unexpected_exception_handler = SetUnhandledExceptionFilter(unexpectedExceptionHandling);
#if !(defined(DISABLE_VECTORED_EXCEPTIONHANDLING))
// const size_t kFirstExceptionHandler = 1;
// kFirstExceptionsHandler is kept here for documentation purposes.
// The last exception seems more like what we want.
const size_t kLastExceptionHandler = 0;
g_vector_exception_handler = AddVectoredExceptionHandler(kLastExceptionHandler, vectorExceptionHandling);
#endif
}
} // end namespace g3

117
src/filesink.cpp Normal file
View File

@ -0,0 +1,117 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#include "g3log/filesink.hpp"
#include <cassert>
#include <chrono>
#include "filesinkhelper.ipp"
namespace g3 {
using namespace internal;
FileSink::FileSink(const std::string& log_prefix, const std::string& log_directory, const std::string& logger_id, size_t write_to_log_every_x_message) :
_log_details_func(&LogMessage::DefaultLogDetailsToString),
_log_file_with_path(log_directory),
_log_prefix_backup(log_prefix),
_outptr(new std::ofstream),
_header("\t\tLOG format: [YYYY/MM/DD hh:mm:ss uuu* LEVEL FILE->FUNCTION:LINE] message\n\n\t\t(uuu*: microseconds fractions of the seconds value)\n\n"),
_firstEntry(true),
_write_counter(0),
_write_to_log_every_x_message(write_to_log_every_x_message) {
_log_prefix_backup = prefixSanityFix(log_prefix);
if (!isValidFilename(_log_prefix_backup)) {
std::cerr << "g3log: forced abort due to illegal log prefix [" << log_prefix << "]" << std::endl;
abort();
}
std::string file_name = createLogFileName(_log_prefix_backup, logger_id);
_log_file_with_path = pathSanityFix(_log_file_with_path, file_name);
_outptr = createLogFile(_log_file_with_path);
if (!_outptr) {
std::cerr << "Cannot write log file to location, attempting current directory" << std::endl;
_log_file_with_path = "./" + file_name;
_outptr = createLogFile(_log_file_with_path);
}
assert(_outptr && "cannot open log file at startup");
}
FileSink::~FileSink() {
std::string exit_msg = {"g3log g3FileSink shutdown at: "};
auto now = std::chrono::system_clock::now();
exit_msg.append(localtime_formatted(now, internal::time_formatted)).append("\n");
// write anything buffered up and then end with the exit msg
filestream() << _write_buffer << exit_msg << std::flush;
exit_msg.append("Log file at: [").append(_log_file_with_path).append("]\n");
std::cerr << exit_msg << std::flush;
}
// The actual log receiving function
void FileSink::fileWrite(LogMessageMover message) {
if (_firstEntry) {
addLogFileHeader();
_firstEntry = false;
}
auto data = message.get().toString(_log_details_func);
_write_buffer.append(data);
if (++_write_counter % _write_to_log_every_x_message == 0) {
filestream() << _write_buffer << std::flush;
_write_buffer.clear();
}
}
std::string FileSink::changeLogFile(const std::string& directory, const std::string& logger_id) {
auto now = std::chrono::system_clock::now();
auto now_formatted = g3::localtime_formatted(now, {internal::date_formatted + " " + internal::time_formatted});
std::string file_name = createLogFileName(_log_prefix_backup, logger_id);
std::string prospect_log = directory + file_name;
std::unique_ptr<std::ofstream> log_stream = createLogFile(prospect_log);
if (nullptr == log_stream) {
filestream() << "\n"
<< now_formatted << " Unable to change log file. Illegal filename or busy? Unsuccessful log name was: " << prospect_log;
return {}; // no success
}
addLogFileHeader();
std::ostringstream ss_change;
ss_change << "\n\tChanging log file from : " << _log_file_with_path;
ss_change << "\n\tto new location: " << prospect_log << "\n";
filestream() << now_formatted << ss_change.str();
ss_change.str("");
std::string old_log = _log_file_with_path;
_log_file_with_path = std::move(prospect_log);
_outptr = std::move(log_stream);
ss_change << "\n\tNew log file. The previous log file was at: ";
ss_change << old_log << "\n";
filestream() << now_formatted << ss_change.str();
return _log_file_with_path;
}
std::string FileSink::fileName() {
return _log_file_with_path;
}
void FileSink::overrideLogDetails(LogMessage::LogDetailsFunc func) {
_log_details_func = func;
}
void FileSink::overrideLogHeader(const std::string& change) {
_header = change;
}
void FileSink::addLogFileHeader() {
filestream() << header(_header);
}
} // namespace g3

127
src/filesinkhelper.ipp Normal file
View File

@ -0,0 +1,127 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include <memory>
#include <string>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
namespace g3 {
namespace internal {
static const std::string file_name_time_formatted = "%Y%m%d-%H%M%S";
// check for filename validity - filename should not be part of PATH
bool isValidFilename(const std::string &prefix_filename) {
std::string illegal_characters("/,|<>:#$%{}[]\'\"^!?+* ");
size_t pos = prefix_filename.find_first_of(illegal_characters, 0);
if (pos != std::string::npos) {
std::cerr << "Illegal character [" << prefix_filename.at(pos) << "] in logname prefix: " << "[" << prefix_filename << "]" << std::endl;
return false;
} else if (prefix_filename.empty()) {
std::cerr << "Empty filename prefix is not allowed" << std::endl;
return false;
}
return true;
}
std::string prefixSanityFix(std::string prefix) {
prefix.erase(std::remove_if(prefix.begin(), prefix.end(), ::isspace), prefix.end());
prefix.erase(std::remove(prefix.begin(), prefix.end(), '/'), prefix.end());
prefix.erase(std::remove(prefix.begin(), prefix.end(), '\\'), prefix.end());
prefix.erase(std::remove(prefix.begin(), prefix.end(), '.'), prefix.end());
prefix.erase(std::remove(prefix.begin(), prefix.end(), ':'), prefix.end());
if (!isValidFilename(prefix)) {
return
{
};
}
return prefix;
}
std::string pathSanityFix(std::string path, const std::string &file_name) {
// Unify the delimeters,. maybe sketchy solution but it seems to work
// on at least win7 + ubuntu. All bets are off for older windows
std::replace(path.begin(), path.end(), '\\', '/');
// clean up in case of multiples
auto contains_end = [&](std::string & in) -> bool {
size_t size = in.size();
if (!size) return false;
char end = in[size - 1];
return (end == '/' || end == ' ');
};
while (contains_end(path)) {
path.erase(path.size() - 1);
}
if (!path.empty()) {
path.insert(path.end(), '/');
}
path.insert(path.size(), file_name);
return path;
}
std::string header(const std::string& headerFormat) {
std::ostringstream ss_entry;
// Day Month Date Time Year: is written as "%a %b %d %H:%M:%S %Y" and formatted output as : Wed Sep 19 08:28:16 2012
auto now = std::chrono::system_clock::now();
ss_entry << "\t\tg3log created log at: " << g3::localtime_formatted(now, "%a %b %d %H:%M:%S %Y") << "\n";
ss_entry << headerFormat;
return ss_entry.str();
}
std::string createLogFileName(const std::string &verified_prefix, const std::string &logger_id) {
std::stringstream oss_name;
oss_name << verified_prefix << ".";
if( !logger_id.empty() ) {
oss_name << logger_id << ".";
}
auto now = std::chrono::system_clock::now();
oss_name << g3::localtime_formatted(now, file_name_time_formatted);
oss_name << ".log";
return oss_name.str();
}
bool openLogFile(const std::string &complete_file_with_path, std::ofstream &outstream) {
std::ios_base::openmode mode = std::ios_base::out; // for clarity: it's really overkill since it's an ofstream
mode |= std::ios_base::trunc;
outstream.open(complete_file_with_path, mode);
if (!outstream.is_open()) {
std::ostringstream ss_error;
ss_error << "FILE ERROR: could not open log file:[" << complete_file_with_path << "]";
ss_error << "\n\t\t std::ios_base state = " << outstream.rdstate();
std::cerr << ss_error.str().c_str() << std::endl;
outstream.close();
return false;
}
return true;
}
std::unique_ptr<std::ofstream> createLogFile(const std::string &file_with_full_path) {
std::unique_ptr<std::ofstream> out(new std::ofstream);
std::ofstream &stream(*(out.get()));
bool success_with_open_file = openLogFile(file_with_full_path, stream);
if (false == success_with_open_file) {
out.reset();
}
return out;
}
}
}

22
src/g2log.hpp Normal file
View File

@ -0,0 +1,22 @@
/** ==========================================================================
* 2015 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
// For convenience: If you don't want to do a recursive search and replace in your source code
// for replacing g2log.hpp for g3log/g3log.hpp then you can choose to add this header file to your
// code. It will get the necessary includes
//
//
// Btw: replacing g2log for g3log include is easy on Linux
// find . -name "*.cpp*" -print | xargs sed -i -e 's/\g2log\.hpp/\g3log\/g3log\.hpp/g'
#include <g3log/filesink.hpp>
#include <g3log/g3log.hpp>
#include <g3log/loglevels.hpp>
#include <g3log/logworker.hpp>

242
src/g3log.cpp Normal file
View File

@ -0,0 +1,242 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================
*
* Filename:g3log.cpp Framework for Logging and Design By Contract
* Created: 2011 by Kjell Hedström
*
* PUBLIC DOMAIN and Not copyrighted since it was built on public-domain software and at least in "spirit" influenced
* from the following sources
* 1. kjellkod.cc ;)
* 2. Dr.Dobbs, Petru Marginean: http://drdobbs.com/article/printableArticle.jhtml?articleId=201804215&dept_url=/cpp/
* 3. Dr.Dobbs, Michael Schulze: http://drdobbs.com/article/printableArticle.jhtml?articleId=225700666&dept_url=/cpp/
* 4. Google 'glog': http://google-glog.googlecode.com/svn/trunk/doc/glog.html
* 5. Various Q&A at StackOverflow
* ********************************************* */
#include "g3log/g3log.hpp"
#include "g3log/crashhandler.hpp"
#include "g3log/loglevels.hpp"
#include "g3log/logmessage.hpp"
#include "g3log/logworker.hpp"
#include <atomic>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <mutex>
#include <sstream>
#include <thread>
namespace {
std::once_flag g_initialize_flag;
g3::LogWorker* g_logger_instance = nullptr; // instantiated and OWNED somewhere else (main)
std::mutex g_logging_init_mutex;
std::unique_ptr<g3::LogMessage> g_first_uninitialized_msg = {nullptr};
std::once_flag g_set_first_uninitialized_flag;
std::once_flag g_save_first_uninitialized_flag;
const std::function<void(void)> g_pre_fatal_hook_that_does_nothing = [] { /*does nothing */ };
std::function<void(void)> g_fatal_pre_logging_hook;
std::atomic<size_t> g_fatal_hook_recursive_counter = {0};
} // namespace
namespace g3 {
// signalhandler and internal clock is only needed to install once
// for unit testing purposes the initializeLogging might be called
// several times...
// for all other practical use, it shouldn't!
void initializeLogging(LogWorker* bgworker) {
std::call_once(g_initialize_flag, [] {
installCrashHandler();
});
std::lock_guard<std::mutex> lock(g_logging_init_mutex);
if (internal::isLoggingInitialized() || nullptr == bgworker) {
std::ostringstream exitMsg;
exitMsg << __FILE__ "->" << __FUNCTION__ << ":" << __LINE__ << std::endl;
exitMsg << "\tFatal exit due to illegal initialization of g3::LogWorker\n";
exitMsg << "\t(due to multiple initializations? : " << std::boolalpha << internal::isLoggingInitialized();
exitMsg << ", due to nullptr == bgworker? : " << std::boolalpha << (nullptr == bgworker) << ")";
std::cerr << exitMsg.str() << std::endl;
std::exit(EXIT_FAILURE);
}
// Save the first uninitialized message, if any
std::call_once(g_save_first_uninitialized_flag, [&bgworker] {
if (g_first_uninitialized_msg) {
bgworker->save(LogMessagePtr{std::move(g_first_uninitialized_msg)});
}
});
g_logger_instance = bgworker;
// by default the pre fatal logging hook does nothing
// if it WOULD do something it would happen in
setFatalPreLoggingHook(g_pre_fatal_hook_that_does_nothing);
// recursive crash counter re-set to zero
g_fatal_hook_recursive_counter.store(0);
}
/**
* default does nothing, @ref ::g_pre_fatal_hook_that_does_nothing
* It will be called just before sending the fatal message, @ref pushFatalmessageToLogger
* It will be reset to do nothing in ::initializeLogging(...)
* so please call this function, if you ever need to, after initializeLogging(...)
*/
void setFatalPreLoggingHook(std::function<void(void)> pre_fatal_hook) {
static std::mutex m;
std::lock_guard<std::mutex> lock(m);
g_fatal_pre_logging_hook = pre_fatal_hook;
}
// By default this function pointer goes to \ref pushFatalMessageToLogger;
std::function<void(FatalMessagePtr)> g_fatal_to_g3logworker_function_ptr = internal::pushFatalMessageToLogger;
/** REPLACE fatalCallToLogger for fatalCallForUnitTest
* This function switches the function pointer so that only
* 'unitTest' mock-fatal calls are made.
* */
void setFatalExitHandler(std::function<void(FatalMessagePtr)> fatal_call) {
g_fatal_to_g3logworker_function_ptr = fatal_call;
}
namespace internal {
bool isLoggingInitialized() {
return g_logger_instance != nullptr;
}
/**
* Shutdown the logging by making the pointer to the background logger to nullptr. The object is not deleted
* that is the responsibility of its owner. *
*/
void shutDownLogging() {
std::lock_guard<std::mutex> lock(g_logging_init_mutex);
g_logger_instance = nullptr;
}
/** Same as the Shutdown above but called by the destructor of the LogWorker, thus ensuring that no further
* LOG(...) calls can happen to a non-existing LogWorker.
* @param active MUST BE the LogWorker initialized for logging. If it is not then this call is just ignored
* and the logging continues to be active.
* @return true if the correct worker was given,. and shutDownLogging was called
*/
bool shutDownLoggingForActiveOnly(LogWorker* active) {
if (isLoggingInitialized() && nullptr != active && (active != g_logger_instance)) {
LOG(WARNING) << "\n\t\tAttempted to shut down logging, but the ID of the Logger is not the one that is active."
<< "\n\t\tHaving multiple instances of the g3::LogWorker is likely a BUG"
<< "\n\t\tEither way, this call to shutDownLogging was ignored"
<< "\n\t\tTry g3::internal::shutDownLogging() instead";
return false;
}
shutDownLogging();
return true;
}
/** explicitly copy of all input. This is makes it possibly to use g3log across dynamically loaded libraries
* i.e. (dlopen + dlsym) */
void saveMessage(const char* entry, const char* file, int line, const char* function, const LEVELS& level,
const char* boolean_expression, int fatal_signal, const char* stack_trace) {
LEVELS msgLevel{level};
LogMessagePtr message{std::make_unique<LogMessage>(file, line, function, msgLevel)};
message.get()->write().append(entry);
message.get()->setExpression(boolean_expression);
if (internal::wasFatal(level)) {
saveFatalMessage(stack_trace, message, fatal_signal);
} else {
pushMessageToLogger(message);
}
}
void saveFatalMessage(const char* stack_trace, g3::LogMessagePtr& message, int& fatal_signal) {
auto fatalhook = g_fatal_pre_logging_hook;
// In case the fatal_pre logging actually will cause a crash in its turn
// let's not do recursive crashing!
setFatalPreLoggingHook(g_pre_fatal_hook_that_does_nothing);
++g_fatal_hook_recursive_counter; // thread safe counter
// "benign" race here. If two threads crashes, with recursive crashes
// then it's possible that the "other" fatal stack trace will be shown
// that's OK since it was anyhow the first crash detected
static const std::string first_stack_trace = stack_trace;
fatalhook();
message.get()->write().append(stack_trace);
if (g_fatal_hook_recursive_counter.load() > 1) {
message.get()->write().append(
"\n\n\nWARNING\n"
"A recursive crash detected. It is likely the hook set with 'setFatalPreLoggingHook(...)' is responsible\n\n")
.append("---First crash stacktrace: ")
.append(first_stack_trace)
.append("\n---End of first stacktrace\n");
}
FatalMessagePtr fatal_message{std::make_unique<FatalMessage>(*(message._move_only.get()), fatal_signal)};
// At destruction, flushes fatal message to g3LogWorker
// either we will stay here until the background worker has received the fatal
// message, flushed the crash message to the sinks and exits with the same fatal signal
//..... OR it's in unit-test mode then we throw a std::runtime_error (and never hit sleep)
fatalCall(fatal_message);
}
/**
* save the message to the logger. In case of called before the logger is instantiated
* the first message will be saved. Any following subsequent uninitialized log calls
* will be ignored.
*
* The first initialized log entry will also save the first uninitialized log message, if any
* @param log_entry to save to logger
*/
void pushMessageToLogger(LogMessagePtr incoming) { // todo rename to Push SavedMessage To Worker
// Uninitialized messages are ignored but does not CHECK/crash the logger
if (!internal::isLoggingInitialized()) {
std::call_once(g_set_first_uninitialized_flag, [&] {
g_first_uninitialized_msg = incoming.release();
std::string err = {"LOGGER NOT INITIALIZED:\n\t\t"};
err.append(g_first_uninitialized_msg->message());
std::string& str = g_first_uninitialized_msg->write();
str.clear();
str.append(err); // replace content
std::cerr << str << std::endl; });
return;
}
// logger is initialized
g_logger_instance->save(incoming);
}
/** Fatal call saved to logger. This will trigger SIGABRT or other fatal signal
* to exit the program. After saving the fatal message the calling thread
* will sleep forever (i.e. until the background thread catches up, saves the fatal
* message and kills the software with the fatal signal.
*/
void pushFatalMessageToLogger(FatalMessagePtr message) {
if (!isLoggingInitialized()) {
std::ostringstream error;
error << "FATAL CALL but logger is NOT initialized\n"
<< "CAUSE: " << message.get()->reason()
<< "\nMessage: \n"
<< message.get()->toString() << std::flush;
std::cerr << error.str() << std::flush;
internal::exitWithDefaultSignalHandler(message.get()->_level, message.get()->_signal_id);
}
g_logger_instance->fatal(message);
while (shouldBlockForFatalHandling()) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
/** The default, initial, handling to send a 'fatal' event to g3logworker
* the caller will stay here, eternally, until the software is aborted
* ... in the case of unit testing it is the given "Mock" fatalCall that will
* define the behaviour.
*/
void fatalCall(FatalMessagePtr message) {
g_fatal_to_g3logworker_function_ptr(FatalMessagePtr{std::move(message)});
}
} // namespace internal
} // namespace g3

67
src/g3log/active.hpp Normal file
View File

@ -0,0 +1,67 @@
/** ==========================================================================
* 2010 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================
*
* Example of a Active Object, using C++11 std::thread mechanisms to make it
* safe for thread communication.
*
* This was originally published at http://sites.google.com/site/kjellhedstrom2/active-object-with-cpp0x
* and inspired from Herb Sutter's C++11 Active Object
* http://herbsutter.com/2010/07/12/effective-concurrency-prefer-using-active-objects-instead-of-naked-threads
*
* Last update 2013-12-19 by Kjell Hedstrom,
* e-mail: hedstrom at kjellkod dot cc
* linkedin: http://linkedin.com/se/kjellkod */
#pragma once
#include <functional>
#include <memory>
#include <thread>
#include "g3log/shared_queue.hpp"
namespace kjellkod {
typedef std::function<void()> Callback;
class Active {
private:
Active() :
done_(false) {} // Construction ONLY through factory createActive();
Active(const Active&) = delete;
Active& operator=(const Active&) = delete;
void run() {
while (!done_) {
Callback func;
mq_.wait_and_pop(func);
func();
}
}
shared_queue<Callback> mq_;
std::thread thd_;
bool done_;
public:
virtual ~Active() {
send([this]() noexcept { done_ = true; });
thd_.join();
}
void send(Callback msg_) {
mq_.push(msg_);
}
/// Factory: safe construction of object before thread start
static std::unique_ptr<Active> createActive() {
std::unique_ptr<Active> aPtr(new Active());
aPtr->thd_ = std::thread(&Active::run, aPtr.get());
return aPtr;
}
};
} // namespace kjellkod

47
src/g3log/atomicbool.hpp Normal file
View File

@ -0,0 +1,47 @@
/** ==========================================================================
* 2015 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include <atomic>
namespace g3 {
/// As suggested in: http://stackoverflow.com/questions/13193484/how-to-declare-a-vector-of-atomic-in-c
struct atomicbool {
private:
std::atomic<bool> value_;
public:
atomicbool() :
value_{false} {}
atomicbool(bool value) :
value_{value} {}
atomicbool(const std::atomic<bool>& value) :
value_{value.load(std::memory_order_acquire)} {}
atomicbool(const atomicbool& other) :
value_{other.value_.load(std::memory_order_acquire)} {}
atomicbool& operator=(const atomicbool& other) {
value_.store(other.value_.load(std::memory_order_acquire), std::memory_order_release);
return *this;
}
atomicbool& operator=(const bool other) {
value_.store(other, std::memory_order_release);
return *this;
}
bool operator==(const atomicbool& rhs) const {
return (value_.load(std::memory_order_acquire) == rhs.value_.load(std::memory_order_acquire));
}
bool value() { return value_.load(std::memory_order_acquire); }
std::atomic<bool>& get() { return value_; }
};
} // namespace g3
// explicit whitespace/EOF for VS15

View File

@ -0,0 +1,82 @@
#pragma once
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#include <cstdio>
#include <map>
#include <string>
#include "g3log/generated_definitions.hpp"
#include "g3log/loglevels.hpp"
// kjell. Separera på crashhandler.hpp och crashhanlder_internal.hpp
// implementationsfilen kan vara den samma
namespace g3 {
// PUBLIC API:
/** Install signal handler that catches FATAL C-runtime or OS signals
See the wikipedia site for details http://en.wikipedia.org/wiki/SIGFPE
See the this site for example usage: http://www.tutorialspoint.com/cplusplus/cpp_signal_handling
SIGABRT ABORT (ANSI), abnormal termination
SIGFPE Floating point exception (ANSI)
SIGILL ILlegal instruction (ANSI)
SIGSEGV Segmentation violation i.e. illegal memory reference
SIGTERM TERMINATION (ANSI) */
void installCrashHandler();
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
typedef unsigned long SignalType;
/// SIGFPE, SIGILL, and SIGSEGV handling must be installed per thread
/// on Windows. This is automatically done if you do at least one LOG(...) call
/// you can also use this function call, per thread so make sure these three
/// fatal signals are covered in your thread (even if you don't do a LOG(...) call
void installSignalHandlerForThread();
#else
typedef int SignalType;
std::string signalToStr(int signal_number);
// restore to whatever signal handler was used before signal handler installation
void restoreSignalHandler(int signal_number);
/// Overrides the existing signal handling for custom signals
/// For example: usage of zcmq relies on its own signal handler for SIGTERM
/// so users of g3log with zcmq should then use the @ref overrideSetupSignals
/// , likely with the original set of signals but with SIGTERM removed
///
/// call example:
/// g3::overrideSetupSignals({ {SIGABRT, "SIGABRT"}, {SIGFPE, "SIGFPE"},{SIGILL, "SIGILL"},
// {SIGSEGV, "SIGSEGV"},});
void overrideSetupSignals(const std::map<int, std::string> overrideSignals);
#endif
namespace internal {
/// Resets the fatal signal/exception handling back to default
/// which might be needed in case it was previously overridden
/// The default signals are: SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGTERM
void restoreFatalHandlingToDefault();
/** return whether or any fatal handling is still ongoing
* this is used by g3log::fatalCallToLogger
* only in the case of Windows exceptions (not fatal signals)
* are we interested in changing this from false to true to
* help any other exceptions handler work with 'EXCEPTION_CONTINUE_SEARCH'*/
bool shouldBlockForFatalHandling();
/** \return signal_name Ref: signum.hpp and \ref installSignalHandler
* or for Windows exception name */
std::string exitReasonName(const LEVELS& level, g3::SignalType signal_number);
/** return calling thread's stackdump*/
std::string stackdump(const char* dump = nullptr);
/** Re-"throw" a fatal signal, previously caught. This will exit the application
* This is an internal only function. Do not use it elsewhere. It is triggered
* from g3log, g3LogWorker after flushing messages to file */
void exitWithDefaultSignalHandler(const LEVELS& level, g3::SignalType signal_number);
size_t writeErrorMessage(const char* message);
} // namespace internal
} // namespace g3

46
src/g3log/filesink.hpp Normal file
View File

@ -0,0 +1,46 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include <memory>
#include <string>
#include "g3log/logmessage.hpp"
namespace g3 {
class FileSink {
public:
FileSink(const std::string& log_prefix, const std::string& log_directory, const std::string& logger_id = "g3log", size_t write_to_log_every_x_message = 100);
virtual ~FileSink();
void fileWrite(LogMessageMover message);
std::string changeLogFile(const std::string& directory, const std::string& logger_id);
std::string fileName();
void overrideLogDetails(LogMessage::LogDetailsFunc func);
void overrideLogHeader(const std::string& change);
private:
LogMessage::LogDetailsFunc _log_details_func;
std::string _log_file_with_path;
std::string _log_prefix_backup; // needed in case of future log file changes of directory
std::unique_ptr<std::ofstream> _outptr;
std::string _header;
bool _firstEntry;
std::string _write_buffer;
size_t _write_counter;
size_t _write_to_log_every_x_message;
void addLogFileHeader();
std::ofstream& filestream() {
return *(_outptr.get());
}
FileSink& operator=(const FileSink&) = delete;
FileSink(const FileSink& other) = delete;
};
} // namespace g3

60
src/g3log/future.hpp Normal file
View File

@ -0,0 +1,60 @@
#pragma once
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================
* Filename:g3future.hpp
* Helper functionality to put packaged_tasks in standard container. This
* is especially helpful for background thread processing a la async but through
* an actor pattern (active object), thread pool or similar.
* Created: 2012 by Kjell Hedström
*
* COMMUNITY THANKS:
* The code below is in large thanks to exemplifying code snippets from StackOverflow
* question/answer: http://stackoverflow.com/questions/6230893/developing-c-concurrency-library-with-futures-or-similar-paradigm
* and a discussion between Lars Gullik Bjønnes and Jonathan Wakely's at: http://gcc.gnu.org/ml/gcc-help/2011-11/msg00052.html
*
* Both are highly recommended reads if you are interested in c++ concurrency library
* - Kjell, 2012
*
* PUBLIC DOMAIN and NOT under copywrite protection.
* ********************************************* */
#include <future>
#include "g3log/active.hpp"
#include "g3log/moveoncopy.hpp"
#include "g3log/stlpatch_future.hpp"
namespace g3 {
// Generic helper function to avoid repeating the steps for managing
// asynchronous task job (by active object) that returns a future results
// could of course be made even more generic if done more in the way of
// std::async, ref: http://en.cppreference.com/w/cpp/thread/async
//
// Example usage:
// std::unique_ptr<Active> bgWorker{Active::createActive()};
// ...
// auto msg_call=[=](){return ("Hello from the Background");};
// auto future_msg = g3::spawn_task(msg_lambda, bgWorker.get());
template <typename Func, class BgWorker>
std::future<std::invoke_result_t<Func>> spawn_task(Func func, BgWorker* worker) {
typedef std::invoke_result_t<Func> result_type;
typedef std::packaged_task<result_type()> task_type;
if (nullptr == worker) {
auto p = std::make_shared<std::promise<result_type>>();
std::future<result_type> future_result = p->get_future();
p->set_exception(std::make_exception_ptr(std::runtime_error("nullptr instantiated worker")));
return future_result;
}
task_type task(std::move(func));
std::future<result_type> result = task.get_future();
worker->send(MoveOnCopy<task_type>(std::move(task)));
return result;
}
} // end namespace g3

227
src/g3log/g3log.hpp Normal file
View File

@ -0,0 +1,227 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================
*
* Filename:g3log.hpp Framework for Logging and Design By Contract
* Created: 2011 by Kjell Hedström
*
* PUBLIC DOMAIN and Not copywrited since it was built on public-domain software and influenced
* at least in "spirit" from the following sources
* 1. kjellkod.cc ;)
* 2. Dr.Dobbs, Petru Marginean: http://drdobbs.com/article/printableArticle.jhtml?articleId=201804215&dept_url=/caddpp/
* 3. Dr.Dobbs, Michael Schulze: http://drdobbs.com/article/printableArticle.jhtml?articleId=225700666&dept_url=/cpp/
* 4. Google 'glog': http://google-glog.googlecode.com/svn/trunk/doc/glog.html
* 5. Various Q&A at StackOverflow
* ********************************************* */
#pragma once
#include "g3log/generated_definitions.hpp"
#include "g3log/logcapture.hpp"
#include "g3log/loglevels.hpp"
#include "g3log/logmessage.hpp"
#include <functional>
#include <string>
#if defined(_MSC_VER) && (defined(WINDOWS_FUNCSIG)) // Microsoft
#define G3LOG_PRETTY_FUNCTION __FUNCSIG__
#elif defined(__GNUC__) && defined(PRETTY_FUNCTION) // GCC compatible
#define G3LOG_PRETTY_FUNCTION __PRETTY_FUNCTION__
#else
#define G3LOG_PRETTY_FUNCTION __FUNCTION__
#endif
// thread_local doesn't exist before VS2013
// it exists on VS2015
#if !(defined(thread_local)) && defined(_MSC_VER) && _MSC_VER < 1900
#define thread_local __declspec(thread)
#endif
/** namespace for LOG() and CHECK() frameworks
* History lesson: Why the names 'g3' and 'g3log'?:
* The framework was made in my own free time as PUBLIC DOMAIN but the
* first commercial project to use it used 'g3' as an internal denominator for
* the current project. g3 as in 'generation 2'. I decided to keep the g3 and g3log names
* to give credit to the people in that project (you know who you are :) and I guess also
* for 'sentimental' reasons. That a big influence was Google's glog is just a happy
* coincidence or subconscious choice. Either way g3log became the name for this logger.
*
* --- Thanks for a great 2011 and good luck with 'g3' --- KjellKod
*/
namespace g3 {
class LogWorker;
struct LogMessage;
struct FatalMessage;
/** Should be called at very first startup of the software with \ref g3LogWorker
* pointer. Ownership of the \ref g3LogWorker is the responsibility of the caller */
void initializeLogging(LogWorker* logger);
/** setFatalPreLoggingHook() provides an optional extra step before the fatalExitHandler is called
*
* Set a function-hook before a fatal message will be sent to the logger
* i.e. this is a great place to put a break point, either in your debugger
* or programmatically to catch LOG(FATAL), CHECK(...) or an OS fatal event (exception or signal)
* This will be reset to default (does nothing) at initializeLogging(...);
*
* Example usage:
* Windows: g3::setFatalPreLoggingHook([]{__debugbreak();}); // remember #include <intrin.h>
* WARNING: '__debugbreak()' when not running in Debug in your Visual Studio IDE will likely
* trigger a recursive crash if used here. It should only be used when debugging
* in your Visual Studio IDE. Recursive crashes are handled but are unnecessary.
*
* Linux: g3::setFatalPreLoggingHook([]{ raise(SIGTRAP); });
*/
void setFatalPreLoggingHook(std::function<void(void)> pre_fatal_hook);
/** If the @ref setFatalPreLoggingHook is not enough and full fatal exit handling is needed then
* use "setFatalExithandler". Please see g3log.cpp and crashhandler_windows.cpp or crashhandler_unix for
* example of restoring signal and exception handlers, flushing the log and shutting down.
*/
void setFatalExitHandler(std::function<void(FatalMessagePtr)> fatal_call);
#ifdef G3_DYNAMIC_MAX_MESSAGE_SIZE
// only_change_at_initialization namespace is for changes to be done only during initialization. More specifically
// items here would be called prior to calling other parts of g3log
namespace only_change_at_initialization {
// Sets the MaxMessageSize to be used when capturing log messages. Currently this value is set to 2KB. Messages
// Longer than this are bound to 2KB with the string "[...truncated...]" at the end. This function allows
// this limit to be changed.
void setMaxMessageSize(size_t max_size);
} // namespace only_change_at_initialization
#endif /* G3_DYNAMIC_MAX_MESSAGE_SIZE */
// internal namespace is for completely internal or semi-hidden from the g3 namespace due to that it is unlikely
// that you will use these
namespace internal {
/// @returns true if logger is initialized
bool isLoggingInitialized();
// Save the created LogMessage to any existing sinks
void saveMessage(const char* message, const char* file, int line, const char* function, const LEVELS& level,
const char* boolean_expression, int fatal_signal, const char* stack_trace);
void saveFatalMessage(const char* stack_trace, g3::LogMessagePtr& message, int& fatal_signal);
// forwards the message to all sinks
void pushMessageToLogger(LogMessagePtr log_entry);
// forwards a FATAL message to all sinks,. after which the g3logworker
// will trigger crashhandler / g3::internal::exitWithDefaultSignalHandler
//
// By default the "fatalCall" will forward a FatalMessageptr to this function
// this behavior can be changed if you set a different fatal handler through
// "setFatalExitHandler"
void pushFatalMessageToLogger(FatalMessagePtr message);
// Saves the created FatalMessage to any existing sinks and exits with
// the originating fatal signal,. or SIGABRT if it originated from a broken contract.
// By default forwards to: pushFatalMessageToLogger, see "setFatalExitHandler" to override
//
// If you override it then you probably want to call "pushFatalMessageToLogger" after your
// custom fatal handler is done. This will make sure that the fatal message the pushed
// to sinks as well as shutting down the process
void fatalCall(FatalMessagePtr message);
// Shuts down logging. No object cleanup but further LOG(...) calls will be ignored.
void shutDownLogging();
// Shutdown logging, but ONLY if the active logger corresponds to the one currently initialized
bool shutDownLoggingForActiveOnly(LogWorker* active);
} // namespace internal
} // namespace g3
// clang-format off
#define INTERNAL_LOG_MESSAGE(level) LogCapture(__FILE__, __LINE__, static_cast<const char*>(G3LOG_PRETTY_FUNCTION), level)
#define INTERNAL_CONTRACT_MESSAGE(boolean_expression) \
LogCapture(__FILE__, __LINE__, G3LOG_PRETTY_FUNCTION, g3::internal::CONTRACT, boolean_expression)
// LOG(level) is the API for the stream log
#define LOG(level) if (!g3::logLevel(level)) {} else INTERNAL_LOG_MESSAGE(level).stream()
// 'Conditional' stream log
#define LOG_IF(level, boolean_expression) \
if (!g3::logLevel(level) || false == (boolean_expression)) {} else INTERNAL_LOG_MESSAGE(level).stream()
// 'Design By Contract' stream API. Broken Contracts will exit the application by using fatal signal SIGABRT
// For unit testing, you can override the fatal handling using setFatalExitHandler(...). See tes_io.cpp for examples
#define CHECK(boolean_expression) \
if (true == (boolean_expression)) {} else INTERNAL_CONTRACT_MESSAGE(#boolean_expression).stream()
/** For details please see this
* REFERENCE: http://www.cppreference.com/wiki/io/c/printf_format
* \verbatim
*
There are different %-codes for different variable types, as well as options to
limit the length of the variables and whatnot.
Code Format
%[flags][width][.precision][length]specifier
SPECIFIERS
----------
%c character
%d signed integers
%i signed integers
%e scientific notation, with a lowercase e
%E scientific notation, with a uppercase E
%f floating point
%g use %e or %f, whichever is shorter
%G use %E or %f, whichever is shorter
%o octal
%s a string of characters
%u unsigned integer
%x unsigned hexadecimal, with lowercase letters
%X unsigned hexadecimal, with uppercase letters
%p a pointer
%n the argument shall be a pointer to an integer into which is placed the number of characters written so far
For flags, width, precision etc please see the above references.
EXAMPLES:
{
LOGF(INFO, "Characters: %c %c \n", 'a', 65);
LOGF(INFO, "Decimals: %d %ld\n", 1977, 650000L); // printing long
LOGF(INFO, "Preceding with blanks: %10d \n", 1977);
LOGF(INFO, "Preceding with zeros: %010d \n", 1977);
LOGF(INFO, "Some different radixes: %d %x %o %#x %#o \n", 100, 100, 100, 100, 100);
LOGF(INFO, "floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416);
LOGF(INFO, "Width trick: %*d \n", 5, 10);
LOGF(INFO, "%s \n", "A string");
return 0;
}
And here is possible output
: Characters: a A
: Decimals: 1977 650000
: Preceding with blanks: 1977
: Preceding with zeros: 0000001977
: Some different radixes: 100 64 144 0x64 0144
: floats: 3.14 +3e+000 3.141600E+000
: Width trick: 10
: A string \endverbatim */
#define LOGF(level, printf_like_message, ...) \
if (!g3::logLevel(level)) {} else INTERNAL_LOG_MESSAGE(level).capturef(printf_like_message, ##__VA_ARGS__)
// Conditional log printf syntax
#define LOGF_IF(level,boolean_expression, printf_like_message, ...) \
if (!g3::logLevel(level) || false == (boolean_expression)) {} else INTERNAL_LOG_MESSAGE(level).capturef(printf_like_message, ##__VA_ARGS__)
// Design By Contract, printf-like API syntax with variadic input parameters.
// Calls the signal handler if the contract failed with the default exit for a failed contract. This is typically SIGABRT
// See g3log, setFatalExitHandler(...) which can be overriden for unit tests (ref test_io.cpp)
#define CHECKF(boolean_expression, printf_like_message, ...) \
if (true == (boolean_expression)) {} else INTERNAL_CONTRACT_MESSAGE(#boolean_expression).capturef(printf_like_message, ##__VA_ARGS__)
// Backwards compatible. The same as CHECKF.
// Design By Contract, printf-like API syntax with variadic input parameters.
// Calls the signal handler if the contract failed. See g3log, setFatalExitHandler(...) which can be overriden for unit tests
// (ref test_io.cpp)
#define CHECK_F(boolean_expression, printf_like_message, ...) \
if (true == (boolean_expression)) {} else INTERNAL_CONTRACT_MESSAGE(#boolean_expression).capturef(printf_like_message, ##__VA_ARGS__)
// clang-format on

75
src/g3log/logcapture.hpp Normal file
View File

@ -0,0 +1,75 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include "g3log/crashhandler.hpp"
#include "g3log/loglevels.hpp"
#include <csignal>
#include <cstdarg>
#include <sstream>
#include <string>
#ifdef _MSC_VER
#include <sal.h>
#endif
/**
* Simple struct for capturing log/fatal entries. At destruction the captured message is
* forwarded to background worker.
* As a safety precaution: No memory allocated here will be moved into the background
* worker in case of dynamic loaded library reasons
*/
struct LogCapture {
/// Called from crash handler when a fatal signal has occurred (SIGSEGV etc)
LogCapture(const LEVELS& level, g3::SignalType fatal_signal, const char* dump = nullptr);
/**
* @file, line, function are given in g3log.hpp from macros
* @level INFO/DEBUG/WARNING/FATAL
* @expression for CHECK calls
* @fatal_signal for failed CHECK:SIGABRT or fatal signal caught in the signal handler
*/
LogCapture(const char* file, const int line, const char* function, const LEVELS& level, const char* expression = "", g3::SignalType fatal_signal = SIGABRT, const char* dump = nullptr);
// At destruction the message will be forwarded to the g3log worker.
// In the case of dynamically (at runtime) loaded libraries, the important thing to know is that
// all strings are copied, so the original are not destroyed at the receiving end, only the copy
virtual ~LogCapture() noexcept(false);
#ifdef _MSC_VER
#if _MSC_VER >= 1400
#define G3LOG_FORMAT_STRING _Printf_format_string_
#else
#define G3LOG_FORMAT_STRING __format_string
#endif
void capturef(G3LOG_FORMAT_STRING const char* printf_like_message, ...);
#else
#define G3LOG_FORMAT_STRING
// Use "-Wall" to generate warnings in case of illegal printf format.
// Ref: http://www.unixwiz.net/techtips/gnu-c-attributes.html
[[gnu::format(printf, 2, 3)]] void capturef(G3LOG_FORMAT_STRING const char* printf_like_message, ...); // 2,3 ref: http://www.codemaestro.com/reviews/18
#endif
/// prettifying API for this completely open struct
std::ostringstream& stream() {
return _stream;
}
std::ostringstream _stream;
std::string _stack_trace;
const char* _file;
const int _line;
const char* _function;
const LEVELS& _level;
const char* _expression;
const g3::SignalType _fatal_signal;
};
//} // g3

195
src/g3log/loglevels.hpp Normal file
View File

@ -0,0 +1,195 @@
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include "g3log/generated_definitions.hpp"
// Users of Juce or other libraries might have a define DEBUG which clashes with
// the DEBUG logging level for G3log. In that case they can instead use the define
// "CHANGE_G3LOG_DEBUG_TO_DBUG" and G3log's logging level DEBUG is changed to be DBUG
#if (defined(CHANGE_G3LOG_DEBUG_TO_DBUG))
#if (defined(DBUG))
#error "DBUG is already defined elsewhere which clashes with G3Log's log level DBUG"
#endif
#else
#if (defined(DEBUG))
#error "DEBUG is already defined elsewhere which clashes with G3Log's log level DEBUG"
#endif
#endif
#include <algorithm>
#include <atomic>
#include <g3log/atomicbool.hpp>
#include <map>
#include <string>
// Levels for logging, made so that it would be easy to change, remove, add levels -- KjellKod
struct LEVELS {
// force internal copy of the const char*. This is a simple safeguard for when g3log is used in a
// "dynamic, runtime loading of shared libraries"
LEVELS(const LEVELS& other) :
value(other.value),
text(other.text.c_str()) {}
LEVELS(int id, const std::string& idtext) :
value(id),
text(idtext) {}
bool operator==(const LEVELS& rhs) const {
return (value == rhs.value && text == rhs.text);
}
bool operator!=(const LEVELS& rhs) const {
return (value != rhs.value || text != rhs.text);
}
friend void swap(LEVELS& first, LEVELS& second) {
using std::swap;
swap(first.value, second.value);
swap(first.text, second.text);
}
LEVELS& operator=(LEVELS other) {
swap(*this, other);
return *this;
}
int value;
std::string text;
};
// If you want to add any extra logging level then please add to your own source file the logging level you need
// 1. If the cmake option G3_DYNAMIC_LOGGING is enabled then you must use g3::only_change_at_initialization::addLogLevel(...).
// to give g3log a record of your logging level and if it is an enabled or disbled logging level.
//
// 2. If the cmake dynamic logging option is turned OFF
// then giving g3log a record of your logging level with 'addLogLevel(...) is NOT needed since no "disbled/enabled"
// check will happen - all logging levels will be considered enabled.
// 3. See also the [g3log/API.markdown](https://github.com/KjellKod/g3log/blob/master/API.markdown) for for information.
//
// example: MyLoggingLevel.h
// #pragma once
// const LEVELS MYINFO {WARNING.value +1, "MyInfoLevel"};
// const LEVELS MYFATAL {FATAL.value +1, "MyFatalLevel"};
//
// ... somewhere else when G3_DYNAMIC_LOGGING is enabled
// addLogLevel(MYINFO, true);
// LOG(MYINFO) << "some text";
//
// ... another example, when G3_DYNAMIC_LOGGING is enabled
// 'addLogLevel' is NOT required
// LOG(MYFATAL) << "this will just work, and it will be counted as a FATAL event";
namespace g3 {
static const int kDebugValue = 100;
static const int kInfoValue = 300;
static const int kWarningValue = 500;
static const int kFatalValue = 1000;
static const int kInternalFatalValue = 2000;
} // namespace g3
const LEVELS G3LOG_DEBUG{g3::kDebugValue, "DEBUG"},
INFO{g3::kInfoValue, "INFO"},
WARNING{g3::kWarningValue, "WARNING"},
FATAL{g3::kFatalValue, "FATAL"};
namespace g3 {
// Logging level and atomic status collection struct
struct LoggingLevel {
atomicbool status;
LEVELS level;
// default operator needed for std::map compliance
LoggingLevel() :
status(false),
level(INFO){};
LoggingLevel(const LoggingLevel& lvl) :
status(lvl.status),
level(lvl.level) {}
LoggingLevel(const LEVELS& lvl) :
status(true),
level(lvl){};
LoggingLevel(const LEVELS& lvl, bool enabled) :
status(enabled),
level(lvl){};
~LoggingLevel() = default;
LoggingLevel& operator=(const LoggingLevel& other) {
status = other.status;
level = other.level;
return *this;
}
bool operator==(const LoggingLevel& rhs) const {
return (status == rhs.status && level == rhs.level);
}
};
} // namespace g3
namespace g3 {
namespace internal {
const LEVELS CONTRACT{g3::kInternalFatalValue, {"CONTRACT"}},
FATAL_SIGNAL{g3::kInternalFatalValue + 1, {"FATAL_SIGNAL"}},
FATAL_EXCEPTION{kInternalFatalValue + 2, {"FATAL_EXCEPTION"}};
/// helper function to tell the logger if a log message was fatal. If it is it will force
/// a shutdown after all log entries are saved to the sinks
bool wasFatal(const LEVELS& level);
} // namespace internal
#ifdef G3_DYNAMIC_LOGGING
// Only safe if done at initialization in a single-thread context
namespace only_change_at_initialization {
/// add a custom level - enabled or disabled
void addLogLevel(LEVELS level, bool enabled);
/// add a custom level - enabled
void addLogLevel(LEVELS level);
/// reset all default logging levels to enabled
/// remove any added logging levels so that the only ones left are
/// {DEBUG,INFO,WARNING,FATAL}
void reset();
} // namespace only_change_at_initialization
namespace log_levels {
/// Enable log level >= log_level.
/// log levels below will be disabled
/// log levels equal or higher will be enabled.
void setHighest(LEVELS level);
void set(LEVELS level, bool enabled);
void disable(LEVELS level);
void enable(LEVELS level);
/// WARNING: This will also disable FATAL events from being logged
void disableAll();
void enableAll();
/// print all levels with their disabled or enabled status
std::string to_string(std::map<int, g3::LoggingLevel> levelsToPrint);
/// print snapshot of system levels with their
/// disabled or enabled status
std::string to_string();
/// Snapshot view of the current logging levels' status
std::map<int, g3::LoggingLevel> getAll();
enum class status { Absent,
Enabled,
Disabled };
status getStatus(LEVELS level);
} // namespace log_levels
#endif
/// Enabled status for the given logging level
bool logLevel(const LEVELS& level);
} // namespace g3

148
src/g3log/logmessage.hpp Normal file
View File

@ -0,0 +1,148 @@
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include "g3log/crashhandler.hpp"
#include "g3log/loglevels.hpp"
#include "g3log/moveoncopy.hpp"
#include "g3log/time.hpp"
#include <memory>
#include <sstream>
#include <string>
#include <thread>
namespace g3 {
/** LogMessage contains all the data collected from the LOG(...) call.
* If the sink receives a std::string it will be the std::string toString()... function
* that will format the data into a string
*
* For sinks that receive a LogMessage they can either use the toString() function, or use
* the helper functions or even the public raw data to format the saved log message any
* desired way.
*/
struct LogMessage {
std::string file_path() const {
return _file_path;
}
std::string file() const {
return _file;
}
std::string line() const {
return std::to_string(_line);
}
std::string function() const {
return _function;
}
std::string level() const {
return _level.text;
}
/// use a different format string to get a different look on the time.
// default look is Y/M/D H:M:S
std::string timestamp(const std::string& time_format = {internal::date_formatted + " " + internal::time_formatted}) const;
std::string message() const {
return _message;
}
std::string& write() const {
return _message;
}
std::string expression() const {
return _expression;
}
bool wasFatal() const {
return internal::wasFatal(_level);
}
std::string threadID() const;
void setExpression(std::string expression) {
_expression = std::move(expression);
}
LogMessage& operator=(LogMessage other);
LogMessage(std::string file, const int line, std::string function, const LEVELS level);
explicit LogMessage(const std::string& fatalOsSignalCrashMessage);
LogMessage(const LogMessage& other);
LogMessage(LogMessage&& other);
virtual ~LogMessage() {}
// helper log printing functions used by "toString()"
static std::string splitFileName(const std::string& str);
static std::string fatalSignalToString(const LogMessage& msg);
// windows only: fatalExceptionToString
static std::string fatalExceptionToString(const LogMessage& msg);
static std::string fatalLogToString(const LogMessage& msg);
static std::string fatalCheckToString(const LogMessage& msg);
static std::string normalToString(const LogMessage& msg);
// the default formatting option
static std::string DefaultLogDetailsToString(const LogMessage& msg);
// this function can be used by the logging sink to add thread ID
// see this concept and it is easy to make your own custom formatting
static std::string FullLogDetailsToString(const LogMessage& msg);
using LogDetailsFunc = std::string (*)(const LogMessage&);
std::string toString(LogDetailsFunc formattingFunc = DefaultLogDetailsToString) const;
void overrideLogDetailsFunc(LogDetailsFunc func) const;
//
// Complete access to the raw data in case the helper functions above
// are not enough.
//
mutable LogDetailsFunc _logDetailsToStringFunc;
g3::high_resolution_time_point _timestamp;
std::thread::id _call_thread_id;
std::string _file;
std::string _file_path;
int _line;
std::string _function;
LEVELS _level;
std::string _expression; // only with content for CHECK(...) calls
mutable std::string _message;
friend void swap(LogMessage& first, LogMessage& second) {
using std::swap;
swap(first._timestamp, second._timestamp);
swap(first._call_thread_id, second._call_thread_id);
swap(first._file, second._file);
swap(first._line, second._line);
swap(first._function, second._function);
swap(first._level, second._level);
swap(first._expression, second._expression);
swap(first._message, second._message);
}
};
/** Trigger for flushing the message queue and exiting the application
* A thread that causes a FatalMessage will sleep forever until the
* application has exited (after message flush) */
struct FatalMessage : public LogMessage {
FatalMessage(const LogMessage& details, g3::SignalType signal_id);
FatalMessage(const FatalMessage&);
FatalMessage& operator=(const FatalMessage&) = delete;
virtual ~FatalMessage() {}
LogMessage copyToLogMessage() const;
std::string reason() const;
const SignalType _signal_id;
};
typedef MoveOnCopy<std::unique_ptr<FatalMessage>> FatalMessagePtr;
typedef MoveOnCopy<std::unique_ptr<LogMessage>> LogMessagePtr;
typedef MoveOnCopy<LogMessage> LogMessageMover;
} // namespace g3

143
src/g3log/logworker.hpp Normal file
View File

@ -0,0 +1,143 @@
#pragma once
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================
* Filename:g3logworker.h Framework for Logging and Design By Contract
* Created: 2011 by Kjell Hedström
*
* PUBLIC DOMAIN and Not copyrighted. First published at KjellKod.cc
* ********************************************* */
#include <memory>
#include "g3log/filesink.hpp"
#include "g3log/g3log.hpp"
#include "g3log/logmessage.hpp"
#include "g3log/sinkhandle.hpp"
#include "g3log/sinkwrapper.hpp"
#include <memory>
#include <string>
#include <vector>
namespace g3 {
class LogWorker;
struct LogWorkerImpl;
using FileSinkHandle = g3::SinkHandle<g3::FileSink>;
/// Background side of the LogWorker. Internal use only
struct LogWorkerImpl final {
typedef std::shared_ptr<g3::internal::SinkWrapper> SinkWrapperPtr;
std::vector<SinkWrapperPtr> _sinks;
std::unique_ptr<kjellkod::Active> _bg; // do not change declaration order. _bg must be destroyed before sinks
LogWorkerImpl();
~LogWorkerImpl() = default;
void bgSave(g3::LogMessagePtr msgPtr);
void bgFatal(FatalMessagePtr msgPtr);
LogWorkerImpl(const LogWorkerImpl&) = delete;
LogWorkerImpl& operator=(const LogWorkerImpl&) = delete;
};
/// Front end of the LogWorker. API that is useful is
/// addSink( sink, default_call ) which returns a handle to the sink. See below and README for usage example
/// save( msg ) : internal use
/// fatal ( fatal_msg ) : internal use
class LogWorker final {
LogWorker() = default;
void addWrappedSink(std::shared_ptr<g3::internal::SinkWrapper> wrapper);
LogWorkerImpl _impl;
LogWorker(const LogWorker&) = delete;
LogWorker& operator=(const LogWorker&) = delete;
public:
~LogWorker();
/// Creates the LogWorker with no sinks. See example below on @ref addSink for how to use it
/// if you want to use the default file logger then see below for @ref addDefaultLogger
static std::unique_ptr<LogWorker> createLogWorker();
/**
A convenience function to add the default g3::FileSink to the log worker
@param log_prefix that you want
@param log_directory where the log is to be stored.
@return a handle for API access to the sink. See the README for example usage
@verbatim
Example:
using namespace g3;
std::unique_ptr<LogWorker> logworker {LogWorker::createLogWorker()};
auto handle = addDefaultLogger("my_test_log", "/tmp");
initializeLogging(logworker.get()); // ref. g3log.hpp
std::future<std::string> log_file_name = sinkHandle->call(&FileSink::fileName);
std::cout << "The filename is: " << log_file_name.get() << std::endl;
// something like: /tmp/my_test_log.g3log.20150819-100300.log
*/
std::unique_ptr<FileSinkHandle> addDefaultLogger(const std::string& log_prefix, const std::string& log_directory, const std::string& default_id = "g3log");
/// Adds a sink and returns the handle for access to the sink
/// @param real_sink unique_ptr ownership is passed to the log worker
/// @param call the default call that should receive either a std::string or a LogMessageMover message
/// @return handle to the sink for API access. See usage example below at @ref addDefaultLogger
template <typename T, typename DefaultLogCall>
std::unique_ptr<g3::SinkHandle<T>> addSink(std::unique_ptr<T> real_sink, DefaultLogCall call) {
using namespace g3;
using namespace g3::internal;
auto sink = std::make_shared<Sink<T>>(std::move(real_sink), call);
addWrappedSink(sink);
return std::make_unique<SinkHandle<T>>(sink);
}
/// Removes a sink. This is a synchronous call.
/// You are guaranteed that the sink is removed by the time the call returns
/// @param sink_handle the ownership of the sink handle is given
template <typename T>
void removeSink(std::unique_ptr<SinkHandle<T>> sink_handle) {
if (sink_handle) {
// sink_handle->sink().use_count() is 1 at this point
// i.e. this would be safe as long as no other weak_ptr to shared_ptr conversion
// was made by the client: assert(sink_handle->sink().use_count() == 0);
auto weak_ptr_sink = sink_handle->sink();
{
auto bg_removesink_call = [this, weak_ptr_sink] {
auto shared_sink = weak_ptr_sink.lock();
if (shared_sink) {
_impl._sinks.erase(std::remove(_impl._sinks.begin(), _impl._sinks.end(), shared_sink), _impl._sinks.end());
}
};
auto token_done = g3::spawn_task(bg_removesink_call, _impl._bg.get());
token_done.wait();
}
// sink_handle->sink().use_count() is 1 at this point.
// i.e. this would be safe: assert(sink_handle->sink().use_count() == 0);
// as long as the client has not converted more instances from the weak_ptr
}
}
/// This will clear/remove all the sinks. If a sink shared_ptr was retrieved via the sink
/// handle then the sink will be removed internally but will live on in the client's instance
void removeAllSinks() {
auto bg_clear_sink_call = [this]() noexcept {
_impl._sinks.clear();
};
auto token_cleared = g3::spawn_task(bg_clear_sink_call, _impl._bg.get());
token_cleared.wait();
}
/// internal:
/// pushes in background thread (asynchronously) input messages to log file
void save(LogMessagePtr entry);
/// internal:
// pushes a fatal message on the queue, this is the last message to be processed
/// this way it's ensured that all existing entries were flushed before 'fatal'
/// Will abort the application!
void fatal(FatalMessagePtr fatal_message);
};
} // namespace g3

51
src/g3log/moveoncopy.hpp Normal file
View File

@ -0,0 +1,51 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
namespace g3 {
// A straightforward technique to move around packaged_tasks.
// Instances of std::packaged_task are MoveConstructible and MoveAssignable, but
// not CopyConstructible or CopyAssignable. To put them in a std container they need
// to be wrapped and their internals "moved" when tried to be copied.
template <typename Moveable>
struct MoveOnCopy {
mutable Moveable _move_only;
explicit MoveOnCopy(Moveable&& m) :
_move_only(std::move(m)) {}
MoveOnCopy(MoveOnCopy const& t) :
_move_only(std::move(t._move_only)) {}
MoveOnCopy(MoveOnCopy&& t) :
_move_only(std::move(t._move_only)) {}
MoveOnCopy& operator=(MoveOnCopy const& other) {
_move_only = std::move(other._move_only);
return *this;
}
MoveOnCopy& operator=(MoveOnCopy&& other) {
_move_only = std::move(other._move_only);
return *this;
}
void operator()() {
_move_only();
}
Moveable& get() {
return _move_only;
}
Moveable release() {
return std::move(_move_only);
}
};
} // namespace g3

View File

@ -0,0 +1,78 @@
/** ==========================================================================
* 2010 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================
*
* Example of a normal std::queue protected by a mutex for operations,
* making it safe for thread communication, using std::mutex from C++0x with
* the help from the std::thread library from JustSoftwareSolutions
* ref: http://www.stdthread.co.uk/doc/headers/mutex.html
*
* This example was totally inspired by Anthony Williams lock-based data structures in
* Ref: "C++ Concurrency In Action" http://www.manning.com/williams */
#pragma once
#include <condition_variable>
#include <exception>
#include <mutex>
#include <queue>
/** Multiple producer, multiple consumer thread safe queue
* Since 'return by reference' is used this queue won't throw */
template <typename T>
class shared_queue {
std::queue<T> queue_;
mutable std::mutex m_;
std::condition_variable data_cond_;
shared_queue& operator=(const shared_queue&) = delete;
shared_queue(const shared_queue& other) = delete;
public:
shared_queue() = default;
void push(T item) {
{
std::lock_guard<std::mutex> lock(m_);
queue_.push(std::move(item));
}
data_cond_.notify_one();
}
/// \return immediately, with true if successful retrieval
bool try_and_pop(T& popped_item) {
std::lock_guard<std::mutex> lock(m_);
if (queue_.empty()) {
return false;
}
popped_item = std::move(queue_.front());
queue_.pop();
return true;
}
/// Try to retrieve, if no items, wait till an item is available and try again
void wait_and_pop(T& popped_item) {
std::unique_lock<std::mutex> lock(m_);
while (queue_.empty()) {
data_cond_.wait(lock);
// This 'while' loop is equal to
// data_cond_.wait(lock, [](bool result){return !queue_.empty();});
}
popped_item = std::move(queue_.front());
queue_.pop();
}
bool empty() const {
std::lock_guard<std::mutex> lock(m_);
return queue_.empty();
}
unsigned size() const {
std::lock_guard<std::mutex> lock(m_);
return queue_.size();
}
};

76
src/g3log/sink.hpp Normal file
View File

@ -0,0 +1,76 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include "g3log/active.hpp"
#include "g3log/future.hpp"
#include "g3log/logmessage.hpp"
#include "g3log/sinkwrapper.hpp"
#include <functional>
#include <memory>
#include <type_traits>
namespace g3 {
namespace internal {
typedef std::function<void(LogMessageMover)> AsyncMessageCall;
/// The asynchronous Sink has an active object, incoming requests for actions
// will be processed in the background by the specific object the Sink represents.
//
// The Sink will wrap either
// a Sink with Message object receiving call
// or a Sink with a LogEntry (string) receiving call
//
// The Sink can also be used through the SinkHandler to call Sink specific function calls
// Ref: send(Message) deals with incoming log entries (converted if necessary to string)
// Ref: send(Call call, Args... args) deals with calls
// to the real sink's API
template <class T>
struct Sink : public SinkWrapper {
std::unique_ptr<T> _real_sink;
std::unique_ptr<kjellkod::Active> _bg;
AsyncMessageCall _default_log_call;
template <typename DefaultLogCall>
Sink(std::unique_ptr<T> sink, DefaultLogCall call) :
SinkWrapper(),
_real_sink{std::move(sink)},
_bg(kjellkod::Active::createActive()),
_default_log_call(std::bind(call, _real_sink.get(), std::placeholders::_1)) {
}
Sink(std::unique_ptr<T> sink, void (T::*Call)(std::string)) :
SinkWrapper(),
_real_sink{std::move(sink)},
_bg(kjellkod::Active::createActive()) {
std::function<void(std::string)> adapter = std::bind(Call, _real_sink.get(), std::placeholders::_1);
_default_log_call = [=](LogMessageMover m) {
adapter(m.get().toString());
};
}
virtual ~Sink() {
_bg.reset(); // TODO: to remove
}
void send(LogMessageMover msg) override {
_bg->send([this, msg] {
_default_log_call(msg);
});
}
template <typename Call, typename... Args>
auto async(Call call, Args&&... args) -> std::future<std::invoke_result_t<decltype(call), T, Args...>> {
return g3::spawn_task(std::bind(call, _real_sink.get(), std::forward<Args>(args)...), _bg.get());
}
};
} // namespace internal
} // namespace g3

59
src/g3log/sinkhandle.hpp Normal file
View File

@ -0,0 +1,59 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include "g3log/sink.hpp"
#include <memory>
#include <type_traits>
namespace g3 {
// The Sinkhandle is the client's access point to the specific sink instance.
// Only through the Sinkhandle can, and should, the real sink's specific API
// be called.
//
// The real sink will be owned by g3log. If the real sink is deleted
// calls to sink's API through the SinkHandle will return an exception embedded
// in the resulting future. Ref: SinkHandle::call
template <class T>
class SinkHandle {
std::weak_ptr<internal::Sink<T>> _sink;
public:
SinkHandle(std::shared_ptr<internal::Sink<T>> sink) :
_sink(sink) {}
~SinkHandle() = default;
// Asynchronous call to the real sink. If the real sink is already deleted
// the returned future will contain a bad_weak_ptr exception instead of the
// call result.
template <typename AsyncCall, typename... Args>
auto call(AsyncCall func, Args&&... args) -> std::future<std::invoke_result_t<decltype(func), T, Args...>> {
try {
std::shared_ptr<internal::Sink<T>> sink(_sink);
return sink->async(func, std::forward<Args>(args)...);
} catch (const std::bad_weak_ptr& e) {
typedef std::invoke_result_t<decltype(func), T, Args...> PromiseType;
std::promise<PromiseType> promise;
promise.set_exception(std::make_exception_ptr(e));
return std::move(promise.get_future());
}
}
/// Get weak_ptr access to the sink(). Make sure to check that the returned pointer is valid,
/// auto p = sink(); auto ptr = p.lock(); if (ptr) { .... }
/// ref: https://en.cppreference.com/w/cpp/memory/weak_ptr/lock
std::weak_ptr<internal::Sink<T>> sink() {
return _sink.lock();
}
};
} // namespace g3

21
src/g3log/sinkwrapper.hpp Normal file
View File

@ -0,0 +1,21 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include "g3log/logmessage.hpp"
namespace g3 {
namespace internal {
struct SinkWrapper {
virtual ~SinkWrapper() {}
virtual void send(LogMessageMover msg) = 0;
};
} // namespace internal
} // namespace g3

View File

@ -0,0 +1,41 @@
/** ==========================================================================
* 2014 by KjellKod.cc AND Robert Engeln.
* The stacktrace code was given as a public domain dedication by Robert Engeln
* It was originally published at: http://code-freeze.blogspot.com/2012/01/generating-stack-traces-from-c.html
* It was (here) modified for g3log purposes.
*
* This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#if !(defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
#error "stacktrace_win.cpp used but not on a windows system"
#endif
#include "g3log/crashhandler.hpp"
#include <windows.h>
#include <string>
namespace stacktrace {
/// return the text description of a Windows exception code
std::string exceptionIdToText(g3::SignalType id);
/// return whether or not the exception is a known exception, i.e.
/// an exception that we should treat as a fatal event
bool isKnownException(g3::SignalType id);
/// helper function: retrieve stackdump from no excisting exception pointer
std::string stackdump();
/// helper function: retrieve stackdump, starting from an exception pointer
std::string stackdump(EXCEPTION_POINTERS* info);
/// main stackdump function. retrieve stackdump, from the given context
std::string stackdump(CONTEXT* context);
} // namespace stacktrace

View File

@ -0,0 +1,78 @@
/** ==========================================================================
* 2013 This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
*
*
* 2013/12/28 Bugfix for Visual Studio 2013 which does not handle well
* std::packaged_task<void()>. Thanks to Michael Rasmussen (lap777)
* Ref: workarounds at http://connect.microsoft.com/VisualStudio/feedback/details/791185/std-packaged-task-t-where-t-is-void-or-a-reference-class-are-not-movable
* ============================================================================*/
#pragma once
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(__MINGW32__) && (_MSC_VER <= 1800)
namespace std {
template <class... _ArgTypes>
class packaged_task<void(_ArgTypes...)> {
promise<void> _my_promise;
function<void(_ArgTypes...)> _my_func;
public:
packaged_task() {
}
template <class _Fty2>
explicit packaged_task(_Fty2&& _Fnarg) :
_my_func(_Fnarg) {
}
packaged_task(packaged_task&& _Other) :
_my_promise(move(_Other._my_promise)),
_my_func(move(_Other._my_func)) {
}
packaged_task& operator=(packaged_task&& _Other) {
_my_promise = move(_Other._my_promise);
_my_func = move(_Other._my_func);
return (*this);
}
packaged_task(const packaged_task&) = delete;
packaged_task& operator=(const packaged_task&) = delete;
~packaged_task() {
}
void swap(packaged_task& _Other) {
swap(_my_promise, _Other._my_promise);
swap(_my_func, _Other._my_func);
}
explicit operator bool() const {
return _my_func != false;
}
bool valid() const {
return _my_func != false;
}
future<void> get_future() {
return _my_promise.get_future();
}
void operator()(_ArgTypes... _Args) {
_my_func(forward<_ArgTypes>(_Args)...);
_my_promise.set_value();
}
void reset() {
_my_promise.swap(promise<void>());
_my_func.swap(function<void(_ArgTypes...)>());
}
};
}; // namespace std
#endif // defined(WIN32) ...

Some files were not shown because too many files have changed in this diff Show More