Compare commits

...

194 Commits

Author SHA1 Message Date
Ahmed Hani
4f007d9621
fix: truncate single log file upon reopening (#1143) 2025-02-20 17:49:33 +01:00
stdpain
7fcf58afa6
feat(signalhandler): add LWP ID to dump info (#1146)
LWP can help identifying the corresponding thread in a debugger more easily.
2025-02-16 15:51:26 +01:00
Rodrigo Queiro
ca390c4718
Revert "Add deprecation notice (#1150)" (#1152)
This reverts commit 575fb19092.
2025-02-04 10:05:23 +01:00
Rodrigo Queiro
575fb19092
Add deprecation notice (#1150) 2025-02-04 12:59:45 +09:00
dependabot[bot]
6c5c692c8e
build(deps): bump codecov/codecov-action from 4 to 5 (#1140)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4 to 5.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-18 18:01:35 +01:00
Takeshi Watanabe
1f0f3d6829
fix(cmake): enable symbolization on macOS (#1138) 2024-11-05 16:22:00 +01:00
Rodrigo Queiro
2075ae813b
Migrate to rules_cc (#1136)
See #1135. Not sure if this will work because the error only repros on
Windows with a specific Bazel version.
2024-10-16 10:08:53 +02:00
Sergiu Deitsch
de309c08c0
fix(clang-tidy): remove deprecated option (#1132) 2024-09-14 13:08:24 +02:00
Yun Peng
be06647ac2
fix(bazel): specify dependencies in MODULE.bazel (#1131)
With WORKSPACE disabled, all dependencies must be specified in MODULE.bazel.
2024-09-14 12:35:18 +02:00
kang jinci
b3b9eb987f
chore: add MODULE.bazel.lock to .gitignore (#1120) 2024-08-03 09:45:25 +02:00
Sergiu Deitsch
2714c2a258
Merge branch '0.7.x' 2024-08-02 21:54:14 +02:00
Sergiu Deitsch
6d92a2e5a1
bump version patch 2024-08-02 21:53:11 +02:00
Sergiu Deitsch
6703865b78
Merge branch '0.7.x' 2024-08-02 21:47:32 +02:00
Shuai Zhang
175b54d4fa
feat(bazel): enable symbolization (#1116)
Symbolization support on Linux and BSD requires link.h which is usually
provided by the GNU C Library (glibc). Assume the header to be present
at all times by unconditionally defining HAVE_SYMBOLIZE on the
corresponding platforms.
2024-08-02 20:57:43 +02:00
Shuai Zhang
65896fe00d
feat(bazel): enable symbolization (#1116)
Symbolization support on Linux and BSD requires link.h which is usually
provided by the GNU C Library (glibc). Assume the header to be present
at all times by unconditionally defining HAVE_SYMBOLIZE on the
corresponding platforms.
2024-08-02 20:38:49 +02:00
Vertexwahn
570c7e4e1d
docs: update to Bzlmod usage (#1099) 2024-07-07 13:54:19 +02:00
Sergiu Deitsch
45f99f5e1a
make operator<< overload constexpr (#1106) 2024-06-13 23:01:34 +02:00
Sergiu Deitsch
2bd06dbe36
ci(deps): update to gtest 1.14 (#1105) 2024-06-13 01:40:15 +02:00
Sergiu Deitsch
409e19881d
cmake: require gtest 1.11 (#1104) 2024-06-13 01:16:50 +02:00
Sergiu Deitsch
0c10a02229
Merge branch '0.7.x' 2024-06-13 00:01:17 +02:00
Sergiu Deitsch
9ca8073cb2
docs: use annotations 2024-06-12 23:58:10 +02:00
Sergiu Deitsch
c4b63c7a4e
docs: use footnotes 2024-06-12 23:57:35 +02:00
Sergiu Deitsch
5cf7a9afd3
docs: describe failure writer 2024-06-12 23:56:44 +02:00
Sergiu Deitsch
d49e700897
docs: move flags out of logging 2024-06-12 23:54:11 +02:00
Sergiu Deitsch
44c2e9d9ad
Merge branch '0.7.x' 2024-06-12 01:20:27 +02:00
Sergiu Deitsch
df683bbc81
docs: provide custom sinks example (#1103) 2024-06-12 01:20:04 +02:00
Sergiu Deitsch
0bad9688a0
docs(bazel): update archive url 2024-06-11 20:52:53 +02:00
Sergiu Deitsch
1cd4d78817
Merge branch '0.7.x' 2024-06-11 20:13:53 +02:00
Sergiu Deitsch
30c9ed3687
docs: update version 2024-06-11 19:57:05 +02:00
Sergiu Deitsch
645acfe606
docs: move to mkdocs-material (#1101) 2024-06-11 19:53:37 +02:00
Sergiu Deitsch
cfe648e9c5
docs: move to mkdocs-material (#1101) 2024-06-11 19:48:12 +02:00
Sergiu Deitsch
cc0de6c200
Merge branch '0.7.x' 2024-06-08 17:11:26 +02:00
Sergiu Deitsch
7b134a5c82
release 0.7.1 (#1098) 2024-06-08 17:07:34 +02:00
Vertexwahn
d76999015c
feat(bazel): port to bzlmod (#1097) 2024-06-08 16:02:59 +02:00
xppt
4c50627c38
fix(symbolize): format unknown stack frames (#1092) 2024-04-22 21:17:57 +02:00
dependabot[bot]
6e6a817a44
build(deps): bump codecov/codecov-action from 3 to 4 (#1071)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 3 to 4.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-22 21:17:57 +02:00
xppt
cd4ef77d58
fix(symbolize): format unknown stack frames (#1092) 2024-04-22 21:08:44 +02:00
dependabot[bot]
c0813f90bb
build(deps): bump codecov/codecov-action from 3 to 4 (#1071)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 3 to 4.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-22 13:40:27 +02:00
Sergiu Deitsch
442c6fcbf1
fix: rework android detection (#1094) 2024-04-22 00:48:01 +02:00
Sergiu Deitsch
2b36dfe444
fix: rework android detection (#1094) 2024-04-22 00:47:36 +02:00
Victor Zheng PhD
eecd37e7eb
fix(bazel): add missing emscripten defines (#1082) 2024-04-22 00:39:29 +02:00
Sergiu Deitsch
f73750564e
fix: error message typo 2024-04-22 00:39:29 +02:00
Ram Subhash D
46e4721fb6
fix(readme): correct LOG_IF_EVERY_N typo (#1077) 2024-04-22 00:39:29 +02:00
Sergiu Deitsch
fd15ff9a54
fix(readme): wording 2024-04-22 00:39:29 +02:00
Victor Zheng PhD
31429d85b8
fix(bazel): add missing emscripten defines (#1082) 2024-03-11 11:20:22 +01:00
Sergiu Deitsch
ea0748d8df
feat: remove deprecations (#1078) 2024-02-21 18:56:43 +01:00
Sergiu Deitsch
5a7856ab96
fix: error message typo 2024-02-19 20:08:00 +01:00
Ram Subhash D
8a1c086d39
fix(readme): correct LOG_IF_EVERY_N typo (#1077) 2024-02-19 20:07:33 +01:00
Sergiu Deitsch
a189fc3d7d
fix(readme): wording 2024-02-18 13:24:53 +01:00
Sergiu Deitsch
34b8da6496
release 0.7 (#1076) 2024-02-17 18:49:26 +01:00
Sergiu Deitsch
7a807f3805
feat: allow to obtain the stack trace as a string (#1075) 2024-02-17 18:41:40 +01:00
Sergiu Deitsch
b24e4d9445
feat: support failure functions that throw (#1074) 2024-02-17 18:41:11 +01:00
Rishik Reddy
de77d0b97b
fix(readme): eliminate typo (#1072) 2024-02-17 18:28:52 +01:00
Sergiu Deitsch
68b6ce38eb
ci(coverage): update to gcovr 7.0 (#1070) 2024-01-27 14:03:18 +01:00
dependabot[bot]
9b34110745
build(deps): bump actions/cache from 3 to 4 (#1064)
Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-22 19:30:29 +01:00
Vertexwahn
ac12a9e794
Add MODULE.bazel file (#1059)
This is the first step of the bzlmod migration: https://bazel.build/external/migration. If/when we no longer support older Bazel versions (bzlmod became GA in 6.0), we can remove WORKSPACE.
2024-01-11 10:41:55 +01:00
Sergiu Deitsch
7e6fca90e8
cmake: rework elf detection (#1058) 2024-01-10 14:06:18 +01:00
Sergiu Deitsch
8d13b3bb0c
fix: unify LogMessage and LogMessageInfo (#1057)
Deprecate the custom prefix callback accepting LogMessageInfo in favor
of existing LogMessage data structure extended with necessary data
fields to avoid redundancies.
2024-01-10 02:03:54 +01:00
Sergiu Deitsch
2293c6fc5a
fix(symbolize): use correct format specifier (#1056) 2024-01-10 00:43:02 +01:00
Sergiu Deitsch
ec455f2cc1
fix: better encapsulate internals (#1055) 2024-01-09 23:51:43 +01:00
Sergiu Deitsch
2b5a53c880
cmake: replace check_function_exists by check_cxx_symbol_exists (#1054) 2024-01-09 20:05:22 +01:00
Sergiu Deitsch
dd77d0fd38
fix: move LogMessageVoidify into internal namespace (#1053) 2024-01-09 13:46:26 +01:00
Sergiu Deitsch
941c66fbcb
cmake: bump SOVERSION (#1052) 2024-01-09 00:39:54 +01:00
Sergiu Deitsch
9377254062
feat(dbghelp): show source line number if present (#1051) 2024-01-08 19:04:22 +01:00
Sergiu Deitsch
c469cc23a1
fix: unify additional debug output (#1050) 2024-01-08 16:26:41 +01:00
Sergiu Deitsch
7af231e6bf
feat: provide fallback for accessing process name (#1049) 2024-01-08 11:18:59 +01:00
Sergiu Deitsch
aaefca72b3
fix(symbolize): cleanup (#1048) 2024-01-08 01:40:29 +01:00
Sergiu Deitsch
734ab3463f
fix(symbolize): simplify resource management (#1047) 2024-01-08 00:18:42 +01:00
Sergiu Deitsch
42a185cd88
fix: reduce manual resource management (#1046) 2024-01-07 21:12:40 +01:00
Sergiu Deitsch
1f9ac49c7d
docs: describe default prefix format (#1045) 2024-01-07 19:12:29 +01:00
Sergiu Deitsch
489d35eb13
fix: reduce boilerplate code (#1043) 2024-01-06 21:39:49 +01:00
Sergiu Deitsch
1ef1ab37e7
fix: do not export g_logging_fail_func (#1042) 2024-01-06 16:58:51 +01:00
Sergiu Deitsch
2c735b8dfb
docs: cleanup (#1041) 2024-01-06 15:04:12 +01:00
Sergiu Deitsch
25a349f7ae
feat(time): use tm::tm_gmtoff if present (#1040)
This greatly simplifies time computations.
2024-01-06 02:56:23 +01:00
Sergiu Deitsch
eb72e4c181
feat(logger): use chrono (#1039) 2024-01-05 23:07:49 +01:00
Sergiu Deitsch
f88544adf5
feat(cleanup): use chrono (#1038)
* Deprecate type-unsafe EnableLogCleaner interface
* Increase time resolution allowing to drop timing specific
  workarounds in unit tests
2024-01-05 20:38:24 +01:00
Sergiu Deitsch
89f5977468
cmake: determine when to use port.h (#1037)
Allow building using MSYS2 (without MinGW).
2024-01-05 19:57:34 +01:00
Sergiu Deitsch
fe46778bd3
fix: threads are always enabled (#1036) 2024-01-05 15:21:43 +01:00
Sergiu Deitsch
6d23649fef
fix(debug): add missing parentheses in ternary expression (#1035) 2024-01-05 14:11:44 +01:00
Sergiu Deitsch
b172be9564
fix: allow setting stderrthreshold using GLOG_stderrthreshold (#1034) 2024-01-05 01:43:22 +01:00
Sergiu Deitsch
8fbad2cb9c
feat: make IsFailureSignalHandlerInstalled public (#1033) 2024-01-05 00:13:04 +01:00
Sergiu Deitsch
8dd7abfdec
fix: remove unused declaration (#1032) 2024-01-05 00:12:43 +01:00
Sergiu Deitsch
f3bee1b15b
fix: ensure export macro to be defined (#1031) 2024-01-04 22:06:27 +01:00
Sergiu Deitsch
c8950c6b17
ci(codecov): enable comments (#966) 2024-01-04 21:54:23 +01:00
Sergiu Deitsch
8775a454c1
feat: make headers self-contained (#1030) 2024-01-04 21:03:55 +01:00
Sergiu Deitsch
dfce35c97c
fix: cleanup exports (#1029)
Reduce unnecessary utility function exports.
2024-01-04 16:57:18 +01:00
Sergiu Deitsch
e1f424a7e2
cmake: opt-in pkg-config support 2024-01-04 15:49:29 +01:00
Sergiu Deitsch
39df0545e7
docs: cleanup 2024-01-04 15:02:54 +01:00
Sergiu Deitsch
cafba580ec
feat: use standard atomics and call_once (#1026) 2024-01-04 01:18:36 +01:00
Sergiu Deitsch
54b2c17172
fix: make log severity type safe (#1025) 2024-01-04 00:35:40 +01:00
Sergiu Deitsch
51e7a439dc
feat(demangle): use cxx abi demangler (#1023) 2024-01-03 19:24:35 +01:00
Sergiu Deitsch
bdd14b6ab1
fix(demangle): place symbols in anonymous namespace (#1022) 2024-01-03 16:49:43 +01:00
Sergiu Deitsch
70285fddc7
feat: use chrono (#1020) 2024-01-03 16:00:24 +01:00
Sergiu Deitsch
4244cec140
cmake: remove unused check (#1021) 2024-01-03 15:45:03 +01:00
Sergiu Deitsch
0032896711
feat: use standard threads (#1019) 2024-01-03 02:24:52 +01:00
Sergiu Deitsch
645d0a5d5f
fix(demangle): support decltype(nullptr) and pack expansion (#1018) 2024-01-02 22:31:00 +01:00
Sergiu Deitsch
45d7978daf
fix(tests): prevent clang from optimizing new away (#1017) 2024-01-02 13:01:42 +01:00
Sergiu Deitsch
b1bc8e75cb
feat: reduce manual deallocations (#1016) 2024-01-02 02:17:23 +01:00
Sergiu Deitsch
8ff1a7db04
feat: use standard mutexes (#1015) 2024-01-02 00:47:22 +01:00
Sergiu Deitsch
ac8f8dae2c
fix: remove unused test code (#1014) 2024-01-02 00:47:02 +01:00
Sergiu Deitsch
d29d02e8af
fix: add missing gmtime_r check (#1013)
909069ea82 introduced optional gmtime_r
support but did implement the function's availability check.
2023-12-30 22:07:29 +01:00
Sergiu Deitsch
93549f3600 chore: apply clang-format 2023-12-30 20:38:56 +01:00
Sergiu Deitsch
e3f5398aa1
rework public header structure (#1012)
Promote generated headers to regular headers. This enables direct
editing of corresponding files and running automatic source code
formatting and static analysis tools, such as clang-format and
clang-tidy on the whole project which previously was not
straightforward.
2023-12-30 19:05:26 +01:00
Sergiu Deitsch
80d7fa3863 ci: use emcmake 2023-12-30 13:06:54 +01:00
Sergiu Deitsch
aeee0ef452 fix(symbolize): use correct size_t format specifier
While compiling under Emscripten with _LP64 being 0, Clang complains
that the format specifier does not match the actual type (even though
size_t and unsigned are probably compatible.)
2023-12-30 02:14:49 +01:00
Sergiu Deitsch
546906f467 fix: remove unused include 2023-12-30 01:01:40 +01:00
Sergiu Deitsch
43792b8a13 rework (lib)unwind integration
Allow to switch between the two backends.
2023-12-30 00:50:52 +01:00
Sergiu Deitsch
3c052d90f8 fix: remove executable bit 2023-12-29 17:54:32 +01:00
Sergiu Deitsch
ab2a1a8519
fix: enable strip log tests (#1009) 2023-12-28 02:34:06 +01:00
Sergiu Deitsch
e92ab7df52
cmake: remove pre C++11 warning options (#1005) 2023-12-21 23:07:58 +01:00
Sergiu Deitsch
e26e342623
cmake: use glog specific project variables (#1004) 2023-12-21 23:07:36 +01:00
Sergiu Deitsch
dfb7703542
cmake: simplify symbol availability checks (#1003) 2023-12-21 22:25:04 +01:00
Sergiu Deitsch
b7686b6995
cmake: remove obsolete check (#1002) 2023-12-21 22:01:35 +01:00
Sergiu Deitsch
72b8a7956f
cmake: do not enable TLS without threads (#1001) 2023-12-21 20:59:30 +01:00
Sergiu Deitsch
65cc31ab16
cmake: use threads import target (#1000) 2023-12-21 20:40:43 +01:00
Sergiu Deitsch
d937c2e1b8
fix: shell quote user-provided mailer path (#999) 2023-12-21 19:54:07 +01:00
Acey
716be9edc7
feat: add missing debug logging macros (#986) 2023-12-21 19:45:06 +01:00
Mike Frysinger
6607b369d0
symbolize_unittest: make it a bit more portable (#985) 2023-12-20 21:10:26 +01:00
Sergiu Deitsch
3fcf77a691
fix: drop custom (v)snprintf definition (#992)
The functions are available since C++11.
2023-12-20 20:49:08 +01:00
Sergiu Deitsch
3731c120c0
fix: replace NULL by nullptr (#993) 2023-12-20 20:48:43 +01:00
Sergiu Deitsch
a9eecd7f9a
fix: log last error code instead of a BOOL (#994) 2023-12-20 20:47:57 +01:00
Sergiu Deitsch
7d973f9b4e
cmake: replace check_library_exists by check_cxx_symbol_exists (#991)
As per https://gitlab.kitware.com/cmake/cmake/-/issues/18121,
check_library_exists cannot not determine the availability of a symbol
in a static library. Switch to check_cxx_symbol_exists to avoid
incorrectly detecting the presence of dbghelp.
2023-12-20 18:47:10 +01:00
dependabot[bot]
36ccb159f4
build(deps): bump actions/upload-artifact from 3 to 4 (#987)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 21:17:14 +01:00
dependabot[bot]
58ac48fe20
build(deps): bump github/codeql-action from 2 to 3 (#988)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 20:02:32 +01:00
Sergiu Deitsch
b6082e5088
fix: remove redundant POSIX function aliases (#990)
The preprocessor defines interfere with method declarations, e.g., in
std::basic_filebuf, resulting in following error:

C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.37.32822\include\fstream(376,26): error C2039: '_close': is not a member of 'std::basic_filebuf<char,std::char_traits<char>>' [D:\a\glog\glog\build_Debug\logging_unittest.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.37.32822\include\iosfwd(244,35): message : see declaration of 'std::basic_filebuf<char,std::char_traits<char>>' [D:\a\glog\glog\build_Debug\logging_unittest.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.37.32822\include\fstream(375,10): message : while compiling class template member function 'void std::basic_ofstream<char,std::char_traits<char>>::_close(void)' [D:\a\glog\glog\build_Debug\logging_unittest.vcxproj]
D:\a\glog\glog\src\logging_unittest.cc(788,12): message : see the first reference to 'std::basic_ofstream<char,std::char_traits<char>>::_close' in 'TestBasenameAppendWhenNoTimestamp' [D:\a\glog\glog\build_Debug\logging_unittest.vcxproj]
D:\a\glog\glog\src\logging_unittest.cc(786,12): message : see reference to class template instantiation 'std::basic_ofstream<char,std::char_traits<char>>' being compiled [D:\a\glog\glog\build_Debug\logging_unittest.vcxproj]
2023-12-19 19:08:48 +01:00
Sergiu Deitsch
931323df21
fix: add missing thread_local specifier 2023-10-15 19:10:31 +02:00
Sergiu Deitsch
b45f5b4c82
fix(build): raise minimum cmake version to 3.21 (#974)
Linking against target objects is otherwise not possible.
2023-10-12 22:28:45 +02:00
LingBin
da9753409b
fix(cleanup): ensure FLAGS_log_dir ends with '/' (#972) 2023-10-12 13:35:52 +02:00
Sergiu Deitsch
b58718f37c
fix(cmake): rework ucontext_t introspection (#954) 2023-10-09 21:35:51 +02:00
Sergiu Deitsch
aebdfd6051
fix: eliminate msvc warning 2023-10-08 19:04:29 +02:00
dependabot[bot]
e19e598302
build(deps): bump actions/checkout from 3 to 4 (#970)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-08 18:58:07 +02:00
Sergiu Deitsch
fe476db256 ci: add dependabot github action 2023-10-08 18:23:31 +02:00
Sergiu Deitsch
b8a251c091 fix(cmake): support xcode generator 2023-10-08 17:33:53 +02:00
Huy Q. Bui
4dbc26af72
feat: support log file truncation on windows (#960) 2023-10-08 14:03:10 +02:00
Sergiu Deitsch
615966eb6d
fix: prefer includes in same directory (#969)
Use quoted form instead of angle-bracket form for includes to avoid
conflicts between multiple versions of the library.
2023-10-07 20:15:29 +02:00
Sergiu Deitsch
6a7be64131
fix: remove stray spaces (#967) 2023-10-07 18:58:01 +02:00
Sergiu Deitsch
9a5e72136b
ci: drop code scanning category (#968) 2023-10-07 18:50:25 +02:00
Sergiu Deitsch
5d4fa3d774
feat: use code scanning 2023-10-07 17:08:40 +02:00
Sergiu Deitsch
4a75a9df7c
fix: eliminate type conversion warnings 2023-10-07 16:14:21 +02:00
Deev Patel
e17f932eec
fix: annotate static variable in VLOG_IS_ON (#890)
Avoid TSAN issues when multiple threads perform the check.
2023-10-07 15:35:52 +02:00
Sergiu Deitsch
f6e4d960e9
ci: replace lcov by gcovr (#965) 2023-10-07 02:29:58 +02:00
Sergiu Deitsch
1dffb4eb29
fix: enable building without threads (#964) 2023-10-06 22:30:31 +02:00
Sergiu Deitsch
747b8a0774
fix(demangle): limit ParseTemplateArg recursion depth (#963) 2023-10-06 21:32:05 +02:00
Sergiu Deitsch
857df01007
fix(demangle): limit recursion depth (#958) 2023-10-06 02:03:43 +02:00
Sergiu Deitsch
319a0dfba4
fix: stack buffer overflow (#957) 2023-10-06 01:47:56 +02:00
Sergiu Deitsch
e567cfc442
fix: address sanitizer failures (#956) 2023-10-06 00:34:38 +02:00
Sergiu Deitsch
7ba2f7bc02
fix(demangle): prevent signed integer overflow (#955) 2023-10-05 23:33:23 +02:00
Sergiu Deitsch
27bf2b2fd3
ci: update to ndk r26 2023-10-05 21:58:43 +02:00
Sergiu Deitsch
fab3b5eac4
ci: support C++23 2023-10-05 21:41:33 +02:00
Sergiu Deitsch
b90799c277
ci: drop setup-ninja action 2023-10-05 20:27:31 +02:00
Sergiu Deitsch
3411d58669 cmake: eliminate deprecation warning 2023-10-05 00:49:39 +02:00
Philipp Wollermann
64827572c0
SendEmail: Protect users against vulnerable logmailers (#939)
glog is used on a variety of systems, and we must assume that some of
them still use vulnerable mailers that have bugs or "interesting
features" such as https://nvd.nist.gov/vuln/detail/CVE-2004-2771.

Let's protect users against accidental shell injection by validating
the email addresses against a slightly stricter version of the regex
used by HTML5 to validate addresses[1].

This should prevent triggering any unexpected behavior in these tools.

Also add some basic unit tests for the SendEmail method.

[1] https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
2023-09-07 17:31:25 +02:00
Praveen Ravichandran
6fbc93a7e4
fix(readme): typo in conan install step (#946) 2023-09-06 08:58:09 +02:00
Rodrigo Queiro
3a0d4d22c5
Warn about dragons in the Bazel include path (#927)
https://github.com/google/glog/issues/837 has caused a couple of
disappointments for PR authors, so I'm hoping this comment can save them
some time, or even help them towards finding a complete solution for the
problem.
2023-06-05 11:08:12 +02:00
Eric Kilmer
22491eb123
logging: Prevent LogStream constructor from being discarded (#925)
Fixes linker error reported in #922
2023-05-25 21:26:33 +02:00
Vertexwahn
4945347d07 Fix spelling mistakes 2023-05-25 20:51:51 +02:00
Mai Hussien
888f93947b Move commandlineflags.h to shared_headers 2023-05-15 16:31:45 +02:00
Mai Hussien
4ffdf0dc78 Move shared headers to a private filegroup 2023-05-15 16:31:45 +02:00
Mai Hussien
7a62819e43 Fix targets for layering_check 2023-05-15 16:31:45 +02:00
Brad Smith
aca9a23c83
fixed OpenBSD support (#921)
- Usage of syscall() is not allowed
- Use getthrid() to retreive the thread ID
2023-05-10 13:41:38 +02:00
Sergiu Deitsch
6742834201
move to C++14 (#902) 2023-02-28 12:26:49 +01:00
Peng Xiao
35f4efbb0a bazel: Add HAVE_EXECINFO_H copts to fix empty stack trace 2023-02-28 12:10:03 +01:00
Catena cyber
9c3d6d0e71
ci: include CIFuzz GitHub workflow (#903) 2023-02-27 11:23:27 +01:00
Uilian Ries
a13d03babc
add conan usage to README (#862)
Signed-off-by: Uilian Ries <uilianries@gmail.com>
2023-02-24 22:55:35 +01:00
Catena cyber
846c3fe55b
Add fuzz testing for demangle (#878) 2023-02-24 22:45:32 +01:00
Sergiu Deitsch
1b59cb0905
drop custom prefix option (#898) 2023-02-24 20:40:09 +01:00
Sergiu Deitsch
af8344bbbe
cmake: rename glogbase to glog_internal (#901) 2023-02-24 20:39:46 +01:00
Sergiu Deitsch
88e2cd4eef
avoid anonymous struct typedefs (#900) 2023-02-24 20:15:03 +01:00
Sergiu Deitsch
4ffb2f3c40
drop lgtm badges (#899) 2023-02-24 20:13:38 +01:00
Sergiu Deitsch
4056374800
fixed emscripten detection (#897) 2023-02-24 19:25:26 +01:00
Sergiu Deitsch
f545ff5e7d
ci: update actions (#886) 2023-01-01 18:30:33 +01:00
Sergiu Deitsch
2115d9b590
ci: run linux workflow on ubuntu 22.04 (#885) 2023-01-01 18:08:53 +01:00
James Sharpe
c18db3903b Fix Windows clang CI for CC toolchain resolution
Select the correct toolchain and platform for
building with clang on windows with CC toolchain
resolution active.
2022-11-30 10:37:01 +01:00
Ivo List
05fbc65278 Disable cc toolchain resolution when using Clang on Windows
Different compilers on Window are not yet supported with CC toolchain resolution.
2022-09-21 17:00:02 +02:00
Rodrigo Queiro
9ad08ac6cc Remove symbolize Bazel test
It is broken on Windows CI (#859) in a way that I don't understand.
2022-09-15 16:42:46 +02:00
Sergiu Deitsch
b70ea80433
Revert "simplify DLOG macro definition in NDEBUG mode (#830)" (#855)
This reverts commit 278ed96891.
2022-08-18 16:14:23 +02:00
Marek Cirkos
bfee415a1d
bazel: fix broken stacktrace (#851)
Since #846, `HAVE_UNWIND_H`  is not really in use. Instead we should use `HAVE__UNWIND_BACKTRACE` and `HAVE__UNWIND_GETIP` (added in #846). To prevent that from happening again, also added Bazel tests that confirm stacktrace are still working.
2022-08-16 18:48:59 +02:00
Andrei Polushin
acc60d0c38
logsink: fix multiple issues with LogSink::ToString() (#852)
1. Initializing std::ostringstream with a string makes no sense, as the
   string becomes an initial value of an underlying buffer; seek-to-end
   is not performed, so the initial value gets completely overwritten by
   subsequent writing.

2. Flag `log_year_in_prefix` should be considered, as if formatting a
   regular logging message.

3. Writing a buffer to std::ostream is better expressed with write(s,n).
2022-08-13 12:21:25 +02:00
Andrei Polushin
6d5b384507
SetLogger should delete previously set custom logger. (#853)
As specified in the doc comment for SetLogger, "the logger becomes the
property of the logging module and should not be deleted by the caller".

Not only should the LogDestination delete a custom logger in its
destructor, but it should also delete a previous logger when another
logger is passed to SetLogger().

Co-authored-by: Sergiu Deitsch <sergiud@users.noreply.github.com>
2022-08-13 12:20:33 +02:00
Andrei Polushin
1fb4cc1958
log_file_header: add option to disable log file headers. (#850)
Log lines can be customized for parsing by an external tool.

To simplify such customization and parsing, there should be an option to
customize the file header, or at least to disable adding it.
2022-08-13 11:10:00 +02:00
Andrei Polushin
a1b6164ef1
windows: call to FormatMessage() should _IGNORE_INSERTS (#849)
Calling FormatMessage without a FORMAT_MESSAGE_IGNORE_INSERTS flag could
cause trouble, as explained in an article by Raymond Chen:

* The importance of the FORMAT_MESSAGE_IGNORE_INSERTS flag
  https://devblogs.microsoft.com/oldnewthing/20071128-00/?p=24353
2022-08-12 15:18:55 +02:00
rain
278ed96891
simplify DLOG macro definition in NDEBUG mode (#830)
Co-authored-by: joliph <joliphzjf@gmail.com>
Co-authored-by: Sergiu Deitsch <sergiud@users.noreply.github.com>
2022-08-06 20:33:23 +02:00
Sergiu Deitsch
6ed0c9e58b
added emscripten support (#846) 2022-08-04 22:52:47 +02:00
Sergiu Deitsch
a34226ca94
support ndk r25 (#844) 2022-08-01 10:46:35 +02:00
Joey Parrish
c515e1ae2f
remove unused STDC_HEADERS definition (#835) 2022-07-02 01:03:18 +02:00
Yun Peng
79d692c645 Strip only the first leading @
This change is needed for glog to work with future version of Bazel when
canonical label literals is used in Bzlmod.

Context: https://docs.google.com/document/d/1N81qfCa8oskCk5LqTW-LNthy6EBrDot7bdUsjz6JFC4/edit#heading=h.5mcn15i0e1ch
2022-06-15 18:05:23 +02:00
Xiangquan Xiao
086ce224d2 bazel: Use glog 0.6.0 in README. 2022-06-13 12:53:24 +02:00
Sergiu Deitsch
b33e3bad4c
Merge pull request #812 from google/release-0.6
release 0.6
2022-04-05 00:03:27 +02:00
Sergiu Deitsch
54b8bcbbf1 release 0.6 2022-04-02 20:33:57 +02:00
Sergiu Deitsch
864ef64920
Merge pull request #801 from skeptic-monkey/master
Fix namespace resolution issue in LOG_EVERY_T
2022-03-16 15:51:09 +01:00
Luc Bertrand
c640c2f7c1 Fix namespace resolution issue in LOG_EVERY_T 2022-03-16 15:27:38 +01:00
Rodrigo Queiro
5addeedc0a Fix "'GLOG_EXPORT' macro redefined" on clang-cl
The previous approach used
--incompatible_enable_cc_toolchain_resolution, which is recommended by
the docs, but a Bazel developer told me it's obsolete. The new, old
approach is simpler and should stop the warning from being user-visible.
2022-03-08 13:39:50 +01:00
Rodrigo Queiro
d153e294b8 Avoid "GLOG_EXPORT macro redefined" in clang-cl CI
I would prefer to fix this in glog.bzl but couldn't get that to work.
2022-03-04 11:12:21 +01:00
Rodrigo Queiro
c4ca519a86 Add CI job for clang-cl on Windows
This should catch issues like #801. This uses the new `tasks` syntax to
define multiple Windows tasks:

https://github.com/bazelbuild/continuous-integration/blob/master/buildkite/README.md#basic-syntax
2022-03-04 11:12:21 +01:00
115 changed files with 9405 additions and 10515 deletions

View File

@ -1,6 +1,8 @@
--- ---
platforms: tasks:
ubuntu1804: ubuntu1804:
name: "Ubuntu 22.04"
platform: ubuntu2204
build_flags: build_flags:
- "--features=layering_check" - "--features=layering_check"
- "--copt=-Werror" - "--copt=-Werror"
@ -12,6 +14,8 @@ platforms:
test_targets: test_targets:
- "//..." - "//..."
macos: macos:
name: "macOS: latest Xcode"
platform: macos
build_flags: build_flags:
- "--features=layering_check" - "--features=layering_check"
- "--copt=-Werror" - "--copt=-Werror"
@ -22,8 +26,9 @@ platforms:
- "--copt=-Werror" - "--copt=-Werror"
test_targets: test_targets:
- "//..." - "//..."
windows: windows-msvc:
# Optional: use VS 2017 instead of 2015. name: "Windows: MSVC 2017"
platform: windows
environment: environment:
BAZEL_VC: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools\\VC" BAZEL_VC: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools\\VC"
build_flags: build_flags:
@ -36,3 +41,22 @@ platforms:
- "--copt=/WX" - "--copt=/WX"
test_targets: test_targets:
- "//..." - "//..."
windows-clang-cl:
name: "Windows: Clang"
platform: windows
environment:
BAZEL_VC: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools\\VC"
build_flags:
- "--extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows-clang-cl"
- "--extra_execution_platforms=//:x64_windows-clang-cl"
- "--compiler=clang-cl"
- "--features=layering_check"
build_targets:
- "//..."
test_flags:
- "--extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows-clang-cl"
- "--extra_execution_platforms=//:x64_windows-clang-cl"
- "--compiler=clang-cl"
- "--features=layering_check"
test_targets:
- "//..."

View File

@ -58,7 +58,7 @@ ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4 ContinuationIndentWidth: 4
Cpp11BracedListStyle: true Cpp11BracedListStyle: true
DeriveLineEnding: true DeriveLineEnding: true
DerivePointerAlignment: true DerivePointerAlignment: false
DisableFormat: false DisableFormat: false
ExperimentalAutoDetectBinPacking: false ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true FixNamespaceComments: true
@ -84,7 +84,7 @@ IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: '' IncludeIsMainSourceRegex: ''
IndentCaseLabels: true IndentCaseLabels: true
IndentGotoLabels: true IndentGotoLabels: true
IndentPPDirectives: None IndentPPDirectives: AfterHash
IndentWidth: 2 IndentWidth: 2
IndentWrappedFunctionNames: false IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave JavaScriptQuotes: Leave
@ -157,7 +157,7 @@ SpacesInCStyleCastParentheses: false
SpacesInParentheses: false SpacesInParentheses: false
SpacesInSquareBrackets: false SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false SpaceBeforeSquareBrackets: false
Standard: Auto Standard: c++14
StatementMacros: StatementMacros:
- Q_UNUSED - Q_UNUSED
- QT_REQUIRE_VERSION - QT_REQUIRE_VERSION

View File

@ -1,8 +1,7 @@
--- ---
Checks: 'clang-diagnostic-*,clang-analyzer-*,google-*' Checks: 'clang-diagnostic-*,clang-analyzer-*,google-*,modernize-*,-modernize-use-trailing-return-type,readability-*,portability-*,performance-*,bugprone-*,android-*,darwin-*,clang-analyzer-*'
WarningsAsErrors: '' WarningsAsErrors: ''
HeaderFilterRegex: '' HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
FormatStyle: file FormatStyle: file
CheckOptions: CheckOptions:
- key: cert-dcl16-c.NewSuffixes - key: cert-dcl16-c.NewSuffixes

10
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,10 @@
# Set update schedule for GitHub Actions
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every week
interval: "weekly"

View File

@ -5,43 +5,58 @@ on: [push, pull_request]
jobs: jobs:
build-android: build-android:
name: NDK-C++${{matrix.std}}-${{matrix.abi}}-${{matrix.build_type}} name: NDK-C++${{matrix.std}}-${{matrix.abi}}-${{matrix.build_type}}
runs-on: ubuntu-latest runs-on: ubuntu-22.04
permissions:
actions: read
contents: read
security-events: write
defaults: defaults:
run: run:
shell: bash shell: bash
env:
NDK_VERSION: 26.0.10792818
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
std: [98, 11, 14, 17, 20] std: [14, 17, 20]
abi: [arm64-v8a, armeabi-v7a, x86_64, x86] abi: [arm64-v8a, armeabi-v7a, x86_64, x86]
build_type: [Debug, Release] build_type: [Debug, Release]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Setup Ninja - name: Initialize CodeQL
uses: ashutoshvarma/setup-ninja@master uses: github/codeql-action/init@v3
with: with:
version: 1.10.0 languages: cpp
- name: Setup C++98 Environment - name: Setup Dependencies
if: matrix.std == '98'
run: | run: |
echo 'CXXFLAGS=-Wno-error=variadic-macros -Wno-error=long-long ${{env.CXXFLAGS}}' >> $GITHUB_ENV sudo apt-get update
DEBIAN_FRONTEND=noninteractive sudo apt-get install -y \
cmake \
ninja-build
- name: Setup NDK
env:
ANDROID_SDK_ROOT: /usr/local/lib/android/sdk
run: |
echo 'y' | ${{env.ANDROID_SDK_ROOT}}/cmdline-tools/latest/bin/sdkmanager --install 'ndk;${{env.NDK_VERSION}}'
- name: Configure - name: Configure
env: env:
CXXFLAGS: -Wall -Wextra -Wpedantic -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror ${{env.CXXFLAGS}} CXXFLAGS: -Wall -Wextra -Wpedantic -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror ${{env.CXXFLAGS}}
run: | run: |
cmake -S . -B build_${{matrix.abi}} \ cmake -S . -B build_${{matrix.abi}} \
-DANDROID_ABI=${{matrix.abi}} \ -DCMAKE_ANDROID_API=28 \
-DANDROID_NATIVE_API_LEVEL=28 \ -DCMAKE_ANDROID_ARCH_ABI=${{matrix.abi}} \
-DANDROID_STL=c++_shared \ -DCMAKE_ANDROID_NDK=/usr/local/lib/android/sdk/ndk/${{env.NDK_VERSION}} \
-DCMAKE_ANDROID_STL_TYPE=c++_shared \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \ -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DCMAKE_CXX_EXTENSIONS=OFF \ -DCMAKE_CXX_EXTENSIONS=OFF \
-DCMAKE_CXX_STANDARD=${{matrix.std}} \ -DCMAKE_CXX_STANDARD=${{matrix.std}} \
-DCMAKE_CXX_STANDARD_REQUIRED=ON \ -DCMAKE_CXX_STANDARD_REQUIRED=ON \
-DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake \ -DCMAKE_SYSTEM_NAME=Android \
-G Ninja \ -G Ninja \
-Werror -Werror
@ -49,3 +64,6 @@ jobs:
run: | run: |
cmake --build build_${{matrix.abi}} \ cmake --build build_${{matrix.abi}} \
--config ${{matrix.build_type}} --config ${{matrix.build_type}}
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

26
.github/workflows/cifuzz.yml vendored Normal file
View File

@ -0,0 +1,26 @@
name: CIFuzz
on: [pull_request]
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'glog'
dry-run: false
language: c++
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'glog'
fuzz-seconds: 60
dry-run: false
language: c++
- name: Upload Crash
uses: actions/upload-artifact@v4
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts

57
.github/workflows/emscripten.yml vendored Normal file
View File

@ -0,0 +1,57 @@
name: Emscripten
on: [push, pull_request]
jobs:
build-linux:
defaults:
run:
shell: bash
name: Emscripten-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}
runs-on: ubuntu-22.04
permissions:
actions: read
contents: read
security-events: write
container: emscripten/emsdk
strategy:
fail-fast: true
matrix:
build_type: [Release, Debug]
lib: [static]
std: [14, 17, 20, 23]
steps:
- uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: cpp
- name: Setup Dependencies
run: |
sudo apt-get update
DEBIAN_FRONTEND=noninteractive sudo apt-get install -y \
cmake \
ninja-build
- name: Configure
env:
CXXFLAGS: -Wall -Wextra -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror -Wno-error=wasm-exception-spec ${{env.CXXFLAGS}}
run: |
emcmake cmake -S . -B build_${{matrix.build_type}} \
-DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
-DCMAKE_CXX_STANDARD_REQUIRED=ON \
-DCMAKE_INSTALL_PREFIX=${{github.workspace}}/install \
-G Ninja \
-Werror
- name: Build
run: |
cmake --build build_${{matrix.build_type}} \
--config ${{matrix.build_type}}
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

View File

@ -7,63 +7,44 @@ jobs:
defaults: defaults:
run: run:
shell: bash shell: bash
name: GCC-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.extra}} name: GCC-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}
runs-on: ubuntu-latest runs-on: ubuntu-22.04
permissions:
actions: read
contents: read
security-events: write
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
build_type: [Release, Debug] build_type: [Release, Debug]
extra: [no-custom-prefix, custom-prefix]
lib: [shared, static] lib: [shared, static]
std: [98, 11, 14, 17, 20] std: [14, 17, 20, 23]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: cpp
- name: Setup Dependencies - name: Setup Dependencies
run: | run: |
sudo apt-get update sudo apt-get update
DEBIAN_FRONTEND=noninteractive sudo apt-get install -y \ DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --no-install-suggests --no-install-recommends \
build-essential \ g++ \
cmake \ cmake \
lcov \ gcovr \
libgflags-dev \ libgflags-dev \
libgmock-dev \
libgtest-dev \
libunwind-dev \ libunwind-dev \
ninja-build ninja-build
- name: Cache GTest
id: cache-gtest
uses: actions/cache@v2
with:
path: gtest/
key: ${{runner.os}}-gtest-1.11
- name: Download GTest
if: steps.cache-gtest.outputs.cache-hit != 'true'
run: |
wget https://github.com/google/googletest/archive/refs/tags/release-1.11.0.tar.gz
tar xvf release-1.11.0.tar.gz
- name: Build GTest
if: steps.cache-gtest.outputs.cache-hit != 'true'
run: |
cmake -S googletest-release-1.11.0 -B build-googletest \
-DBUILD_SHARED_LIBS=${{matrix.shared}} \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DCMAKE_INSTALL_PREFIX=${{github.workspace}}/gtest \
-G Ninja
cmake --build build-googletest --target install
- name: Setup Environment - name: Setup Environment
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
run: | run: |
echo 'CXXFLAGS=--coverage' >> $GITHUB_ENV echo 'CXXFLAGS=--coverage' >> $GITHUB_ENV
echo 'GTest_ROOT=${{github.workspace}}/gtest' >> $GITHUB_ENV
- name: Setup C++98 Environment
if: matrix.std == '98'
run: |
echo 'CXXFLAGS=-Wno-error=variadic-macros -Wno-error=long-long ${{env.CXXFLAGS}}' >> $GITHUB_ENV
- name: Configure - name: Configure
env: env:
@ -74,7 +55,6 @@ jobs:
-DCMAKE_CXX_STANDARD=${{matrix.std}} \ -DCMAKE_CXX_STANDARD=${{matrix.std}} \
-DCMAKE_CXX_STANDARD_REQUIRED=ON \ -DCMAKE_CXX_STANDARD_REQUIRED=ON \
-DCMAKE_INSTALL_PREFIX=${{github.workspace}}/install \ -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/install \
-DWITH_CUSTOM_PREFIX=${{matrix.extra == 'custom-prefix'}} \
-G Ninja \ -G Ninja \
-Werror -Werror
@ -124,27 +104,17 @@ jobs:
- name: Generate Coverage - name: Generate Coverage
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
run: | run: |
lcov --directory . --capture --output-file coverage.info cd build_${{matrix.build_type}}
lcov --remove coverage.info \ gcovr -r .. . -s --xml coverage.xml
'${{github.workspace}}/gtest/*' \
'*/src/*_unittest.cc' \
'*/src/googletest.h' \
'*/src/mock-log.h' \
'/usr/*' \
--output-file coverage.info
for file in src/glog/*.h.in; do
name=$(basename ${file})
name_we=${name%.h.in}
sed -i "s|build_${{matrix.build_type}}/glog/${name_we}.h\$|${file}|g" coverage.info
done
lcov --list coverage.info
- name: Upload Coverage to Codecov - name: Upload Coverage to Codecov
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
uses: codecov/codecov-action@v2 uses: codecov/codecov-action@v5
with: with:
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
files: build_${{matrix.build_type}}/coverage.xml
fail_ci_if_error: true fail_ci_if_error: true
verbose: true verbose: true
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

View File

@ -5,41 +5,44 @@ on: [push, pull_request]
jobs: jobs:
build-macos: build-macos:
name: AppleClang-C++${{matrix.std}}-${{matrix.build_type}} name: AppleClang-C++${{matrix.std}}-${{matrix.build_type}}
runs-on: macos-10.15 runs-on: macos-12
permissions:
actions: read
contents: read
security-events: write
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
std: [98, 11, 14, 17, 20] std: [14, 17, 20, 23]
include: include:
- generator: Ninja - generator: Xcode
- build_type: Debug - build_type: Debug
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Setup Ninja
uses: ashutoshvarma/setup-ninja@master
with:
version: 1.10.0
- name: Setup Dependencies - name: Setup Dependencies
run: | run: |
brew install lcov brew install ninja
- name: Setup Coverage Dependencies
if: matrix.build_type == 'Debug'
run: |
brew install gcovr
- name: Setup Environment - name: Setup Environment
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
run: | run: |
echo 'CXXFLAGS=--coverage' >> $GITHUB_ENV echo 'CXXFLAGS=--coverage' >> $GITHUB_ENV
echo 'LDFLAGS=--coverage' >> $GITHUB_ENV
- name: Configure - name: Configure
shell: bash shell: bash
env: env:
CXXFLAGS: -Wall -Wextra -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror ${{env.CXXFLAGS}} CXXFLAGS: -Wall -Wextra -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror -pedantic-errors ${{env.CXXFLAGS}}
run: | run: |
cmake -S . -B build_${{matrix.build_type}} \ cmake -S . -B build_${{matrix.build_type}} \
-DCMAKE_CXX_EXTENSIONS=OFF \ -DCMAKE_CXX_EXTENSIONS=OFF \
-DCMAKE_CXX_FLAGS_DEBUG=-pedantic-errors \
-DCMAKE_CXX_FLAGS_RELEASE=-pedantic-errors \
-DCMAKE_CXX_STANDARD=${{matrix.std}} \ -DCMAKE_CXX_STANDARD=${{matrix.std}} \
-DCMAKE_CXX_STANDARD_REQUIRED=ON \ -DCMAKE_CXX_STANDARD_REQUIRED=ON \
-G "${{matrix.generator}}" \ -G "${{matrix.generator}}" \
@ -53,31 +56,21 @@ jobs:
- name: Test - name: Test
run: | run: |
ctest --test-dir build_${{matrix.build_type}} \ ctest --test-dir build_${{matrix.build_type}} \
--build-config ${{matrix.build_type}} \
--output-on-failure --output-on-failure
- name: Generate Coverage - name: Generate Coverage
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
run: | run: |
lcov --directory . --capture --output-file coverage.info cd build_${{matrix.build_type}}
lcov --remove coverage.info \ rm -r Tests/
'*/src/*_unittest.cc' \ gcovr -r .. . -s --cobertura coverage.xml
'*/src/googletest.h' \
'*/src/mock-log.h' \
'*/usr/*' \
--output-file coverage.info
for file in src/glog/*.h.in; do
name=$(basename ${file})
name_we=${name%.h.in}
sed -i "" "s|${{github.workspace}}/glog/${name_we}.h\$|${file}|g" coverage.info
done
lcov --list coverage.info
- name: Upload Coverage to Codecov - name: Upload Coverage to Codecov
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
uses: codecov/codecov-action@v2 uses: codecov/codecov-action@v5
with: with:
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
files: build_${{matrix.build_type}}/coverage.xml
fail_ci_if_error: true fail_ci_if_error: true
verbose: true verbose: true

View File

@ -4,8 +4,12 @@ on: [push, pull_request]
jobs: jobs:
build-msvc: build-msvc:
name: ${{matrix.msvc}}-${{matrix.arch}}-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.extra}} name: ${{matrix.msvc}}-${{matrix.arch}}-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}
runs-on: ${{matrix.os}} runs-on: ${{matrix.os}}
permissions:
actions: read
contents: read
security-events: write
defaults: defaults:
run: run:
shell: powershell shell: powershell
@ -17,11 +21,9 @@ jobs:
matrix: matrix:
arch: [Win32, x64] arch: [Win32, x64]
build_type: [Debug, Release] build_type: [Debug, Release]
extra: [no-custom-prefix, custom-prefix]
lib: [shared, static] lib: [shared, static]
msvc: [VS-16-2019, VS-17-2022] msvc: [VS-16-2019, VS-17-2022]
# Visual Studio 17 2022 does not support C++11 and older language standard std: [14, 17, 20, 23]
std: [14, 17, 20]
include: include:
- msvc: VS-16-2019 - msvc: VS-16-2019
os: windows-2019 os: windows-2019
@ -31,25 +33,30 @@ jobs:
generator: 'Visual Studio 17 2022' generator: 'Visual Studio 17 2022'
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: cpp
- name: Cache GTest - name: Cache GTest
id: cache-gtest id: cache-gtest
uses: actions/cache@v2 uses: actions/cache@v4
with: with:
path: gtest/ path: gtest/
key: ${{runner.os}}-gtest-1.11-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}} key: ${{runner.os}}-gtest-1.14-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}}
- name: Download GTest - name: Download GTest
if: steps.cache-gtest.outputs.cache-hit != 'true' if: steps.cache-gtest.outputs.cache-hit != 'true'
run: | run: |
(New-Object System.Net.WebClient).DownloadFile("https://github.com/google/googletest/archive/refs/tags/release-1.11.0.zip", "release-1.11.0.zip") (New-Object System.Net.WebClient).DownloadFile("https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip", "v1.14.0.zip")
Expand-Archive release-1.11.0.zip . Expand-Archive v1.14.0.zip .
- name: Build GTest - name: Build GTest
if: steps.cache-gtest.outputs.cache-hit != 'true' if: steps.cache-gtest.outputs.cache-hit != 'true'
run: | run: |
cmake -S googletest-release-1.11.0 -B build-googletest ` cmake -S googletest-1.14.0 -B build-googletest `
-A ${{matrix.arch}} ` -A ${{matrix.arch}} `
-DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} ` -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `
-Dgtest_force_shared_crt=ON ` -Dgtest_force_shared_crt=ON `
@ -60,7 +67,7 @@ jobs:
- name: Cache gflags - name: Cache gflags
id: cache-gflags id: cache-gflags
uses: actions/cache@v2 uses: actions/cache@v4
with: with:
path: gflags/ path: gflags/
key: ${{runner.os}}-gflags-2.2.2-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}} key: ${{runner.os}}-gflags-2.2.2-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}}
@ -106,7 +113,6 @@ jobs:
-DCMAKE_EXE_LINKER_FLAGS_RELEASE='/INCREMENTAL:NO /DEBUG' ` -DCMAKE_EXE_LINKER_FLAGS_RELEASE='/INCREMENTAL:NO /DEBUG' `
-DCMAKE_INSTALL_PREFIX:PATH=./install ` -DCMAKE_INSTALL_PREFIX:PATH=./install `
-DCMAKE_MSVC_RUNTIME_LIBRARY='MultiThreaded$<$<CONFIG:Debug>:Debug>DLL' ` -DCMAKE_MSVC_RUNTIME_LIBRARY='MultiThreaded$<$<CONFIG:Debug>:Debug>DLL' `
-DWITH_CUSTOM_PREFIX=${{matrix.extra == 'custom-prefix'}} `
-G "${{matrix.generator}}" ` -G "${{matrix.generator}}" `
-Werror -Werror
@ -128,11 +134,20 @@ jobs:
--config ${{matrix.build_type}} ` --config ${{matrix.build_type}} `
--target install --target install
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: language:cpp
build-mingw: build-mingw:
name: ${{matrix.sys}}-${{matrix.env}}-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.extra}} name: ${{matrix.sys}}-${{matrix.env}}-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}
runs-on: windows-2022 runs-on: windows-2022
permissions:
actions: read
contents: read
security-events: write
env: env:
BUILDDIR: 'build_${{matrix.sys}}-${{matrix.env}}-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.extra}}' BUILDDIR: 'build_${{matrix.sys}}-${{matrix.env}}-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}'
defaults: defaults:
run: run:
shell: msys2 {0} shell: msys2 {0}
@ -140,9 +155,8 @@ jobs:
fail-fast: true fail-fast: true
matrix: matrix:
build_type: [Debug] build_type: [Debug]
extra: [no-custom-prefix, custom-prefix]
lib: [shared, static] lib: [shared, static]
std: [98, 11, 14, 17, 20] std: [14, 17, 20, 23]
sys: [mingw32, mingw64] sys: [mingw32, mingw64]
include: include:
- sys: mingw32 - sys: mingw32
@ -151,21 +165,30 @@ jobs:
env: x86_64 env: x86_64
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: cpp
- uses: msys2/setup-msys2@v2 - uses: msys2/setup-msys2@v2
with: with:
msystem: ${{matrix.sys}} msystem: ${{matrix.sys}}
install: >- install: >-
lcov
mingw-w64-${{matrix.env}}-cmake mingw-w64-${{matrix.env}}-cmake
mingw-w64-${{matrix.env}}-gcc mingw-w64-${{matrix.env}}-gcc
mingw-w64-${{matrix.env}}-gflags mingw-w64-${{matrix.env}}-gflags
mingw-w64-${{matrix.env}}-ninja mingw-w64-${{matrix.env}}-ninja
mingw-w64-${{matrix.env}}-python-jinja
mingw-w64-${{matrix.env}}-python-lxml
mingw-w64-${{matrix.env}}-python-pip
mingw-w64-${{matrix.env}}-python-pygments
- name: Setup C++98 Environment - name: Setup Coverage Dependencies
if: matrix.std == '98' if: matrix.build_type == 'Debug'
run: | run: |
echo 'CXXFLAGS=-Wno-error=variadic-macros -Wno-error=long-long ${{env.CXXFLAGS}}' >> $GITHUB_ENV pip install 'gcovr==7.0'
- name: Setup Environment - name: Setup Environment
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
@ -183,7 +206,6 @@ jobs:
-DCMAKE_CXX_STANDARD=${{matrix.std}} \ -DCMAKE_CXX_STANDARD=${{matrix.std}} \
-DCMAKE_CXX_STANDARD_REQUIRED=ON \ -DCMAKE_CXX_STANDARD_REQUIRED=ON \
-DCMAKE_INSTALL_PREFIX:PATH=./install \ -DCMAKE_INSTALL_PREFIX:PATH=./install \
-DWITH_CUSTOM_PREFIX=${{matrix.extra == 'custom-prefix'}} \
-G Ninja \ -G Ninja \
-Werror -Werror
@ -207,28 +229,17 @@ jobs:
- name: Generate Coverage - name: Generate Coverage
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
run: | run: |
lcov --directory . --capture --output-file coverage.info cd build_${{matrix.build_type}}
lcov --remove coverage.info \ gcovr -r .. . -s --cobertura coverage.xml
'*/install/include/*' \
'*/msys64/mingw32/*' \
'*/msys64/mingw64/*' \
'*/src/*_unittest.cc' \
'*/src/googletest.h' \
'*/src/mock-log.h' \
--output-file coverage.info
for file in src/glog/*.h.in; do
name=$(basename ${file})
name_we=${name%.h.in}
sed -i "s|build_${{matrix.build_type}}/glog/${name_we}.h\$|${file}|g" coverage.info
done
lcov --list coverage.info
- name: Upload Coverage to Codecov - name: Upload Coverage to Codecov
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
uses: codecov/codecov-action@v2 uses: codecov/codecov-action@v5
with: with:
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
files: build_${{matrix.build_type}}/coverage.xml
fail_ci_if_error: true fail_ci_if_error: true
verbose: true verbose: true
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
*.orig *.orig
/build*/ /build*/
/site/
bazel-* bazel-*
# Bzlmod lockfile
/MODULE.bazel.lock

View File

@ -16,6 +16,7 @@ Brian Silverman <bsilver16384@gmail.com>
Dmitriy Arbitman <d.arbitman@gmail.com> Dmitriy Arbitman <d.arbitman@gmail.com>
Google Inc. Google Inc.
Guillaume Dumont <dumont.guillaume@gmail.com> Guillaume Dumont <dumont.guillaume@gmail.com>
LingBin <lingbinlb@gmail.com>
Marco Wang <m.aesophor@gmail.com> Marco Wang <m.aesophor@gmail.com>
Michael Tanner <michael@tannertaxpro.com> Michael Tanner <michael@tannertaxpro.com>
MiniLight <MiniLightAR@Gmail.com> MiniLight <MiniLightAR@Gmail.com>

View File

@ -1,7 +1,22 @@
licenses(['notice']) licenses(["notice"])
exports_files(["COPYING"]) exports_files(["COPYING"])
load(':bazel/glog.bzl', 'glog_library') load(":bazel/glog.bzl", "glog_library")
glog_library() glog_library()
# platform() to build with clang-cl on Bazel CI. This is enabled with
# the flags in .bazelci/presubmit.yml:
#
# --incompatible_enable_cc_toolchain_resolution
# --extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows-clang-cl
# --extra_execution_platforms=//:x64_windows-clang-cl
platform(
name = "x64_windows-clang-cl",
constraint_values = [
"@platforms//cpu:x86_64",
"@platforms//os:windows",
"@rules_cc//cc/private/toolchain:clang-cl",
],
)

File diff suppressed because it is too large Load Diff

View File

@ -29,12 +29,14 @@ Andy Ying <andy@trailofbits.com>
Bret McKee <bretmckee@google.com> Bret McKee <bretmckee@google.com>
Brian Silverman <bsilver16384@gmail.com> Brian Silverman <bsilver16384@gmail.com>
Dmitriy Arbitman <d.arbitman@gmail.com> Dmitriy Arbitman <d.arbitman@gmail.com>
Eric Kilmer <eric.d.kilmer@gmail.com>
Fumitoshi Ukai <ukai@google.com> Fumitoshi Ukai <ukai@google.com>
Guillaume Dumont <dumont.guillaume@gmail.com> Guillaume Dumont <dumont.guillaume@gmail.com>
Håkan L. S. Younes <hyounes@google.com> Håkan L. S. Younes <hyounes@google.com>
Ivan Penkov <ivanpe@google.com> Ivan Penkov <ivanpe@google.com>
Jacob Trimble <modmaker@google.com> Jacob Trimble <modmaker@google.com>
Jim Ray <jimray@google.com> Jim Ray <jimray@google.com>
LingBin <lingbinlb@gmail.com>
Marco Wang <m.aesophor@gmail.com> Marco Wang <m.aesophor@gmail.com>
Michael Darr <mdarr@matician.com> Michael Darr <mdarr@matician.com>
Michael Tanner <michael@tannertaxpro.com> Michael Tanner <michael@tannertaxpro.com>

65
COPYING
View File

@ -1,65 +0,0 @@
Copyright (c) 2008, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
A function gettimeofday in utilities.cc is based on
http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/COPYING&q=GetSystemTimeAsFileTime%20license:bsd
The license of this code is:
Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name(s) of the above-listed copyright holder(s) nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,3 +1,18 @@
2024-06-08 Google Inc. <opensource@google.com>
* google-glog: version 0.7.1.
* See git log for the details.
2024-02-17 Google Inc. <opensource@google.com>
* google-glog: version 0.7.0.
* See git log for the details.
2022-04-05 Google Inc. <opensource@google.com>
* google-glog: version 0.6.0.
* See git log for the details.
2021-05-08 Google Inc. <opensource@google.com> 2021-05-08 Google Inc. <opensource@google.com>
* google-glog: version 0.5.0. * google-glog: version 0.5.0.

27
LICENSE.md Normal file
View File

@ -0,0 +1,27 @@
Copyright © 2024, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
* Neither the name of Google Inc. nor the names of its contributors may be used
to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

13
MODULE.bazel Normal file
View File

@ -0,0 +1,13 @@
module(
name = "glog",
compatibility_level = 1,
)
bazel_dep(name = "gflags", version = "2.2.2")
bazel_dep(name = "googletest", version = "1.14.0", dev_dependency = True)
bazel_dep(name = "platforms", version = "0.0.10")
bazel_dep(name = "rules_cc", version = "0.0.12")
# Required for Windows clang-cl build: --extra_toolchains=@local_config_cc//:cc-toolchain-arm64_windows
cc_configure = use_extension("@rules_cc//cc:extensions.bzl", "cc_configure_extension")
use_repo(cc_configure, "local_config_cc")

View File

@ -1,868 +1,16 @@
Google Logging Library Google Logging Library
====================== ======================
|Linux Github actions| |Windows Github actions| |macOS Github actions| |Total alerts| |Language grade: C++| |Codecov| |Linux Github actions| |Windows Github actions| |macOS Github actions| |Codecov|
Google Logging (glog) is a C++98 library that implements application-level Google Logging (glog) is a C++14 library that implements application-level
logging. The library provides logging APIs based on C++-style streams and logging. The library provides logging APIs based on C++-style streams and
various helper macros. various helper macros.
.. role:: cmake(code)
:language: cmake
.. role:: cmd(code)
:language: bash
.. role:: cpp(code)
:language: cpp
.. role:: bazel(code)
:language: starlark
Getting Started Getting Started
--------------- ---------------
You can log a message by simply streaming things to ``LOG``\ (<a Please refer to project's `documentation <https://google.github.io/glog/>`_.
particular `severity level <#severity-levels>`__>), e.g.,
.. code:: cpp
#include <glog/logging.h>
int main(int argc, char* argv[]) {
// Initialize Googles logging library.
google::InitGoogleLogging(argv[0]);
// ...
LOG(INFO) << "Found " << num_cookies << " cookies";
}
For a detailed overview of glog features and their usage, please refer
to the `user guide <#user-guide>`__.
.. contents:: Table of Contents
Building from Source
--------------------
glog supports multiple build systems for compiling the project from
source: `Bazel <#bazel>`__, `CMake <#cmake>`__, and `vcpkg <#vcpkg>`__.
Bazel
~~~~~
To use glog within a project which uses the
`Bazel <https://bazel.build/>`__ build tool, add the following lines to
your ``WORKSPACE`` file:
.. code:: bazel
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "com_github_gflags_gflags",
sha256 = "34af2f15cf7367513b352bdcd2493ab14ce43692d2dcd9dfc499492966c64dcf",
strip_prefix = "gflags-2.2.2",
urls = ["https://github.com/gflags/gflags/archive/v2.2.2.tar.gz"],
)
http_archive(
name = "com_github_google_glog",
sha256 = "21bc744fb7f2fa701ee8db339ded7dce4f975d0d55837a97be7d46e8382dea5a",
strip_prefix = "glog-0.5.0",
urls = ["https://github.com/google/glog/archive/v0.5.0.zip"],
)
You can then add :bazel:`@com_github_google_glog//:glog` to the deps section
of a :bazel:`cc_binary` or :bazel:`cc_library` rule, and :code:`#include
<glog/logging.h>` to include it in your source code. Heres a simple example:
.. code:: bazel
cc_binary(
name = "main",
srcs = ["main.cc"],
deps = ["@com_github_google_glog//:glog"],
)
CMake
~~~~~
glog also supports CMake that can be used to build the project on a wide
range of platforms. If you dont have CMake installed already, you can
download it for from CMakes `official
website <http://www.cmake.org>`__.
CMake works by generating native makefiles or build projects that can be
used in the compiler environment of your choice. You can either build
glog with CMake as a standalone project or it can be incorporated into
an existing CMake build for another project.
Building glog with CMake
^^^^^^^^^^^^^^^^^^^^^^^^
When building glog as a standalone project, on Unix-like systems with
GNU Make as build tool, the typical workflow is:
1. Get the source code and change to it. e.g., cloning with git:
.. code:: bash
git clone https://github.com/google/glog.git
cd glog
2. Run CMake to configure the build tree.
.. code:: bash
cmake -S . -B build -G "Unix Makefiles"
CMake provides different generators, and by default will pick the most
relevant one to your environment. If you need a specific version of Visual
Studio, use :cmd:`cmake . -G <generator-name>`, and see :cmd:`cmake --help`
for the available generators. Also see :cmd:`-T <toolset-name>`, which can
be used to request the native x64 toolchain with :cmd:`-T host=x64`.
3. Afterwards, generated files can be used to compile the project.
.. code:: bash
cmake --build build
4. Test the build software (optional).
.. code:: bash
cmake --build build --target test
5. Install the built files (optional).
.. code:: bash
cmake --build build --target install
Consuming glog in a CMake Project
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you have glog installed in your system, you can use the CMake command
:cmake:`find_package` to build against glog in your CMake Project as follows:
.. code:: cmake
cmake_minimum_required (VERSION 3.16)
project (myproj VERSION 1.0)
find_package (glog 0.6.0 REQUIRED)
add_executable (myapp main.cpp)
target_link_libraries (myapp glog::glog)
Compile definitions and options will be added automatically to your
target as needed.
Incorporating glog into a CMake Project
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can also use the CMake command :cmake:`add_subdirectory` to include glog
directly from a subdirectory of your project by replacing the
:cmake:`find_package` call from the previous example by
:cmake:`add_subdirectory`. The :cmake:`glog::glog` target is in this case an
:cmake:`ALIAS` library target for the ``glog`` library target.
Again, compile definitions and options will be added automatically to
your target as needed.
vcpkg
~~~~~
You can download and install glog using the `vcpkg
<https://github.com/Microsoft/vcpkg>`__ dependency manager:
.. code:: bash
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install glog
The glog port in vcpkg is kept up to date by Microsoft team members and
community contributors. If the version is out of date, please create an
issue or pull request on the vcpkg repository.
User Guide
----------
glog defines a series of macros that simplify many common logging tasks.
You can log messages by severity level, control logging behavior from
the command line, log based on conditionals, abort the program when
expected conditions are not met, introduce your own verbose logging
levels, customize the prefix attached to log messages, and more.
Following sections describe the functionality supported by glog. Please note
this description may not be complete but limited to the most useful ones. If you
want to find less common features, please check header files under `src/glog
<src/glog>`__ directory.
Severity Levels
~~~~~~~~~~~~~~~
You can specify one of the following severity levels (in increasing
order of severity): ``INFO``, ``WARNING``, ``ERROR``, and ``FATAL``.
Logging a ``FATAL`` message terminates the program (after the message is
logged). Note that messages of a given severity are logged not only in
the logfile for that severity, but also in all logfiles of lower
severity. E.g., a message of severity ``FATAL`` will be logged to the
logfiles of severity ``FATAL``, ``ERROR``, ``WARNING``, and ``INFO``.
The ``DFATAL`` severity logs a ``FATAL`` error in debug mode (i.e.,
there is no ``NDEBUG`` macro defined), but avoids halting the program in
production by automatically reducing the severity to ``ERROR``.
Unless otherwise specified, glog writes to the filename
``/tmp/\<program name\>.\<hostname\>.\<user name\>.log.\<severity level\>.\<date\>-\<time\>.\<pid\>``
(e.g.,
``/tmp/hello_world.example.com.hamaji.log.INFO.20080709-222411.10474``).
By default, glog copies the log messages of severity level ``ERROR`` or
``FATAL`` to standard error (``stderr``) in addition to log files.
Setting Flags
~~~~~~~~~~~~~
Several flags influence glogs output behavior. If the `Google gflags library
<https://github.com/gflags/gflags>`__ is installed on your machine, the build
system will automatically detect and use it, allowing you to pass flags on the
command line. For example, if you want to turn the flag :cmd:`--logtostderr` on,
you can start your application with the following command line:
.. code:: bash
./your_application --logtostderr=1
If the Google gflags library isnt installed, you set flags via
environment variables, prefixing the flag name with ``GLOG_``, e.g.,
.. code:: bash
GLOG_logtostderr=1 ./your_application
The following flags are most commonly used:
``logtostderr`` (``bool``, default=\ ``false``)
Log messages to ``stderr`` instead of logfiles. Note: you can set
binary flags to ``true`` by specifying ``1``, ``true``, or ``yes``
(case insensitive). Also, you can set binary flags to ``false`` by
specifying ``0``, ``false``, or ``no`` (again, case insensitive).
``stderrthreshold`` (``int``, default=2, which is ``ERROR``)
Copy log messages at or above this level to stderr in addition to
logfiles. The numbers of severity levels ``INFO``, ``WARNING``,
``ERROR``, and ``FATAL`` are 0, 1, 2, and 3, respectively.
``minloglevel`` (``int``, default=0, which is ``INFO``)
Log messages at or above this level. Again, the numbers of severity
levels ``INFO``, ``WARNING``, ``ERROR``, and ``FATAL`` are 0, 1, 2,
and 3, respectively.
``log_dir`` (``string``, default="")
If specified, logfiles are written into this directory instead of the
default logging directory.
``v`` (``int``, default=0)
Show all ``VLOG(m)`` messages for ``m`` less or equal the value of
this flag. Overridable by :cmd:`--vmodule`. See `the section about
verbose logging <#verbose-logging>`__ for more detail.
``vmodule`` (``string``, default="")
Per-module verbose level. The argument has to contain a
comma-separated list of <module name>=<log level>. <module name> is a
glob pattern (e.g., ``gfs*`` for all modules whose name starts with
"gfs"), matched against the filename base (that is, name ignoring
.cc/.h./-inl.h). <log level> overrides any value given by :cmd:`--v`.
See also `the section about verbose logging <#verbose-logging>`__.
There are some other flags defined in logging.cc. Please grep the source
code for ``DEFINE_`` to see a complete list of all flags.
You can also modify flag values in your program by modifying global
variables ``FLAGS_*`` . Most settings start working immediately after
you update ``FLAGS_*`` . The exceptions are the flags related to
destination files. For example, you might want to set ``FLAGS_log_dir``
before calling :cpp:`google::InitGoogleLogging` . Here is an example:
.. code:: cpp
LOG(INFO) << "file";
// Most flags work immediately after updating values.
FLAGS_logtostderr = 1;
LOG(INFO) << "stderr";
FLAGS_logtostderr = 0;
// This wont change the log destination. If you want to set this
// value, you should do this before google::InitGoogleLogging .
FLAGS_log_dir = "/some/log/directory";
LOG(INFO) << "the same file";
Conditional / Occasional Logging
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sometimes, you may only want to log a message under certain conditions.
You can use the following macros to perform conditional logging:
.. code:: cpp
LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
The "Got lots of cookies" message is logged only when the variable
``num_cookies`` exceeds 10. If a line of code is executed many times, it
may be useful to only log a message at certain intervals. This kind of
logging is most useful for informational messages.
.. code:: cpp
LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
The above line outputs a log messages on the 1st, 11th, 21st, ... times
it is executed. Note that the special ``google::COUNTER`` value is used
to identify which repetition is happening.
You can combine conditional and occasional logging with the following
macro.
.. code:: cpp
LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER
<< "th big cookie";
Instead of outputting a message every nth time, you can also limit the
output to the first n occurrences:
.. code:: cpp
LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";
Outputs log messages for the first 20 times it is executed. Again, the
``google::COUNTER`` identifier indicates which repetition is happening.
Other times, it is desired to only log a message periodically based on a time.
So for example, to log a message every 10ms:
.. code:: cpp
LOG_EVERY_T(INFO, 0.01) << "Got a cookie";
Or every 2.35s:
.. code:: cpp
LOG_EVERY_T(INFO, 2.35) << "Got a cookie";
Debug Mode Support
~~~~~~~~~~~~~~~~~~
Special "debug mode" logging macros only have an effect in debug mode
and are compiled away to nothing for non-debug mode compiles. Use these
macros to avoid slowing down your production application due to
excessive logging.
.. code:: cpp
DLOG(INFO) << "Found cookies";
DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
``CHECK`` Macros
~~~~~~~~~~~~~~~~
It is a good practice to check expected conditions in your program
frequently to detect errors as early as possible. The ``CHECK`` macro
provides the ability to abort the application when a condition is not
met, similar to the ``assert`` macro defined in the standard C library.
``CHECK`` aborts the application if a condition is not true. Unlike
``assert``, it is \*not\* controlled by ``NDEBUG``, so the check will be
executed regardless of compilation mode. Therefore, ``fp->Write(x)`` in
the following example is always executed:
.. code:: cpp
CHECK(fp->Write(x) == 4) << "Write failed!";
There are various helper macros for equality/inequality checks -
``CHECK_EQ``, ``CHECK_NE``, ``CHECK_LE``, ``CHECK_LT``, ``CHECK_GE``,
and ``CHECK_GT``. They compare two values, and log a ``FATAL`` message
including the two values when the result is not as expected. The values
must have :cpp:`operator<<(ostream, ...)` defined.
You may append to the error message like so:
.. code:: cpp
CHECK_NE(1, 2) << ": The world must be ending!";
We are very careful to ensure that each argument is evaluated exactly
once, and that anything which is legal to pass as a function argument is
legal here. In particular, the arguments may be temporary expressions
which will end up being destroyed at the end of the apparent statement,
for example:
.. code:: cpp
CHECK_EQ(string("abc")[1], b);
The compiler reports an error if one of the arguments is a pointer and the other
is :cpp:`NULL`. To work around this, simply :cpp:`static_cast` :cpp:`NULL` to
the type of the desired pointer.
.. code:: cpp
CHECK_EQ(some_ptr, static_cast<SomeType*>(NULL));
Better yet, use the ``CHECK_NOTNULL`` macro:
.. code:: cpp
CHECK_NOTNULL(some_ptr);
some_ptr->DoSomething();
Since this macro returns the given pointer, this is very useful in
constructor initializer lists.
.. code:: cpp
struct S {
S(Something* ptr) : ptr_(CHECK_NOTNULL(ptr)) {}
Something* ptr_;
};
Note that you cannot use this macro as a C++ stream due to this feature.
Please use ``CHECK_EQ`` described above to log a custom message before
aborting the application.
If you are comparing C strings (:cpp:`char *`), a handy set of macros performs
case sensitive as well as case insensitive comparisons - ``CHECK_STREQ``,
``CHECK_STRNE``, ``CHECK_STRCASEEQ``, and ``CHECK_STRCASENE``. The CASE versions
are case-insensitive. You can safely pass :cpp:`NULL` pointers for this macro. They
treat :cpp:`NULL` and any non-:cpp:`NULL` string as not equal. Two :cpp:`NULL`\
s are equal.
Note that both arguments may be temporary strings which are destructed
at the end of the current "full expression" (e.g.,
:cpp:`CHECK_STREQ(Foo().c_str(), Bar().c_str())` where ``Foo`` and ``Bar``
return C++s :cpp:`std::string`).
The ``CHECK_DOUBLE_EQ`` macro checks the equality of two floating point
values, accepting a small error margin. ``CHECK_NEAR`` accepts a third
floating point argument, which specifies the acceptable error margin.
Verbose Logging
~~~~~~~~~~~~~~~
When you are chasing difficult bugs, thorough log messages are very useful.
However, you may want to ignore too verbose messages in usual development. For
such verbose logging, glog provides the ``VLOG`` macro, which allows you to
define your own numeric logging levels. The :cmd:`--v` command line option
controls which verbose messages are logged:
.. code:: cpp
VLOG(1) << "Im printed when you run the program with --v=1 or higher";
VLOG(2) << "Im printed when you run the program with --v=2 or higher";
With ``VLOG``, the lower the verbose level, the more likely messages are to be
logged. For example, if :cmd:`--v==1`, ``VLOG(1)`` will log, but ``VLOG(2)``
will not log. This is opposite of the severity level, where ``INFO`` is 0, and
``ERROR`` is 2. :cmd:`--minloglevel` of 1 will log ``WARNING`` and above. Though
you can specify any integers for both ``VLOG`` macro and :cmd:`--v` flag, the
common values for them are small positive integers. For example, if you write
``VLOG(0)``, you should specify :cmd:`--v=-1` or lower to silence it. This is
less useful since we may not want verbose logs by default in most cases. The
``VLOG`` macros always log at the ``INFO`` log level (when they log at all).
Verbose logging can be controlled from the command line on a per-module
basis:
.. code:: bash
--vmodule=mapreduce=2,file=1,gfs*=3 --v=0
will:
(a) Print ``VLOG(2)`` and lower messages from mapreduce.{h,cc}
(b) Print ``VLOG(1)`` and lower messages from file.{h,cc}
(c) Print ``VLOG(3)`` and lower messages from files prefixed with "gfs"
(d) Print ``VLOG(0)`` and lower messages from elsewhere
The wildcarding functionality shown by (c) supports both * (matches 0
or more characters) and ? (matches any single character) wildcards.
Please also check the section about `command line flags <#setting-flags>`__.
Theres also ``VLOG_IS_ON(n)`` "verbose level" condition macro. This
macro returns true when the :cmd:`--v` is equal or greater than ``n``. To
be used as
.. code:: cpp
if (VLOG_IS_ON(2)) {
// do some logging preparation and logging
// that cant be accomplished with just VLOG(2) << ...;
}
Verbose level condition macros ``VLOG_IF``, ``VLOG_EVERY_N`` and
``VLOG_IF_EVERY_N`` behave analogous to ``LOG_IF``, ``LOG_EVERY_N``,
``LOF_IF_EVERY``, but accept a numeric verbosity level as opposed to a
severity level.
.. code:: cpp
VLOG_IF(1, (size > 1024))
<< "Im printed when size is more than 1024 and when you run the "
"program with --v=1 or more";
VLOG_EVERY_N(1, 10)
<< "Im printed every 10th occurrence, and when you run the program "
"with --v=1 or more. Present occurence is " << google::COUNTER;
VLOG_IF_EVERY_N(1, (size > 1024), 10)
<< "Im printed on every 10th occurence of case when size is more "
" than 1024, when you run the program with --v=1 or more. ";
"Present occurence is " << google::COUNTER;
Custom Log Prefix Format
~~~~~~~~~~~~~~~~~~~~~~~~
glog supports changing the format of the prefix attached to log messages by
receiving a user-provided callback to be used to generate such strings. That
feature must be enabled at compile time by the ``WITH_CUSTOM_PREFIX`` flag.
For each log entry, the callback will be invoked with a ``LogMessageInfo``
struct containing the severity, filename, line number, thread ID, and time of
the event. It will also be given a reference to the output stream, whose
contents will be prepended to the actual message in the final log line.
For example:
.. code:: cpp
/* This function writes a prefix that matches glog's default format.
* (The third parameter can be used to receive user-supplied data, and is
* NULL by default.)
*/
void CustomPrefix(std::ostream &s, const LogMessageInfo &l, void*) {
s << l.severity[0]
<< setw(4) << 1900 + l.time.year()
<< setw(2) << 1 + l.time.month()
<< setw(2) << l.time.day()
<< ' '
<< setw(2) << l.time.hour() << ':'
<< setw(2) << l.time.min() << ':'
<< setw(2) << l.time.sec() << "."
<< setw(6) << l.time.usec()
<< ' '
<< setfill(' ') << setw(5)
<< l.thread_id << setfill('0')
<< ' '
<< l.filename << ':' << l.line_number << "]";
}
To enable the use of ``CustomPrefix()``, simply give glog a pointer to it
during initialization: ``InitGoogleLogging(argv[0], &CustomPrefix);``.
Optionally, ``InitGoogleLogging()`` takes a third argument of type ``void*``
to pass on to the callback function.
Failure Signal Handler
~~~~~~~~~~~~~~~~~~~~~~
The library provides a convenient signal handler that will dump useful
information when the program crashes on certain signals such as ``SIGSEGV``. The
signal handler can be installed by :cpp:`google::InstallFailureSignalHandler()`.
The following is an example of output from the signal handler.
::
*** Aborted at 1225095260 (unix time) try "date -d @1225095260" if you are using GNU date ***
*** SIGSEGV (@0x0) received by PID 17711 (TID 0x7f893090a6f0) from PID 0; stack trace: ***
PC: @ 0x412eb1 TestWaitingLogSink::send()
@ 0x7f892fb417d0 (unknown)
@ 0x412eb1 TestWaitingLogSink::send()
@ 0x7f89304f7f06 google::LogMessage::SendToLog()
@ 0x7f89304f35af google::LogMessage::Flush()
@ 0x7f89304f3739 google::LogMessage::~LogMessage()
@ 0x408cf4 TestLogSinkWaitTillSent()
@ 0x4115de main
@ 0x7f892f7ef1c4 (unknown)
@ 0x4046f9 (unknown)
By default, the signal handler writes the failure dump to the standard
error. You can customize the destination by :cpp:`InstallFailureWriter()`.
Performance of Messages
~~~~~~~~~~~~~~~~~~~~~~~
The conditional logging macros provided by glog (e.g., ``CHECK``,
``LOG_IF``, ``VLOG``, etc.) are carefully implemented and dont execute
the right hand side expressions when the conditions are false. So, the
following check may not sacrifice the performance of your application.
.. code:: cpp
CHECK(obj.ok) << obj.CreatePrettyFormattedStringButVerySlow();
User-defined Failure Function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``FATAL`` severity level messages or unsatisfied ``CHECK`` condition
terminate your program. You can change the behavior of the termination
by :cpp:`InstallFailureFunction`.
.. code:: cpp
void YourFailureFunction() {
// Reports something...
exit(EXIT_FAILURE);
}
int main(int argc, char* argv[]) {
google::InstallFailureFunction(&YourFailureFunction);
}
By default, glog tries to dump stacktrace and makes the program exit
with status 1. The stacktrace is produced only when you run the program
on an architecture for which glog supports stack tracing (as of
September 2008, glog supports stack tracing for x86 and x86_64).
Raw Logging
~~~~~~~~~~~
The header file ``<glog/raw_logging.h>`` can be used for thread-safe logging,
which does not allocate any memory or acquire any locks. Therefore, the macros
defined in this header file can be used by low-level memory allocation and
synchronization code. Please check `src/glog/raw_logging.h.in
<src/glog/raw_logging.h.in>`__ for detail.
Google Style ``perror()``
~~~~~~~~~~~~~~~~~~~~~~~~~
``PLOG()`` and ``PLOG_IF()`` and ``PCHECK()`` behave exactly like their
``LOG*`` and ``CHECK`` equivalents with the addition that they append a
description of the current state of errno to their output lines. E.g.
.. code:: cpp
PCHECK(write(1, NULL, 2) >= 0) << "Write NULL failed";
This check fails with the following error message.
::
F0825 185142 test.cc:22] Check failed: write(1, NULL, 2) >= 0 Write NULL failed: Bad address [14]
Syslog
~~~~~~
``SYSLOG``, ``SYSLOG_IF``, and ``SYSLOG_EVERY_N`` macros are available.
These log to syslog in addition to the normal logs. Be aware that
logging to syslog can drastically impact performance, especially if
syslog is configured for remote logging! Make sure you understand the
implications of outputting to syslog before you use these macros. In
general, its wise to use these macros sparingly.
Strip Logging Messages
~~~~~~~~~~~~~~~~~~~~~~
Strings used in log messages can increase the size of your binary and
present a privacy concern. You can therefore instruct glog to remove all
strings which fall below a certain severity level by using the
``GOOGLE_STRIP_LOG`` macro:
If your application has code like this:
.. code:: cpp
#define GOOGLE_STRIP_LOG 1 // this must go before the #include!
#include <glog/logging.h>
The compiler will remove the log messages whose severities are less than
the specified integer value. Since ``VLOG`` logs at the severity level
``INFO`` (numeric value ``0``), setting ``GOOGLE_STRIP_LOG`` to 1 or
greater removes all log messages associated with ``VLOG``\ s as well as
``INFO`` log statements.
Automatically Remove Old Logs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To enable the log cleaner:
.. code:: cpp
google::EnableLogCleaner(3); // keep your logs for 3 days
And then glog will check if there are overdue logs whenever a flush is
performed. In this example, any log file from your project whose last
modified time is greater than 3 days will be unlink()ed.
This feature can be disabled at any time (if it has been enabled)
.. code:: cpp
google::DisableLogCleaner();
Notes for Windows Users
~~~~~~~~~~~~~~~~~~~~~~~
glog defines a severity level ``ERROR``, which is also defined in
``windows.h`` . You can make glog not define ``INFO``, ``WARNING``,
``ERROR``, and ``FATAL`` by defining ``GLOG_NO_ABBREVIATED_SEVERITIES``
before including ``glog/logging.h`` . Even with this macro, you can
still use the iostream like logging facilities:
.. code:: cpp
#define GLOG_NO_ABBREVIATED_SEVERITIES
#include <windows.h>
#include <glog/logging.h>
// ...
LOG(ERROR) << "This should work";
LOG_IF(ERROR, x > y) << "This should be also OK";
However, you cannot use ``INFO``, ``WARNING``, ``ERROR``, and ``FATAL``
anymore for functions defined in ``glog/logging.h`` .
.. code:: cpp
#define GLOG_NO_ABBREVIATED_SEVERITIES
#include <windows.h>
#include <glog/logging.h>
// ...
// This wont work.
// google::FlushLogFiles(google::ERROR);
// Use this instead.
google::FlushLogFiles(google::GLOG_ERROR);
If you dont need ``ERROR`` defined by ``windows.h``, there are a couple
of more workarounds which sometimes dont work:
- ``#define WIN32_LEAN_AND_MEAN`` or ``NOGDI`` **before** you
``#include windows.h``.
- ``#undef ERROR`` **after** you ``#include windows.h`` .
See `this
issue <http://code.google.com/p/google-glog/issues/detail?id=33>`__ for
more detail.
Installation Notes for 64-bit Linux Systems
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The glibc built-in stack-unwinder on 64-bit systems has some problems with glog.
(In particular, if you are using :cpp:`InstallFailureSignalHandler()`, the
signal may be raised in the middle of malloc, holding some malloc-related locks
when they invoke the stack unwinder. The built-in stack unwinder may call malloc
recursively, which may require the thread to acquire a lock it already holds:
deadlock.)
For that reason, if you use a 64-bit system and you need
:cpp:`InstallFailureSignalHandler()`, we strongly recommend you install
``libunwind`` before trying to configure or install google glog.
libunwind can be found
`here <http://download.savannah.nongnu.org/releases/libunwind/libunwind-snap-070410.tar.gz>`__.
Even if you already have ``libunwind`` installed, you will probably
still need to install from the snapshot to get the latest version.
Caution: if you install libunwind from the URL above, be aware that you
may have trouble if you try to statically link your binary with glog:
that is, if you link with ``gcc -static -lgcc_eh ...``. This is because
both ``libunwind`` and ``libgcc`` implement the same C++ exception
handling APIs, but they implement them differently on some platforms.
This is not likely to be a problem on ia64, but may be on x86-64.
Also, if you link binaries statically, make sure that you add
:cmd:`-Wl,--eh-frame-hdr` to your linker options. This is required so that
``libunwind`` can find the information generated by the compiler required for
stack unwinding.
Using :cmd:`-static` is rare, though, so unless you know this will affect you it
probably wont.
If you cannot or do not wish to install libunwind, you can still try to
use two kinds of stack-unwinder: 1. glibc built-in stack-unwinder and 2.
frame pointer based stack-unwinder.
1. As we already mentioned, glibcs unwinder has a deadlock issue.
However, if you dont use :cpp:`InstallFailureSignalHandler()` or you
dont worry about the rare possibilities of deadlocks, you can use
this stack-unwinder. If you specify no options and ``libunwind``
isnt detected on your system, the configure script chooses this
unwinder by default.
2. The frame pointer based stack unwinder requires that your
application, the glog library, and system libraries like libc, all be
compiled with a frame pointer. This is *not* the default for x86-64.
How to Contribute
-----------------
Wed love to accept your patches and contributions to this project.
There are a just a few small guidelines you need to follow.
Contributor License Agreement (CLA)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Contributions to any Google project must be accompanied by a Contributor
License Agreement. This is not a copyright **assignment**, it simply
gives Google permission to use and redistribute your contributions as
part of the project.
* If you are an individual writing original source code and youre sure
you own the intellectual property, then youll need to sign an
`individual
CLA <https://developers.google.com/open-source/cla/individual>`__.
* If you work for a company that wants to allow you to contribute your
work, then youll need to sign a `corporate
CLA <https://developers.google.com/open-source/cla/corporate>`__.
You generally only need to submit a CLA once, so if youve already
submitted one (even if it was for a different project), you probably
dont need to do it again.
Once your CLA is submitted (or if you already submitted one for another
Google project), make a commit adding yourself to the
`AUTHORS <./AUTHORS>`__ and `CONTRIBUTORS <./CONTRIBUTORS>`__ files. This
commit can be part of your first `pull
request <https://help.github.com/articles/creating-a-pull-request>`__.
Submitting a Patch
~~~~~~~~~~~~~~~~~~
1. Its generally best to start by opening a new issue describing the
bug or feature youre intending to fix. Even if you think its
relatively minor, its helpful to know what people are working on.
Mention in the initial issue that you are planning to work on that
bug or feature so that it can be assigned to you.
2. Follow the normal process of
`forking <https://help.github.com/articles/fork-a-repo>`__ the
project, and setup a new branch to work in. Its important that each
group of changes be done in separate branches in order to ensure that
a pull request only includes the commits related to that bug or
feature.
3. Do your best to have `well-formed commit
messages <http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html>`__
for each change. This provides consistency throughout the project,
and ensures that commit messages are able to be formatted properly by
various git tools.
4. Finally, push the commits to your fork and submit a `pull
request <https://help.github.com/articles/creating-a-pull-request>`__.
.. |Linux Github actions| image:: https://github.com/google/glog/actions/workflows/linux.yml/badge.svg .. |Linux Github actions| image:: https://github.com/google/glog/actions/workflows/linux.yml/badge.svg
@ -871,9 +19,5 @@ Submitting a Patch
:target: https://github.com/google/glog/actions :target: https://github.com/google/glog/actions
.. |macOS Github actions| image:: https://github.com/google/glog/actions/workflows/macos.yml/badge.svg .. |macOS Github actions| image:: https://github.com/google/glog/actions/workflows/macos.yml/badge.svg
:target: https://github.com/google/glog/actions :target: https://github.com/google/glog/actions
.. |Total alerts| image:: https://img.shields.io/lgtm/alerts/g/google/glog.svg?logo=lgtm&logoWidth=18
:target: https://lgtm.com/projects/g/google/glog/alerts/
.. |Language grade: C++| image:: https://img.shields.io/lgtm/grade/cpp/g/google/glog.svg?logo=lgtm&logoWidth=18)
:target: https://lgtm.com/projects/g/google/glog/context:cpp
.. |Codecov| image:: https://codecov.io/gh/google/glog/branch/master/graph/badge.svg?token=8an420vNju .. |Codecov| image:: https://codecov.io/gh/google/glog/branch/master/graph/badge.svg?token=8an420vNju
:target: https://codecov.io/gh/google/glog :target: https://codecov.io/gh/google/glog

View File

@ -1,11 +0,0 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "com_github_gflags_gflags",
sha256 = "34af2f15cf7367513b352bdcd2493ab14ce43692d2dcd9dfc499492966c64dcf",
strip_prefix = "gflags-2.2.2",
urls = [
"https://mirror.bazel.build/github.com/gflags/gflags/archive/v2.2.2.tar.gz",
"https://github.com/gflags/gflags/archive/v2.2.2.tar.gz",
],
)

1
WORKSPACE.bazel Normal file
View File

@ -0,0 +1 @@
# WORKSPACE marker file needed by Bazel

View File

@ -4,6 +4,6 @@ cc_test(
srcs = ["main.cc"], srcs = ["main.cc"],
deps = [ deps = [
"//:glog", "//:glog",
"@com_github_gflags_gflags//:gflags", "@gflags//:gflags",
], ],
) )

View File

@ -25,15 +25,9 @@ expand_template = rule(
}, },
) )
def dict_union(x, y): def glog_library(with_gflags = 1, **kwargs):
z = {}
z.update(x)
z.update(y)
return z
def glog_library(namespace = "google", with_gflags = 1, **kwargs):
if native.repository_name() != "@": if native.repository_name() != "@":
repo_name = native.repository_name().lstrip("@") repo_name = native.repository_name()[1:] # Strip the first leading @
gendir = "$(GENDIR)/external/" + repo_name gendir = "$(GENDIR)/external/" + repo_name
src_windows = "external/%s/src/windows" % repo_name src_windows = "external/%s/src/windows" % repo_name
else: else:
@ -46,16 +40,16 @@ def glog_library(namespace = "google", with_gflags = 1, **kwargs):
values = {"cpu": "wasm"}, values = {"cpu": "wasm"},
) )
# Detect when building with clang-cl on Windows.
native.config_setting(
name = "clang-cl",
values = {"compiler": "clang-cl"},
)
common_copts = [ common_copts = [
"-DGLOG_BAZEL_BUILD", "-std=c++14",
# Inject a C++ namespace.
"-DGOOGLE_NAMESPACE='%s'" % namespace,
"-DHAVE_CXX11_NULLPTR_T",
"-DHAVE_STDINT_H",
"-DHAVE_STRING_H",
"-DGLOG_CUSTOM_PREFIX_SUPPORT",
"-I%s/glog_internal" % gendir, "-I%s/glog_internal" % gendir,
] + (["-DHAVE_LIB_GFLAGS"] if with_gflags else []) ] + (["-DGLOG_USE_GFLAGS"] if with_gflags else [])
wasm_copts = [ wasm_copts = [
# Disable warnings that exists in glog. # Disable warnings that exists in glog.
@ -63,26 +57,32 @@ def glog_library(namespace = "google", with_gflags = 1, **kwargs):
"-Wno-unused-function", "-Wno-unused-function",
"-Wno-unused-local-typedefs", "-Wno-unused-local-typedefs",
"-Wno-unused-variable", "-Wno-unused-variable",
# Allows src/base/mutex.h to include pthread.h.
"-DHAVE_PTHREAD",
# Allows src/logging.cc to determine the host name. # Allows src/logging.cc to determine the host name.
"-DHAVE_SYS_UTSNAME_H", "-DHAVE_SYS_UTSNAME_H",
# For src/utilities.cc. # For src/utilities.cc.
"-DHAVE_SYS_TIME_H", "-DHAVE_SYS_TIME_H",
"-DHAVE_UNWIND_H", # NOTE: users could optionally patch -DHAVE_UNWIND off if
# stacktrace dumping is not needed
"-DHAVE_UNWIND",
# Enable dumping stacktrace upon sigaction. # Enable dumping stacktrace upon sigaction.
"-DHAVE_SIGACTION", "-DHAVE_SIGACTION",
# For logging.cc. # For logging.cc.
"-DHAVE_PREAD", "-DHAVE_PREAD",
"-DHAVE___ATTRIBUTE__", # -DHAVE_MODE_T prevent repeated typedef mode_t leading
# to emcc compilation failure
"-DHAVE_MODE_T",
"-DHAVE_UNISTD_H",
] ]
linux_or_darwin_copts = wasm_copts + [ linux_or_darwin_copts = wasm_copts + [
"-DGLOG_EXPORT=__attribute__((visibility(\\\"default\\\")))", "-DGLOG_EXPORT=__attribute__((visibility(\\\"default\\\")))",
"-DGLOG_NO_EXPORT=__attribute__((visibility(\\\"default\\\")))",
"-DHAVE_POSIX_FADVISE",
"-DHAVE_SSIZE_T",
"-DHAVE_SYS_TYPES_H",
# For src/utilities.cc. # For src/utilities.cc.
"-DHAVE_SYS_SYSCALL_H", "-DHAVE_SYS_SYSCALL_H",
# For src/logging.cc to create symlinks. # For src/logging.cc to create symlinks.
"-DHAVE_UNISTD_H",
"-fvisibility-inlines-hidden", "-fvisibility-inlines-hidden",
"-fvisibility=hidden", "-fvisibility=hidden",
] ]
@ -90,44 +90,97 @@ def glog_library(namespace = "google", with_gflags = 1, **kwargs):
freebsd_only_copts = [ freebsd_only_copts = [
# Enable declaration of _Unwind_Backtrace # Enable declaration of _Unwind_Backtrace
"-D_GNU_SOURCE", "-D_GNU_SOURCE",
"-DHAVE_LINK_H",
"-DHAVE_SYMBOLIZE", # Supported by <link.h>
]
linux_only_copts = [
# For utilities.h.
"-DHAVE_EXECINFO_H",
"-DHAVE_LINK_H",
"-DHAVE_SYMBOLIZE", # Supported by <link.h>
] ]
darwin_only_copts = [ darwin_only_copts = [
# For stacktrace. # For stacktrace.
"-DHAVE_DLADDR", "-DHAVE_DLADDR",
# Avoid deprecated syscall().
"-DHAVE_PTHREAD_THREADID_NP",
] ]
windows_only_copts = [ windows_only_copts = [
# Override -DGLOG_EXPORT= from the cc_library's defines.
"-DGLOG_EXPORT=__declspec(dllexport)", "-DGLOG_EXPORT=__declspec(dllexport)",
"-DGLOG_NO_ABBREVIATED_SEVERITIES", "-DGLOG_NO_ABBREVIATED_SEVERITIES",
"-DHAVE_SNPRINTF", "-DGLOG_NO_EXPORT=",
"-DGLOG_USE_WINDOWS_PORT",
"-DHAVE__CHSIZE_S",
"-DHAVE_DBGHELP",
"-I" + src_windows, "-I" + src_windows,
] ]
clang_cl_only_copts = [
# Allow the override of -DGLOG_EXPORT.
"-Wno-macro-redefined",
]
windows_only_srcs = [ windows_only_srcs = [
"src/glog/log_severity.h",
"src/windows/dirent.h", "src/windows/dirent.h",
"src/windows/port.cc", "src/windows/port.cc",
"src/windows/port.h", "src/windows/port.h",
] ]
gflags_deps = ["@com_github_gflags_gflags//:gflags"] if with_gflags else [] gflags_deps = ["@gflags//:gflags"] if with_gflags else []
final_lib_defines = select({
# GLOG_EXPORT is normally set by export.h, but that's not
# generated for Bazel.
"@bazel_tools//src/conditions:windows": [
"GLOG_DEPRECATED=__declspec(deprecated)",
"GLOG_EXPORT=",
"GLOG_NO_ABBREVIATED_SEVERITIES",
"GLOG_NO_EXPORT=",
],
"//conditions:default": [
"GLOG_DEPRECATED=__attribute__((deprecated))",
"GLOG_EXPORT=__attribute__((visibility(\\\"default\\\")))",
"GLOG_NO_EXPORT=__attribute__((visibility(\\\"default\\\")))",
],
})
final_lib_copts = select({
"@bazel_tools//src/conditions:windows": common_copts + windows_only_copts,
"@bazel_tools//src/conditions:darwin": common_copts + linux_or_darwin_copts + darwin_only_copts,
"@bazel_tools//src/conditions:freebsd": common_copts + linux_or_darwin_copts + freebsd_only_copts,
":wasm": common_copts + wasm_copts,
"//conditions:default": common_copts + linux_or_darwin_copts + linux_only_copts,
}) + select({
":clang-cl": clang_cl_only_copts,
"//conditions:default": [],
})
# Needed to use these headers in `glog` and the test targets without exposing them as public targets in `glog`
native.filegroup(
name = "shared_headers",
srcs = [
"src/base/commandlineflags.h",
"src/stacktrace.h",
"src/utilities.h",
]
)
native.cc_library( native.cc_library(
name = "glog", name = "glog",
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
srcs = [ srcs = [
":config_h", ":config_h",
"src/base/commandlineflags.h", ":shared_headers",
"src/base/googleinit.h", "src/base/googleinit.h",
"src/base/mutex.h",
"src/demangle.cc", "src/demangle.cc",
"src/demangle.h", "src/demangle.h",
"src/flags.cc",
"src/logging.cc", "src/logging.cc",
"src/raw_logging.cc", "src/raw_logging.cc",
"src/signalhandler.cc", "src/signalhandler.cc",
"src/stacktrace.cc",
"src/stacktrace.h", "src/stacktrace.h",
"src/stacktrace_generic-inl.h", "src/stacktrace_generic-inl.h",
"src/stacktrace_libunwind-inl.h", "src/stacktrace_libunwind-inl.h",
@ -145,52 +198,87 @@ def glog_library(namespace = "google", with_gflags = 1, **kwargs):
"//conditions:default": [], "//conditions:default": [],
}), }),
hdrs = [ hdrs = [
"src/glog/flags.h",
"src/glog/log_severity.h", "src/glog/log_severity.h",
"src/glog/logging.h",
"src/glog/platform.h", "src/glog/platform.h",
":logging_h", "src/glog/raw_logging.h",
":raw_logging_h", "src/glog/stl_logging.h",
":stl_logging_h", "src/glog/types.h",
":vlog_is_on_h", "src/glog/vlog_is_on.h",
], ],
# https://github.com/google/glog/issues/837: Replacing
# `strip_include_prefix` with `includes` would avoid spamming
# downstream projects with compiler warnings, but would also leak
# private headers like stacktrace.h, because strip_include_prefix's
# implementation only creates symlinks for the public hdrs. I suspect
# the only way to avoid this is to refactor the project including the
# CMake build, so that the private headers are in a glog_internal
# subdirectory.
strip_include_prefix = "src", strip_include_prefix = "src",
defines = select({ defines = final_lib_defines,
# GLOG_EXPORT is normally set by export.h, but that's not copts = final_lib_copts,
# generated for Bazel.
"@bazel_tools//src/conditions:windows": [
"GLOG_EXPORT=",
"GLOG_DEPRECATED=__declspec(deprecated)",
"GLOG_NO_ABBREVIATED_SEVERITIES",
],
"//conditions:default": [
"GLOG_DEPRECATED=__attribute__((deprecated))",
"GLOG_EXPORT=__attribute__((visibility(\\\"default\\\")))",
],
}),
copts =
select({
"@bazel_tools//src/conditions:windows": common_copts + windows_only_copts,
"@bazel_tools//src/conditions:darwin": common_copts + linux_or_darwin_copts + darwin_only_copts,
"@bazel_tools//src/conditions:freebsd": common_copts + linux_or_darwin_copts + freebsd_only_copts,
":wasm": common_copts + wasm_copts,
"//conditions:default": common_copts + linux_or_darwin_copts,
}),
deps = gflags_deps + select({ deps = gflags_deps + select({
"@bazel_tools//src/conditions:windows": [":strip_include_prefix_hack"], "@bazel_tools//src/conditions:windows": [":strip_include_prefix_hack"],
"//conditions:default": [], "//conditions:default": [],
}), }),
linkopts = select({
"@bazel_tools//src/conditions:windows": ["dbghelp.lib"],
"//conditions:default": [],
}),
**kwargs **kwargs
) )
test_list = [
"cleanup_immediately",
"cleanup_with_absolute_prefix",
"cleanup_with_relative_prefix",
# "demangle", # Broken
# "logging", # Broken
# "mock-log", # Broken
# "signalhandler", # Pointless
"stacktrace",
"stl_logging",
# "symbolize", # Broken
"utilities",
]
test_only_copts = [
"-DTEST_SRC_DIR=\\\"%s/tests\\\"" % gendir,
]
for test_name in test_list:
native.cc_test(
name = test_name + "_test",
visibility = ["//visibility:public"],
srcs = [
":config_h",
":shared_headers",
"src/googletest.h",
"src/" + test_name + "_unittest.cc",
],
defines = final_lib_defines,
copts = final_lib_copts + test_only_copts,
deps = gflags_deps + [
":glog",
"@googletest//:gtest",
],
**kwargs
)
# Workaround https://github.com/bazelbuild/bazel/issues/6337 by declaring # Workaround https://github.com/bazelbuild/bazel/issues/6337 by declaring
# the dependencies without strip_include_prefix. # the dependencies without strip_include_prefix.
native.cc_library( native.cc_library(
name = "strip_include_prefix_hack", name = "strip_include_prefix_hack",
hdrs = [ hdrs = [
"src/glog/flags.h",
"src/glog/log_severity.h", "src/glog/log_severity.h",
":logging_h", "src/glog/logging.h",
":raw_logging_h", "src/glog/platform.h",
":stl_logging_h", "src/glog/raw_logging.h",
":vlog_is_on_h", "src/glog/stl_logging.h",
"src/glog/types.h",
"src/glog/vlog_is_on.h",
], ],
) )
@ -200,61 +288,3 @@ def glog_library(namespace = "google", with_gflags = 1, **kwargs):
out = "glog_internal/config.h", out = "glog_internal/config.h",
substitutions = {"#cmakedefine": "//cmakedefine"}, substitutions = {"#cmakedefine": "//cmakedefine"},
) )
common_config = {
"@ac_cv_cxx11_atomic@": "1",
"@ac_cv_cxx11_constexpr@": "1",
"@ac_cv_cxx11_chrono@": "1",
"@ac_cv_cxx11_nullptr_t@": "1",
"@ac_cv_cxx_using_operator@": "1",
"@ac_cv_have_inttypes_h@": "0",
"@ac_cv_have_u_int16_t@": "0",
"@ac_cv_have_glog_export@": "0",
"@ac_google_start_namespace@": "namespace google {",
"@ac_google_end_namespace@": "}",
"@ac_google_namespace@": "google",
}
posix_config = dict_union(common_config, {
"@ac_cv_have_unistd_h@": "1",
"@ac_cv_have_stdint_h@": "1",
"@ac_cv_have_systypes_h@": "1",
"@ac_cv_have_uint16_t@": "1",
"@ac_cv_have___uint16@": "0",
"@ac_cv_have___builtin_expect@": "1",
"@ac_cv_have_libgflags@": "1" if with_gflags else "0",
"@ac_cv___attribute___noinline@": "__attribute__((noinline))",
"@ac_cv___attribute___noreturn@": "__attribute__((noreturn))",
"@ac_cv___attribute___printf_4_5@": "__attribute__((__format__(__printf__, 4, 5)))",
})
windows_config = dict_union(common_config, {
"@ac_cv_have_unistd_h@": "0",
"@ac_cv_have_stdint_h@": "0",
"@ac_cv_have_systypes_h@": "0",
"@ac_cv_have_uint16_t@": "0",
"@ac_cv_have___uint16@": "1",
"@ac_cv_have___builtin_expect@": "0",
"@ac_cv_have_libgflags@": "0",
"@ac_cv___attribute___noinline@": "",
"@ac_cv___attribute___noreturn@": "__declspec(noreturn)",
"@ac_cv___attribute___printf_4_5@": "",
})
[
expand_template(
name = "%s_h" % f,
template = "src/glog/%s.h.in" % f,
out = "src/glog/%s.h" % f,
substitutions = select({
"@bazel_tools//src/conditions:windows": windows_config,
"//conditions:default": posix_config,
}),
)
for f in [
"vlog_is_on",
"stl_logging",
"raw_logging",
"logging",
]
]

View File

@ -1,5 +1,5 @@
cmake_policy (PUSH) cmake_policy (PUSH)
cmake_policy (VERSION 3.3) cmake_policy (VERSION 3.16...3.27)
include (CMakeParseArguments) include (CMakeParseArguments)

View File

@ -7,16 +7,20 @@ foreach (iter RANGE 1 ${RUNS})
if (NOT _RESULT EQUAL 0) if (NOT _RESULT EQUAL 0)
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})") message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
endif (NOT _RESULT EQUAL 0) endif (NOT _RESULT EQUAL 0)
# Ensure the log files to have different modification timestamps such that
# exactly one log file remains at the end. Otherwise all log files will be
# retained.
execute_process (COMMAND ${CMAKE_COMMAND} -E sleep 1)
endforeach (iter) endforeach (iter)
file (GLOB LOG_FILES ${TEST_DIR}/*.foobar) file (GLOB LOG_FILES ${TEST_DIR}/*.foobar)
list (LENGTH LOG_FILES NUM_FILES) list (LENGTH LOG_FILES NUM_FILES)
if (NOT NUM_FILES EQUAL 1) if (WIN32)
message (SEND_ERROR "Expected 1 log file in log directory but found ${NUM_FILES}") # On Windows open files cannot be removed and will result in a permission
endif (NOT NUM_FILES EQUAL 1) # denied error while unlinking such file. Therefore, the last file will be
# retained.
set (_expected 1)
else (WIN32)
set (_expected 0)
endif (WIN32)
if (NOT NUM_FILES EQUAL _expected)
message (SEND_ERROR "Expected ${_expected} log file in log directory but found ${NUM_FILES}")
endif (NOT NUM_FILES EQUAL _expected)

View File

@ -7,16 +7,20 @@ foreach (iter RANGE 1 ${RUNS})
if (NOT _RESULT EQUAL 0) if (NOT _RESULT EQUAL 0)
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})") message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
endif (NOT _RESULT EQUAL 0) endif (NOT _RESULT EQUAL 0)
# Ensure the log files to have different modification timestamps such that
# exactly one log file remains at the end. Otherwise all log files will be
# retained.
execute_process (COMMAND ${CMAKE_COMMAND} -E sleep 1)
endforeach (iter) endforeach (iter)
file (GLOB LOG_FILES ${TEST_DIR}/test_cleanup_*.barfoo) file (GLOB LOG_FILES ${TEST_DIR}/test_cleanup_*.barfoo)
list (LENGTH LOG_FILES NUM_FILES) list (LENGTH LOG_FILES NUM_FILES)
if (NOT NUM_FILES EQUAL 1) if (WIN32)
message (SEND_ERROR "Expected 1 log file in build directory ${TEST_DIR} but found ${NUM_FILES}") # On Windows open files cannot be removed and will result in a permission
endif (NOT NUM_FILES EQUAL 1) # denied error while unlinking such file. Therefore, the last file will be
# retained.
set (_expected 1)
else (WIN32)
set (_expected 0)
endif (WIN32)
if (NOT NUM_FILES EQUAL _expected)
message (SEND_ERROR "Expected ${_expected} log file in log directory but found ${NUM_FILES}")
endif (NOT NUM_FILES EQUAL _expected)

View File

@ -10,19 +10,23 @@ foreach (iter RANGE 1 ${RUNS})
if (NOT _RESULT EQUAL 0) if (NOT _RESULT EQUAL 0)
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})") message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
endif (NOT _RESULT EQUAL 0) endif (NOT _RESULT EQUAL 0)
# Ensure the log files to have different modification timestamps such that
# exactly one log file remains at the end. Otherwise all log files will be
# retained.
execute_process (COMMAND ${CMAKE_COMMAND} -E sleep 2)
endforeach (iter) endforeach (iter)
file (GLOB LOG_FILES ${TEST_DIR}/${TEST_SUBDIR}/test_cleanup_*.relativefoo) file (GLOB LOG_FILES ${TEST_DIR}/${TEST_SUBDIR}/test_cleanup_*.relativefoo)
list (LENGTH LOG_FILES NUM_FILES) list (LENGTH LOG_FILES NUM_FILES)
if (NOT NUM_FILES EQUAL 1) if (WIN32)
message (SEND_ERROR "Expected 1 log file in build directory ${TEST_DIR}${TEST_SUBDIR} but found ${NUM_FILES}") # On Windows open files cannot be removed and will result in a permission
endif (NOT NUM_FILES EQUAL 1) # denied error while unlinking such file. Therefore, the last file will be
# retained.
set (_expected 1)
else (WIN32)
set (_expected 0)
endif (WIN32)
if (NOT NUM_FILES EQUAL _expected)
message (SEND_ERROR "Expected ${_expected} log file in build directory ${TEST_DIR}${TEST_SUBDIR} but found ${NUM_FILES}")
endif (NOT NUM_FILES EQUAL _expected)
# Remove the subdirectory required by this unit test. # Remove the subdirectory required by this unit test.
file (REMOVE_RECURSE ${TEST_DIR}/${TEST_SUBDIR}) file (REMOVE_RECURSE ${TEST_DIR}/${TEST_SUBDIR})

View File

@ -1,13 +1,3 @@
# Create the build directory
execute_process (
COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_BINARY_DIR}
RESULT_VARIABLE _DIRECTORY_CREATED_SUCCEEDED
)
if (NOT _DIRECTORY_CREATED_SUCCEEDED EQUAL 0)
message (FATAL_ERROR "Failed to create build directory")
endif (NOT _DIRECTORY_CREATED_SUCCEEDED EQUAL 0)
if (GENERATOR_TOOLSET) if (GENERATOR_TOOLSET)
list (APPEND _ADDITIONAL_ARGS -T ${GENERATOR_TOOLSET}) list (APPEND _ADDITIONAL_ARGS -T ${GENERATOR_TOOLSET})
endif (GENERATOR_TOOLSET) endif (GENERATOR_TOOLSET)
@ -21,7 +11,7 @@ execute_process (
# Capture the PATH environment variable content set during project generation # Capture the PATH environment variable content set during project generation
# stage. This is required because later during the build stage the PATH is # stage. This is required because later during the build stage the PATH is
# modified again (e.g., for MinGW AppVeyor CI builds) by adding back the # modified again (e.g., for MinGW AppVeyor CI builds) by adding back the
# directory containing git.exe. Incidently, the Git installation directory # directory containing git.exe. Incidentally, the Git installation directory
# also contains sh.exe which causes MinGW Makefile generation to fail. # also contains sh.exe which causes MinGW Makefile generation to fail.
COMMAND ${CMAKE_COMMAND} -E env PATH=${PATH} COMMAND ${CMAKE_COMMAND} -E env PATH=${PATH}
${CMAKE_COMMAND} -C ${INITIAL_CACHE} ${CMAKE_COMMAND} -C ${INITIAL_CACHE}
@ -29,9 +19,9 @@ execute_process (
${_ADDITIONAL_ARGS} ${_ADDITIONAL_ARGS}
-DCMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=ON -DCMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=ON
-DCMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY=ON -DCMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY=ON
-DCMAKE_PREFIX_PATH=${PACKAGE_DIR} -Dglog_ROOT=${PACKAGE_DIR}
${SOURCE_DIR} -S ${SOURCE_DIR}
WORKING_DIRECTORY ${TEST_BINARY_DIR} -B ${TEST_BINARY_DIR}
RESULT_VARIABLE _GENERATE_SUCCEEDED RESULT_VARIABLE _GENERATE_SUCCEEDED
) )

11
codecov.yml Normal file
View File

@ -0,0 +1,11 @@
comment:
layout: "diff, flags, files"
behavior: default
require_changes: false
require_base: false
require_head: true
ignore:
- "**/*_unittest.cc"
- "src/*_unittest/**"
- "src/googletest.h"
- "src/mock-log.h"

66
docs/build.md Normal file
View File

@ -0,0 +1,66 @@
# Building from Source
## Bazel
To use glog within a project which uses the [Bazel](https://bazel.build/) build
tool, add the following lines to your `MODULE.bazel` file:
``` bazel title="MODULE.bazel"
bazel_dep(name = "glog")
archive_override(
module_name = "glog",
urls = "https://github.com/google/glog/archive/cc0de6c200375b33d907ee7632eee2f173b33a09.tar.gz",
strip_prefix = "glog-cc0de6c200375b33d907ee7632eee2f173b33a09", # Latest commit as of 2024-06-08.
integrity = "sha256-rUrv4EBkdc+4Wbhfxp+KoRstlj2Iw842/OpLfDq0ivg=",
)
```
You can then add `@glog//:glog` to
the deps section of a `cc_binary` or
`cc_library` rule, and `#!cpp #include <glog/logging.h>` to
include it in your source code.
!!! example "Using glog in a Bazel project"
``` bazel
cc_binary(
name = "main",
srcs = ["main.cc"],
deps = ["@glog//:glog"],
)
```
## CMake
glog can be compiled using [CMake](http://www.cmake.org) on a wide range of
platforms. The typical workflow for building glog on a Unix-like system with GNU
Make as build tool is as follows:
1. Clone the repository and change into source directory.
``` bash
git clone https://github.com/google/glog.git
cd glog
```
2. Run CMake to configure the build tree.
``` bash
cmake -S . -B build -G "Unix Makefiles"
```
CMake provides different generators, and by default will pick the most
relevant one to your environment. If you need a specific version of Visual
Studio, use `#!bash cmake . -G <generator-name>`, and see `#!bash cmake
--help` for the available generators. Also see `-T <toolset-name>`, which can
be used to request the native x64 toolchain with `-T host=x64`.
3. Afterwards, generated files can be used to compile the project.
``` bash
cmake --build build
```
4. Test the build software (optional).
``` bash
cmake --build build --target test
```
5. Install the built files (optional).
``` bash
cmake --build build --target install
```
Once successfully built, glog can be [integrated into own projects](usage.md).

50
docs/contribute.md Normal file
View File

@ -0,0 +1,50 @@
# How to Contribute
We'd love to accept your patches and contributions to this project.
There are a just a few small guidelines you need to follow.
## Contributor License Agreement (CLA)
Contributions to any Google project must be accompanied by a Contributor
License Agreement. This is not a copyright **assignment**, it simply
gives Google permission to use and redistribute your contributions as
part of the project.
- If you are an individual writing original source code and you're
sure you own the intellectual property, then you'll need to sign an
[individual
CLA](https://developers.google.com/open-source/cla/individual).
- If you work for a company that wants to allow you to contribute your
work, then you'll need to sign a [corporate
CLA](https://developers.google.com/open-source/cla/corporate).
You generally only need to submit a CLA once, so if you've already
submitted one (even if it was for a different project), you probably
don't need to do it again.
Once your CLA is submitted (or if you already submitted one for another Google
project), make a commit adding yourself to the
[AUTHORS](https://github.com/google/glog/blob/master/AUTHORS) and
[CONTRIBUTORS](https://github.com/google/glog/blob/master/CONTRIBUTORS) files.
This commit can be part of your first [pull
request](https://help.github.com/articles/creating-a-pull-request).
## Submitting a Patch
1. It's generally best to start by opening a new issue describing the
bug or feature you're intending to fix. Even if you think it's
relatively minor, it's helpful to know what people are working on.
Mention in the initial issue that you are planning to work on that
bug or feature so that it can be assigned to you.
2. Follow the normal process of
[forking](https://help.github.com/articles/fork-a-repo) the project,
and setup a new branch to work in. It's important that each group of
changes be done in separate branches in order to ensure that a pull
request only includes the commits related to that bug or feature.
3. Do your best to have [well-formed commit
messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
for each change. This provides consistency throughout the project,
and ensures that commit messages are able to be formatted properly
by various git tools.
4. Finally, push the commits to your fork and submit a [pull
request](https://help.github.com/articles/creating-a-pull-request).

73
docs/failures.md Normal file
View File

@ -0,0 +1,73 @@
# Failure Signal Handler
## Stacktrace as Default Failure Handler
The library provides a convenient signal handler that will dump useful
information when the program crashes on certain signals such as `SIGSEGV`. The
signal handler can be installed by `#!cpp
google::InstallFailureSignalHandler()`. The following is an example of output
from the signal handler.
*** Aborted at 1225095260 (unix time) try "date -d @1225095260" if you are using GNU date ***
*** SIGSEGV (@0x0) received by PID 17711 (TID 0x7f893090a6f0) from PID 0; stack trace: ***
PC: @ 0x412eb1 TestWaitingLogSink::send()
@ 0x7f892fb417d0 (unknown)
@ 0x412eb1 TestWaitingLogSink::send()
@ 0x7f89304f7f06 google::LogMessage::SendToLog()
@ 0x7f89304f35af google::LogMessage::Flush()
@ 0x7f89304f3739 google::LogMessage::~LogMessage()
@ 0x408cf4 TestLogSinkWaitTillSent()
@ 0x4115de main
@ 0x7f892f7ef1c4 (unknown)
@ 0x4046f9 (unknown)
## Customizing Handler Output
By default, the signal handler writes the failure dump to the standard error.
However, it is possible to customize the destination by installing a callback
using the `#!cpp google::InstallFailureWriter()` function. The function expects
a pointer to a function with the following signature:
``` cpp
void YourFailureWriter(const char* message/* (1)! */, std::size_t length/* (2)! */);
```
1. The pointer references the start of the failure message.
!!! danger
The string is **not null-terminated**.
2. The message length in characters.
!!! warning "Possible overflow errors"
Users should not expect the `message` string to be null-terminated.
## User-defined Failure Function
`FATAL` severity level messages or unsatisfied `CHECK` condition
terminate your program. You can change the behavior of the termination
by `google::InstallFailureFunction`.
``` cpp
void YourFailureFunction() {
// Reports something...
exit(EXIT_FAILURE);
}
int main(int argc, char* argv[]) {
google::InstallFailureFunction(&YourFailureFunction);
}
```
By default, glog tries to dump the stacktrace and calls `#!cpp std::abort`. The
stacktrace is generated only when running the application on a system
supported[^1] by glog.
[^1]: To extract the stack trace, glog currently supports the following targets:
* x86, x86_64,
* PowerPC architectures,
* `libunwind`,
* and the Debug Help Library (`dbghelp`) on Windows.

93
docs/flags.md Normal file
View File

@ -0,0 +1,93 @@
# Adjusting Output
Several flags influence glog's output behavior.
## Using Command-line Parameters and Environment Variables
If the [Google gflags
library](https://github.com/gflags/gflags) is installed on your machine,
the build system will automatically detect and use it, allowing you to
pass flags on the command line.
!!! example "Activate `--logtostderr` in an application from the command line"
A binary `you_application` that uses glog can be started using
``` bash
./your_application --logtostderr=1
```
to log to `stderr` instead of writing the output to a log file.
!!! tip
You can set boolean flags to `true` by specifying `1`, `true`, or `yes`. To
set boolean flags to `false`, specify `0`, `false`, or `no`. In either case
the spelling is case-insensitive.
If the Google gflags library isn't installed, you set flags via
environment variables, prefixing the flag name with `GLOG_`, e.g.,
!!! example "Activate `logtostderr` without gflags"
``` bash
GLOG_logtostderr=1 ./your_application
```
The following flags are most commonly used:
`logtostderr` (`bool`, default=`false`)
: Log messages to `stderr` instead of logfiles.
`stderrthreshold` (`int`, default=2, which is `ERROR`)
: Copy log messages at or above this level to `stderr` in addition to
logfiles. The numbers of severity levels `INFO`, `WARNING`, `ERROR`,
and `FATAL` are 0, 1, 2, and 3, respectively.
`minloglevel` (`int`, default=0, which is `INFO`)
: Log messages at or above this level. Again, the numbers of severity
levels `INFO`, `WARNING`, `ERROR`, and `FATAL` are 0, 1, 2, and 3,
respectively.
`log_dir` (`string`, default="")
: If specified, logfiles are written into this directory instead of
the default logging directory.
`v` (`int`, default=0)
: Show all `#!cpp VLOG(m)` messages for `m` less or equal the value of this
flag. Overridable by `#!bash --vmodule`. Refer to [verbose
logging](logging.md#verbose-logging) for more detail.
`vmodule` (`string`, default="")
: Per-module verbose level. The argument has to contain a
comma-separated list of `<module name>=<log level>`. `<module name>` is a
glob pattern (e.g., `gfs*` for all modules whose name starts with "gfs"),
matched against the filename base (that is, name ignoring .cc/.h./-inl.h).
`<log level>` overrides any value given by `--v`. See also [verbose
logging](logging.md#verbose-logging) for more details.
Additional flags are defined in
[flags.cc](https://github.com/google/glog/blob/master/src/flags.cc). Please see
the source for their complete list.
## Modifying Flags Programmatically
You can also modify flag values in your program by modifying global variables
`FLAGS_*`. Most settings start working immediately after you update `FLAGS_*`.
The exceptions are the flags related to destination files. For instance, you
might want to set `FLAGS_log_dir` before calling `google::InitGoogleLogging`.
!!! example "Setting `log_dir` at runtime"
``` cpp
LOG(INFO) << "file";
// Most flags work immediately after updating values.
FLAGS_logtostderr = 1;
LOG(INFO) << "stderr";
FLAGS_logtostderr = 0;
// This wont change the log destination. If you want to set this
// value, you should do this before google::InitGoogleLogging .
FLAGS_log_dir = "/some/log/directory";
LOG(INFO) << "the same file";
```

30
docs/index.md Normal file
View File

@ -0,0 +1,30 @@
# Google Logging Library
Google Logging (glog) is a C++14 library that implements application-level
logging. The library provides logging APIs based on C++-style streams and
various helper macros.
# How to Use
You can log a message by simply streaming things to `LOG`(<a particular
[severity level](logging.md#severity-levels)\>), e.g.,
``` cpp title="main.cpp"
#include <glog/logging.h>
int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]); // (1)!
LOG(INFO) << "Found " << num_cookies << " cookies"; // (2)!
}
```
1. Initialize the Google Logging Library
2. Log a message with informational severity
The library can be installed using various [package managers](packages.md) or
compiled [from source](build.md). For a detailed overview of glog features and
their usage, please refer to the [user guide](logging.md).
!!! warning
The above example requires further [Bazel](build.md#bazel) or
[CMake](usage.md) setup for use in own projects.

3
docs/license.md Normal file
View File

@ -0,0 +1,3 @@
# The 3-Clause BSD License
--8<-- "LICENSE.md"

24
docs/log_cleaner.md Normal file
View File

@ -0,0 +1,24 @@
# Automatically Remove Old Logs
To enable the log cleaner:
``` cpp
using namespace std::chrono_literals;
google::EnableLogCleaner(24h * 3); // keep your logs for 3 days
```
In C++20 (and later) this can be shortened to:
``` cpp
using namespace std::chrono_literals;
google::EnableLogCleaner(3d); // keep your logs for 3 days
```
And then glog will check if there are overdue logs whenever a flush is
performed. In this example, any log file from your project whose last
modified time is greater than 3 days will be `unlink`()ed.
This feature can be disabled at any time (if it has been enabled) using
``` cpp
google::DisableLogCleaner();
```

20
docs/log_stripping.md Normal file
View File

@ -0,0 +1,20 @@
# Strip Logging Messages
Strings used in log messages can increase the size of your binary and
present a privacy concern. You can therefore instruct glog to remove all
strings which fall below a certain severity level by using the
`GOOGLE_STRIP_LOG` macro:
If your application has code like this:
``` cpp
#define GOOGLE_STRIP_LOG 1 // this must go before the #include!
#include <glog/logging.h>
```
The compiler will remove the log messages whose severities are less than
the specified integer value. Since `VLOG` logs at the severity level
`INFO` (numeric value `0`), setting `GOOGLE_STRIP_LOG` to 1 or greater
removes all log messages associated with `VLOG`s as well as `INFO` log
statements.

424
docs/logging.md Normal file
View File

@ -0,0 +1,424 @@
# Logging
glog defines a series of macros that simplify many common logging tasks. You can
log messages by [severity level](#severity-levels), [control logging](flags.md)
behavior from the command line, log based on
[conditionals](#conditional-occasional-logging), abort the program when
[expected conditions](#runtime-checks) are not met, introduce your [own logging
levels](#verbose-logging), [customize the prefix](#format-customization)
attached to log messages, and more.
## Severity Levels
You can specify one of the following severity levels (in increasing order of
severity):
1. `INFO`,
2. `WARNING`,
3. `ERROR`, and
4. `FATAL`.
Logging a `FATAL` message terminates the program (after the message is logged).
!!! note
Messages of a given severity are logged not only to corresponding severity
logfile but also to other logfiles of lower severity. For instance, a
message of severity `FATAL` will be logged to logfiles of severity `FATAL`,
`ERROR`, `WARNING`, and `INFO`.
The `DFATAL` severity logs a `FATAL` error in [debug mode](#debugging-support)
(i.e., there is no `NDEBUG` macro defined), but avoids halting the program in
production by automatically reducing the severity to `ERROR`.
## Log Files
Unless otherwise specified, glog uses the format
<tmp>/<program name>.<hostname>.<user name>.log.<severity level>.<date>-<time>.<pid>
for log filenames written to a directory designated as `<tmp>` and
determined according to the following rules.
**Windows**
: glog uses the
[GetTempPathA](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha)
API function to retrieve the directory for temporary files with a
fallback to
1. `C:\TMP\`
2. `C:\TEMP\`
(in the order given.)
**non-Windows**
: The directory is determined by referencing the environment variables
1. `TMPDIR`
2. `TMP`
if set with a fallback to `/tmp/`.
The default path to a log file on Linux, for instance, could be
/tmp/hello_world.example.com.hamaji.log.INFO.20080709-222411.10474
By default, glog echos `ERROR` and `FATAL` messages to standard error in
addition to log files.
## Log Line Prefix Format
Log lines have this form:
Lyyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg...
where the fields are defined as follows:
| Placeholder | Meaning |
| ------------------- | ----------------------------------------------------------------------|
| `L` | A single character, representing the log level (e.g., `I` for `INFO`) |
| `yyyy` | The year |
| `mm` | The month (zero padded; i.e., May is `05`) |
| `dd` | The day (zero padded) |
| `hh:mm:ss.uuuuuu` | Time in hours, minutes and fractional seconds |
| `threadid` | The space-padded thread ID |
| `file` | The file name |
| `line` | The line number |
| `msg` | The user-supplied message |
!!! example "Default log line prefix format"
```
I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog
I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395
```
!!! note
Although microseconds are useful for comparing events on a single machine,
clocks on different machines may not be well synchronized. Hence, use with
caution when comparing the low bits of timestamps from different machines.
### Format Customization
The predefined log line prefix can be replaced using a user-provided callback
that formats the corresponding output.
For each log entry, the callback will be invoked with a reference to a
`google::LogMessage` instance containing the severity, filename, line
number, thread ID, and time of the event. It will also be given a
reference to the output stream, whose contents will be prepended to the actual
message in the final log line.
To enable the use of a prefix formatter, use the
``` cpp
google::InstallPrefixFormatter(&MyPrefixFormatter);
```
function to pass a pointer to the corresponding `MyPrefixFormatter` callback
during initialization. `InstallPrefixFormatter` takes a second optional argument
of type `#!cpp void*` that allows supplying user data to the callback.
!!! example "Custom prefix formatter"
The following function outputs a prefix that matches glog's default format.
The third parameter `data` can be used to access user-supplied data which
unless specified defaults to `#!cpp nullptr`.
``` cpp
void MyPrefixFormatter(std::ostream& s, const google::LogMessage& m, void* /*data*/) {
s << google::GetLogSeverityName(m.severity())[0]
<< setw(4) << 1900 + m.time().year()
<< setw(2) << 1 + m.time().month()
<< setw(2) << m.time().day()
<< ' '
<< setw(2) << m.time().hour() << ':'
<< setw(2) << m.time().min() << ':'
<< setw(2) << m.time().sec() << "."
<< setw(6) << m.time().usec()
<< ' '
<< setfill(' ') << setw(5)
<< m.thread_id() << setfill('0')
<< ' '
<< m.basename() << ':' << m.line() << "]";
}
```
## Conditional / Occasional Logging
Sometimes, you may only want to log a message under certain conditions.
You can use the following macros to perform conditional logging:
``` cpp
LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
```
The "Got lots of cookies" message is logged only when the variable
`num_cookies` exceeds 10. If a line of code is executed many times, it may be
useful to only log a message at certain intervals. This kind of logging is most
useful for informational messages.
``` cpp
LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
```
The above line outputs a log messages on the 1st, 11th, 21st, ... times
it is executed.
!!! note
The placeholder `#!cpp google::COUNTER` identifies the recurring repetition.
You can combine conditional and occasional logging with the following
macro.
``` cpp
LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER
<< "th big cookie";
```
Instead of outputting a message every nth time, you can also limit the
output to the first n occurrences:
``` cpp
LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";
```
Outputs log messages for the first 20 times it is executed. The `#!cpp
google::COUNTER` identifier indicates which repetition is happening.
Other times, it is desired to only log a message periodically based on a
time. For instance, to log a message every 10ms:
``` cpp
LOG_EVERY_T(INFO, 0.01) << "Got a cookie";
```
Or every 2.35s:
``` cpp
LOG_EVERY_T(INFO, 2.35) << "Got a cookie";
```
## Verbose Logging
When you are chasing difficult bugs, thorough log messages are very
useful. However, you may want to ignore too verbose messages in usual
development. For such verbose logging, glog provides the `VLOG` macro, which
allows you to define your own numeric logging levels.
The `#!bash --v` command line option controls which verbose messages are logged:
``` cpp
VLOG(1) << "Im printed when you run the program with --v=1 or higher";
VLOG(2) << "Im printed when you run the program with --v=2 or higher";
```
With `VLOG`, the lower the verbose level, the more likely messages are to be
logged. For example, if `#!bash --v==1`, `#!cpp VLOG(1)` will log, but `#!cpp
VLOG(2)` will not log.
!!! warning
The `VLOG` behavior is opposite of the severity level logging, where
`INFO`, `ERROR`, etc. are defined in increasing order and thus
`#!bash --minloglevel` of 1 will only log `WARNING` and above.
Though you can specify any integers for both `VLOG` macro and `--v` flag, the
common values for them are small positive integers. For example, if you write
`#!cpp VLOG(0)`, you should specify `--v=-1` or lower to silence it. This is less
useful since we may not want verbose logs by default in most cases. The `VLOG`
macros always log at the `INFO` log level (when they log at all).
Verbose logging can be controlled from the command line on a per-module basis:
``` bash
--vmodule=mapreduce=2,file=1,gfs*=3 --v=0
```
Specifying these options will specifically:
1. Print `#!cpp VLOG(2)` and lower messages from mapreduce.{h,cc}
2. Print `#!cpp VLOG(1)` and lower messages from file.{h,cc}
3. Print `#!cpp VLOG(3)` and lower messages from files prefixed with "gfs"
4. Print `#!cpp VLOG(0)` and lower messages from elsewhere
The wildcarding functionality 3. supports both `*` (matches 0 or more
characters) and `?` (matches any single character) wildcards. Please also refer
to [command line flags](flags.md) for more information.
There's also `#!cpp VLOG_IS_ON(n)` "verbose level" condition macro. This macro
returns `#!cpp true` when the `--v` is equal to or greater than `n`. The macro can be
used as follows:
``` cpp
if (VLOG_IS_ON(2)) {
// (1)
}
```
1. Here we can perform some logging preparation and logging that cant be
accomplished with just `#!cpp VLOG(2) << "message ...";`
Verbose level condition macros `VLOG_IF`, `VLOG_EVERY_N` and `VLOG_IF_EVERY_N`
behave analogous to `LOG_IF`, `LOG_EVERY_N`, `LOG_IF_EVERY_N`, but accept a
numeric verbosity level as opposed to a severity level.
``` cpp
VLOG_IF(1, (size > 1024))
<< "Im printed when size is more than 1024 and when you run the "
"program with --v=1 or more";
VLOG_EVERY_N(1, 10)
<< "Im printed every 10th occurrence, and when you run the program "
"with --v=1 or more. Present occurrence is " << google::COUNTER;
VLOG_IF_EVERY_N(1, (size > 1024), 10)
<< "Im printed on every 10th occurrence of case when size is more "
" than 1024, when you run the program with --v=1 or more. ";
"Present occurrence is " << google::COUNTER;
```
!!! info "Performance"
The conditional logging macros provided by glog (e.g., `CHECK`, `LOG_IF`,
`VLOG`, etc.) are carefully implemented and don't execute the right hand
side expressions when the conditions are false. So, the following check may
not sacrifice the performance of your application.
``` cpp
CHECK(obj.ok) << obj.CreatePrettyFormattedStringButVerySlow();
```
## Debugging Support
Special debug mode logging macros only have an effect in debug mode and are
compiled away to nothing for non-debug mode compiles. Use these macros to avoid
slowing down your production application due to excessive logging.
``` cpp
DLOG(INFO) << "Found cookies";
DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
DLOG_FIRST_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
DLOG_EVERY_T(INFO, 0.01) << "Got a cookie";
```
## Runtime Checks
It is a good practice to check expected conditions in your program
frequently to detect errors as early as possible. The `CHECK` macro
provides the ability to abort the application when a condition is not met,
similar to the `assert` macro defined in the standard C library.
`CHECK` aborts the application if a condition is not true. Unlike
`assert`, it is **not** controlled by `NDEBUG`, so the check will be executed
regardless of compilation mode. Therefore, `fp->Write(x)` in the following
example is always executed:
``` cpp
CHECK(fp->Write(x) == 4) << "Write failed!";
```
There are various helper macros for equality/inequality checks
-`CHECK_EQ`, `CHECK_NE`, `CHECK_LE`, `CHECK_LT`, `CHECK_GE`, and
`CHECK_GT`. They compare two values, and log a `FATAL` message including the two
values when the result is not as expected. The values must have
`#!cpp operator<<(ostream, ...)` defined.
You may append to the error message like so:
``` cpp
CHECK_NE(1, 2) << ": The world must be ending!";
```
We are very careful to ensure that each argument is evaluated exactly
once, and that anything which is legal to pass as a function argument is legal
here. In particular, the arguments may be temporary expressions which will end
up being destroyed at the end of the apparent statement, for example:
``` cpp
CHECK_EQ(string("abc")[1], b);
```
The compiler reports an error if one of the arguments is a pointer and the other
is `#!cpp nullptr`. To work around this, simply `#!cpp static_cast` `#!cpp
nullptr` to the type of the desired pointer.
``` cpp
CHECK_EQ(some_ptr, static_cast<SomeType*>(nullptr));
```
Better yet, use the `CHECK_NOTNULL` macro:
``` cpp
CHECK_NOTNULL(some_ptr);
some_ptr->DoSomething();
```
Since this macro returns the given pointer, this is very useful in
constructor initializer lists.
``` cpp
struct S {
S(Something* ptr) : ptr_(CHECK_NOTNULL(ptr)) {}
Something* ptr_;
};
```
!!! warning
Due to the argument forwarding, `CHECK_NOTNULL` cannot be used to
simultaneously stream an additional custom message. To provide a custom
message, one can use the macro `CHECK_EQ` prior to the failing check.
If you are comparing C strings (`#!cpp char *`), a handy set of macros performs
both case sensitive and insensitive comparisons - `CHECK_STREQ`, `CHECK_STRNE`,
`CHECK_STRCASEEQ`, and `CHECK_STRCASENE`. The `CHECK_*CASE*` macro variants are
case-insensitive. You can safely pass `#!cpp nullptr` pointers to this macro.
They treat `#!cpp nullptr` and any non-`#!cpp nullptr` string as not equal. Two
`#!cpp nullptr`s are equal.
!!! note
Both arguments may be temporary objects which are destructed at the
end of the current *full expression*, such as
``` cpp
CHECK_STREQ(Foo().c_str(), Bar().c_str());
```
where `Foo` and `Bar` return `std::string`.
The `CHECK_DOUBLE_EQ` macro checks the equality of two floating point values,
accepting a small error margin. `CHECK_NEAR` accepts a third floating point
argument, which specifies the acceptable error margin.
## Raw Logging
The header file `<glog/raw_logging.h>` can be used for thread-safe logging,
which does not allocate any memory or acquire any locks. Therefore, the macros
defined in this header file can be used by low-level memory allocation and
synchronization code. Please check
[src/glog/raw_logging.h](https://github.com/google/glog/blob/master/src/glog/raw_logging.h)
for detail.
## Google Style `perror()`
`PLOG()` and `PLOG_IF()` and `PCHECK()` behave exactly like their `LOG*` and
`CHECK` equivalents with the addition that they append a description of the
current state of `errno` to their output lines. E.g.
``` cpp
PCHECK(write(1, nullptr, 2) >= 0) << "Write nullptr failed";
```
This check fails with the following error message.
F0825 185142 test.cc:22] Check failed: write(1, nullptr, 2) >= 0 Write nullptr failed: Bad address [14]
## Syslog
`SYSLOG`, `SYSLOG_IF`, and `SYSLOG_EVERY_N` macros are available. These log to
syslog in addition to the normal logs. Be aware that logging to syslog can
drastically impact performance, especially if syslog is configured for remote
logging! Make sure you understand the implications of outputting to syslog
before you use these macros. In general, it's wise to use these macros
sparingly.

8
docs/overrides/main.html Normal file
View File

@ -0,0 +1,8 @@
{% extends "base.html" %}
{% block outdated %}
You're not viewing the latest version.
<a href="{{ '../' ~ base_url }}">
<strong>Click here to go to latest.</strong>
</a>
{% endblock %}

34
docs/packages.md Normal file
View File

@ -0,0 +1,34 @@
# Installation using Package Managers
## conan
You can download and install glog using the [conan](https://conan.io)
package manager:
``` bash
pip install conan
conan install -r conancenter glog/<glog-version>@
```
The glog recipe in conan center is kept up to date by conan center index
community contributors. If the version is out of date, please create an
issue or pull request on the
[conan-center-index](https://github.com/conan-io/conan-center-index)
repository.
## vcpkg
You can download and install glog using the
[vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
``` bash
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install glog
```
The glog port in vcpkg is kept up to date by Microsoft team members and
community contributors. If the version is out of date, please create an
issue or pull request on the vcpkg repository.

6
docs/requirements.txt Normal file
View File

@ -0,0 +1,6 @@
mike>=2.1.1
mkdocs-git-committers-plugin-2>=2.3.0
mkdocs-git-revision-date-localized-plugin>=1.2.6
mkdocs-material-extensions>=1.3.1
mkdocs-material>=9.5.26
mkdocs>=1.6.0

84
docs/sinks.md Normal file
View File

@ -0,0 +1,84 @@
# Custom Sinks
Under certain circumstances, it is useful to send the log output to a
destination other than a file, `stderr` and/or `stdout`. In case, the library
provides the `#!cpp google::LogSink` interface whose implementations can be used
to write the log output to arbitrary locations.
## Basic Interface
The sink interface is defined as follows:
``` cpp
class LogSink {
public:
virtual void send(LogSeverity severity, const char* full_filename,
const char* base_filename, int line,
const LogMessageTime& time, const char* message,
size_t message_len);
};
```
The user must implement `#!cpp google::LogSink::send`, which is called by the
library every time a message is logged.
!!! warning "Possible deadlock due to nested logging"
This method can't use `LOG()` or `CHECK()` as logging system mutex(s) are
held during this call.
## Registering Log Sinks
To use the custom sink and instance of the above interface implementation must
be registered using `google::AddLogSink` which expects a pointer to the
`google::LogSink` instance. To unregister use `google::RemoveLogSink`. Both
functions are thread-safe.
!!! danger "`LogSink` ownership"
The `google::LogSink` instance must not be destroyed until the referencing
pointer is unregistered.
## Direct Logging
Instead of registering the sink, we can directly use to log messages. While `#!
LOG_TO_SINK(sink, severity)` allows to log both to the sink and to a global log
registry, e.g., a file, `#!cpp LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity)`
will avoid the latter.
!!! example "Using a custom sink"
``` cpp title="custom_sink.cc"
-8<- "examples/custom_sink.cc:33:"
```
1. `MySink` implements a custom sink that sends log messages to `std::cout`.
2. The custom sink must be registered to for use with existing logging
macros.
3. Once the custom sink is no longer needed we remove it from the registry.
4. A sink does not need to be registered globally. However, then, messages
must be logged using dedicated macros.
Running the above example as `#!bash GLOG_log_dir=. ./custom_sink_example`
will produce
<div class="annotate" markdown>
``` title="Custom sink output"
INFO custom_sink.cc:63 logging to MySink
INFO custom_sink.cc:68 direct logging
INFO custom_sink.cc:69 direct logging but not to file (1)
```
</div>
1. This line is not present in the log file because we used
`LOG_TO_SINK_BUT_NOT_TO_LOGFILE` to log the message.
and the corresponding log file will contain
``` title="Log file generated with the custom sink"
Log file created at: 2024/06/11 13:24:27
Running on machine: pc
Running duration (h:mm:ss): 0:00:00
Log line format: [IWEF]yyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg
I20240611 13:24:27.476620 126237946035776 custom_sink.cc:63] logging to MySink
I20240611 13:24:27.476796 126237946035776 custom_sink.cc:68] direct logging
```

57
docs/unwinder.md Normal file
View File

@ -0,0 +1,57 @@
# Installation Notes for 64-bit Linux Systems
!!! note
The description on this page is possibly not up-to-date.
The [glibc built-in stack-unwinder](#glibc-built-in-stack-unwinder) on 64-bit
systems has some problems with glog. In particular, if you are using
[`InstallFailureSignalHandler()`](failures.md), the signal may be raised in the
middle of `malloc`, holding some `malloc`-related locks when they invoke the
stack unwinder. The built-in stack unwinder may call `malloc` recursively, which
may require the thread to acquire a lock it already holds resulting in a
deadlock.
## Recommended Approach: `libunwind`
For above reason, if you use a 64-bit system and you need
`InstallFailureSignalHandler()`, we strongly recommend you install `libunwind`
before trying to configure or install google glog. libunwind can be found
[here](http://download.savannah.nongnu.org/releases/libunwind/libunwind-snap-070410.tar.gz).
Even if you already have `libunwind` installed, you will probably still need to
install from the snapshot to get the latest version.
!!! warning
If you install libunwind from the URL above, be aware that you may have
trouble if you try to statically link your binary with glog: that is, if you
link with `gcc -static -lgcc_eh ...`. This is because both `libunwind` and
`libgcc` implement the same C++ exception handling APIs, but they implement
them differently on some platforms. This is not likely to be a problem on
ia64, but may be on x86-64.
Also, if you link binaries statically, make sure that you add
`-Wl,--eh-frame-hdr` to your linker options. This is required so that
`libunwind` can find the information generated by the compiler required for
stack unwinding.
Using `-static` is rare, though, so unless you know this will affect you it
probably won't.
## Alternative Stack-unwinder
If you cannot or do not wish to install `libunwind`, you can still try to use
two kinds of stack-unwinder:
### glibc Built-in Stack-unwinder
As we already mentioned, glibc's unwinder has a deadlock issue. However, if you
don't use `InstallFailureSignalHandler()` or you don't worry about the rare
possibilities of deadlocks, you can use this stack-unwinder. If you specify no
options and `libunwind` isn't detected on your system, the configure script
chooses this unwinder by default.
### Frame Pointer based Stack-unwinder
The frame pointer based stack unwinder requires that your application, the glog
library, and system libraries like libc, all be compiled with a frame pointer.
This is *not* the default for x86-64.

24
docs/usage.md Normal file
View File

@ -0,0 +1,24 @@
# Using glog in a CMake Project
Assuming that glog was previously [built using CMake](build.md#cmake) or
installed using a package manager, you can use the CMake command `#!cmake
find_package` to build against glog in your CMake project as follows:
``` cmake title="CMakeLists.txt"
cmake_minimum_required (VERSION 3.16)
project (myproj VERSION 1.0)
find_package (glog 0.8.0 REQUIRED)
add_executable (myapp main.cpp)
target_link_libraries (myapp glog::glog)
```
Compile definitions and options will be added automatically to your target as
needed.
Alternatively, glog can be incorporated into using the CMake command `#!cmake
add_subdirectory` to include glog directly from a subdirectory of your project
by replacing the `#!cmake find_package` call from the previous snippet by
`add_subdirectory`. The `#!cmake glog::glog` target is in this case an `#!cmake
ALIAS` library target for the `glog` library target.

44
docs/windows.md Normal file
View File

@ -0,0 +1,44 @@
# Notes for Windows Users
glog defines the severity level `ERROR`, which is also defined by `windows.h`.
You can make glog not define `INFO`, `WARNING`, `ERROR`, and `FATAL` by defining
`GLOG_NO_ABBREVIATED_SEVERITIES` before including `glog/logging.h`. Even with
this macro, you can still use the iostream like logging facilities:
``` cpp
#define GLOG_NO_ABBREVIATED_SEVERITIES
#include <windows.h>
#include <glog/logging.h>
// ...
LOG(ERROR) << "This should work";
LOG_IF(ERROR, x > y) << "This should be also OK";
```
However, you cannot use `INFO`, `WARNING`, `ERROR`, and `FATAL` anymore for
functions defined in `glog/logging.h`.
``` cpp
#define GLOG_NO_ABBREVIATED_SEVERITIES
#include <windows.h>
#include <glog/logging.h>
// ...
// This wont work.
// google::FlushLogFiles(google::ERROR);
// Use this instead.
google::FlushLogFiles(google::GLOG_ERROR);
```
If you don't need `ERROR` defined by `windows.h`, there are a couple of more
workarounds which sometimes don't work[^1]:
- `#!cpp #define WIN32_LEAN_AND_MEAN` or `NOGDI` **before**
`#!cpp #include <windows.h>`.
- `#!cpp #undef ERROR` **after** `#!cpp #include <windows.h>`.
[^1]: For more information refer to [this
issue](http://code.google.com/p/google-glog/issues/detail?id=33).

71
examples/custom_sink.cc Normal file
View File

@ -0,0 +1,71 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sergiu Deitsch
//
#include <glog/logging.h>
#include <algorithm>
#include <cstddef>
#include <iostream>
#include <iterator>
namespace {
struct MyLogSink : google::LogSink { // (1)!
void send(google::LogSeverity severity, const char* /*full_filename*/,
const char* base_filename, int line,
const google::LogMessageTime& /*time*/, const char* message,
std::size_t message_len) override {
std::cout << google::GetLogSeverityName(severity) << ' ' << base_filename
<< ':' << line << ' ';
std::copy_n(message, message_len,
std::ostreambuf_iterator<char>{std::cout});
std::cout << '\n';
}
};
} // namespace
int main(int /*argc*/, char** argv) {
google::InitGoogleLogging(argv[0]);
MyLogSink sink;
google::AddLogSink(&sink); // (2)!
LOG(INFO) << "logging to MySink";
google::RemoveLogSink(&sink); // (3)!
// We can directly log to a sink without registering it
LOG_TO_SINK(&sink, INFO) << "direct logging"; // (4)!
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, INFO)
<< "direct logging but not to file";
}

8
gcovr.cfg Normal file
View File

@ -0,0 +1,8 @@
exclude = src/.*_unittest\.cc
exclude = src/googletest\.h
exclude = src/mock-log\.h
exclude-directories = Tests/
exclude-throw-branches = yes
exclude-unreachable-branches = yes
filter = .*/glog/.*\.h
filter = src/

View File

@ -7,6 +7,8 @@ endif (CMAKE_VERSION VERSION_LESS @glog_CMake_VERSION@)
include (CMakeFindDependencyMacro) include (CMakeFindDependencyMacro)
include (${CMAKE_CURRENT_LIST_DIR}/glog-modules.cmake) include (${CMAKE_CURRENT_LIST_DIR}/glog-modules.cmake)
find_dependency (Threads)
@gflags_DEPENDENCY@ @gflags_DEPENDENCY@
@Unwind_DEPENDENCY@ @Unwind_DEPENDENCY@

123
mkdocs.yml Normal file
View File

@ -0,0 +1,123 @@
---
site_name: Google Logging Library
site_url: https://google.github.io/glog/
repo_url: https://github.com/google/glog
repo_name: google/glog
edit_uri: edit/master/docs/
copyright: Copyright &copy; 2024 Google Inc. &amp; contributors - <a href="#__consent">Change cookie settings</a>
markdown_extensions:
- admonition
- attr_list
- def_list
- footnotes
- md_in_html
- pymdownx.details
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.inlinehilite
- pymdownx.snippets:
base_path:
- '.'
check_paths: true
- pymdownx.superfences
- tables
- toc:
permalink: true
theme:
name: material
custom_dir: docs/overrides
icon:
annotation: material/chevron-right-circle
edit: material/pencil
repo: fontawesome/brands/git-alt
view: material/eye
language: en
features:
- content.action.edit
- content.code.annotate
- content.code.copy
- content.code.select
- header.autohide
- navigation.expand
- navigation.instant.preview
- navigation.instant.progress
- navigation.prune
- navigation.indexes
- toc.follow
- navigation.top
- navigation.path
# - navigation.sections
# - navigation.tabs
# - navigation.tabs.sticky
- navigation.tracking
- search.highlight
- search.share
- search.suggest
palette:
# Palette toggle for automatic mode
- media: "(prefers-color-scheme)"
toggle:
icon: material/brightness-auto
name: Switch to light mode
# Palette toggle for light mode
- media: "(prefers-color-scheme: light)"
scheme: default
primary: teal
accent: green
toggle:
icon: material/brightness-7
name: Switch to dark mode
# Palette toggle for dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: black
toggle:
icon: material/brightness-4
name: Switch to system preference
plugins:
- git-revision-date-localized:
enable_creation_date: true
- git-committers:
repository: google/glog
branch: master
- privacy
- search
- tags
extra:
version:
alias: true
default:
- dev
- stable
provider: mike
consent:
actions:
- manage
- accept
- reject
title: Cookie consent
description: >-
We use cookies to recognize your repeated visits and preferences, as well
as to measure the effectiveness of our documentation and whether users
find what they're searching for. With your consent, you're helping us to
make our documentation better.
nav:
- Getting Started:
- Overview: index.md
- Usage in CMake Projects: usage.md
- Building from Source: build.md
- Installation using Package Managers: packages.md
- User Guide:
- Logging: logging.md
- Adjusting Output: flags.md
- Custom Sinks: sinks.md
- Failure Handler: failures.md
- Log Removal: log_cleaner.md
- Stripping Log Messages: log_stripping.md
- System-specific Considerations:
- Usage on Windows: windows.md
- Linux Unwinder: unwinder.md
- Contributing: contribute.md
- License: license.md

View File

@ -48,67 +48,66 @@
#ifndef BASE_COMMANDLINEFLAGS_H__ #ifndef BASE_COMMANDLINEFLAGS_H__
#define BASE_COMMANDLINEFLAGS_H__ #define BASE_COMMANDLINEFLAGS_H__
#include "config.h" #include <cstdlib> // for getenv
#include <cstdlib> // for getenv #include <cstring> // for memchr
#include <cstring> // for memchr
#include <string> #include <string>
#ifdef HAVE_LIB_GFLAGS #include "config.h"
#include <gflags/gflags.h> #ifdef GLOG_USE_GFLAGS
# include <gflags/gflags.h>
#else #else
#include <glog/logging.h> # include "glog/logging.h"
#define DECLARE_VARIABLE(type, shorttype, name, tn) \ # define DECLARE_VARIABLE(type, shorttype, name, tn) \
namespace fL##shorttype { \ namespace fL##shorttype { \
extern GLOG_EXPORT type FLAGS_##name; \ extern GLOG_EXPORT type FLAGS_##name; \
} \ } \
using fL##shorttype::FLAGS_##name using fL##shorttype::FLAGS_##name
#define DEFINE_VARIABLE(type, shorttype, name, value, meaning, tn) \ # define DEFINE_VARIABLE(type, shorttype, name, value, meaning, tn) \
namespace fL##shorttype { \ namespace fL##shorttype { \
GLOG_EXPORT type FLAGS_##name(value); \ GLOG_EXPORT type FLAGS_##name(value); \
char FLAGS_no##name; \ char FLAGS_no##name; \
} \ } \
using fL##shorttype::FLAGS_##name using fL##shorttype::FLAGS_##name
// bool specialization // bool specialization
#define DECLARE_bool(name) \ # define DECLARE_bool(name) DECLARE_VARIABLE(bool, B, name, bool)
DECLARE_VARIABLE(bool, B, name, bool) # define DEFINE_bool(name, value, meaning) \
#define DEFINE_bool(name, value, meaning) \ DEFINE_VARIABLE(bool, B, name, value, meaning, bool)
DEFINE_VARIABLE(bool, B, name, value, meaning, bool)
// int32 specialization // int32 specialization
#define DECLARE_int32(name) \ # define DECLARE_int32(name) DECLARE_VARIABLE(google::int32, I, name, int32)
DECLARE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, int32) # define DEFINE_int32(name, value, meaning) \
#define DEFINE_int32(name, value, meaning) \ DEFINE_VARIABLE(google::int32, I, name, value, meaning, int32)
DEFINE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, value, meaning, int32)
// uint32 specialization // uint32 specialization
#ifndef DECLARE_uint32 # ifndef DECLARE_uint32
#define DECLARE_uint32(name) \ # define DECLARE_uint32(name) \
DECLARE_VARIABLE(GOOGLE_NAMESPACE::uint32, U, name, uint32) DECLARE_VARIABLE(google::uint32, U, name, uint32)
#endif // DECLARE_uint64 # endif // DECLARE_uint64
#define DEFINE_uint32(name, value, meaning) \ # define DEFINE_uint32(name, value, meaning) \
DEFINE_VARIABLE(GOOGLE_NAMESPACE::uint32, U, name, value, meaning, uint32) DEFINE_VARIABLE(google::uint32, U, name, value, meaning, uint32)
// Special case for string, because we have to specify the namespace // Special case for string, because we have to specify the namespace
// std::string, which doesn't play nicely with our FLAG__namespace hackery. // std::string, which doesn't play nicely with our FLAG__namespace hackery.
#define DECLARE_string(name) \ # define DECLARE_string(name) \
namespace fLS { \ namespace fLS { \
extern GLOG_EXPORT std::string& FLAGS_##name; \ extern GLOG_EXPORT std::string& FLAGS_##name; \
} \ } \
using fLS::FLAGS_##name using fLS::FLAGS_##name
#define DEFINE_string(name, value, meaning) \ # define DEFINE_string(name, value, meaning) \
namespace fLS { \ namespace fLS { \
std::string FLAGS_##name##_buf(value); \ std::string FLAGS_##name##_buf(value); \
GLOG_EXPORT std::string& FLAGS_##name = FLAGS_##name##_buf; \ GLOG_EXPORT std::string& FLAGS_##name = FLAGS_##name##_buf; \
char FLAGS_no##name; \ char FLAGS_no##name; \
} \ } \
using fLS::FLAGS_##name using fLS::FLAGS_##name
#endif // HAVE_LIB_GFLAGS #endif // GLOG_USE_GFLAGS
// Define GLOG_DEFINE_* using DEFINE_* . By using these macros, we // Define GLOG_DEFINE_* using DEFINE_* . By using these macros, we
// have GLOG_* environ variables even if we have gflags installed. // have GLOG_* environ variables even if we have gflags installed.
@ -132,16 +131,19 @@
// These macros (could be functions, but I don't want to bother with a .cc // These macros (could be functions, but I don't want to bother with a .cc
// file), make it easier to initialize flags from the environment. // file), make it easier to initialize flags from the environment.
#define EnvToString(envname, dflt) \ #define EnvToString(envname, dflt) (!getenv(envname) ? (dflt) : getenv(envname))
(!getenv(envname) ? (dflt) : getenv(envname))
#define EnvToBool(envname, dflt) \ #define EnvToBool(envname, dflt) \
(!getenv(envname) ? (dflt) : memchr("tTyY1\0", getenv(envname)[0], 6) != NULL) (!getenv(envname) ? (dflt) \
: memchr("tTyY1\0", getenv(envname)[0], 6) != nullptr)
#define EnvToInt(envname, dflt) \ #define EnvToInt(envname, dflt) \
(!getenv(envname) ? (dflt) : strtol(getenv(envname), NULL, 10)) (!getenv(envname) ? (dflt) \
: static_cast<int>(strtol(getenv(envname), nullptr, 10)))
#define EnvToUInt(envname, dflt) \ #define EnvToUInt(envname, dflt) \
(!getenv(envname) ? (dflt) : strtoul(getenv(envname), NULL, 10)) (!getenv(envname) \
? (dflt) \
: static_cast<unsigned>(strtoul(getenv(envname), nullptr, 10)))
#endif // BASE_COMMANDLINEFLAGS_H__ #endif // BASE_COMMANDLINEFLAGS_H__

View File

@ -1,10 +1,10 @@
// Copyright (c) 2008, Google Inc. // Copyright (c) 2008, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
// //
// * Redistributions of source code must retain the above copyright // * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer. // notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above // * Redistributions in binary form must reproduce the above
@ -14,7 +14,7 @@
// * Neither the name of Google Inc. nor the names of its // * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from // contributors may be used to endorse or promote products derived from
// this software without specific prior written permission. // this software without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@ -35,17 +35,15 @@
class GoogleInitializer { class GoogleInitializer {
public: public:
typedef void (*void_function)(void); using void_function = void (*)();
GoogleInitializer(const char*, void_function f) { GoogleInitializer(const char*, void_function f) { f(); }
f();
}
}; };
#define REGISTER_MODULE_INITIALIZER(name, body) \ #define REGISTER_MODULE_INITIALIZER(name, body) \
namespace { \ namespace { \
static void google_init_module_##name () { body; } \ static void google_init_module_##name() { body; } \
GoogleInitializer google_initializer_module_##name(#name, \ GoogleInitializer google_initializer_module_##name( \
google_init_module_##name); \ #name, google_init_module_##name); \
} }
#endif /* _GOOGLEINIT_H */ #endif /* _GOOGLEINIT_H */

View File

@ -1,333 +0,0 @@
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---
// Author: Craig Silverstein.
//
// A simple mutex wrapper, supporting locks and read-write locks.
// You should assume the locks are *not* re-entrant.
//
// To use: you should define the following macros in your configure.ac:
// ACX_PTHREAD
// AC_RWLOCK
// The latter is defined in ../autoconf.
//
// This class is meant to be internal-only and should be wrapped by an
// internal namespace. Before you use this module, please give the
// name of your internal namespace for this module. Or, if you want
// to expose it, you'll want to move it to the Google namespace. We
// cannot put this class in global namespace because there can be some
// problems when we have multiple versions of Mutex in each shared object.
//
// NOTE: by default, we have #ifdef'ed out the TryLock() method.
// This is for two reasons:
// 1) TryLock() under Windows is a bit annoying (it requires a
// #define to be defined very early).
// 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG
// mode.
// If you need TryLock(), and either these two caveats are not a
// problem for you, or you're willing to work around them, then
// feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs
// in the code below.
//
// CYGWIN NOTE: Cygwin support for rwlock seems to be buggy:
// http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html
// Because of that, we might as well use windows locks for
// cygwin. They seem to be more reliable than the cygwin pthreads layer.
//
// TRICKY IMPLEMENTATION NOTE:
// This class is designed to be safe to use during
// dynamic-initialization -- that is, by global constructors that are
// run before main() starts. The issue in this case is that
// dynamic-initialization happens in an unpredictable order, and it
// could be that someone else's dynamic initializer could call a
// function that tries to acquire this mutex -- but that all happens
// before this mutex's constructor has run. (This can happen even if
// the mutex and the function that uses the mutex are in the same .cc
// file.) Basically, because Mutex does non-trivial work in its
// constructor, it's not, in the naive implementation, safe to use
// before dynamic initialization has run on it.
//
// The solution used here is to pair the actual mutex primitive with a
// bool that is set to true when the mutex is dynamically initialized.
// (Before that it's false.) Then we modify all mutex routines to
// look at the bool, and not try to lock/unlock until the bool makes
// it to true (which happens after the Mutex constructor has run.)
//
// This works because before main() starts -- particularly, during
// dynamic initialization -- there are no threads, so a) it's ok that
// the mutex operations are a no-op, since we don't need locking then
// anyway; and b) we can be quite confident our bool won't change
// state between a call to Lock() and a call to Unlock() (that would
// require a global constructor in one translation unit to call Lock()
// and another global constructor in another translation unit to call
// Unlock() later, which is pretty perverse).
//
// That said, it's tricky, and can conceivably fail; it's safest to
// avoid trying to acquire a mutex in a global constructor, if you
// can. One way it can fail is that a really smart compiler might
// initialize the bool to true at static-initialization time (too
// early) rather than at dynamic-initialization time. To discourage
// that, we set is_safe_ to true in code (not the constructor
// colon-initializer) and set it to true via a function that always
// evaluates to true, but that the compiler can't know always
// evaluates to true. This should be good enough.
#ifndef GOOGLE_MUTEX_H_
#define GOOGLE_MUTEX_H_
#include "config.h" // to figure out pthreads support
#if defined(NO_THREADS)
typedef int MutexType; // to keep a lock-count
#elif defined(_WIN32) || defined(__CYGWIN__)
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN // We only need minimal includes
# endif
# ifdef GMUTEX_TRYLOCK
// We need Windows NT or later for TryEnterCriticalSection(). If you
// don't need that functionality, you can remove these _WIN32_WINNT
// lines, and change TryLock() to assert(0) or something.
# ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0400
# endif
# endif
// To avoid macro definition of ERROR.
# ifndef NOGDI
# define NOGDI
# endif
// To avoid macro definition of min/max.
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <windows.h>
typedef CRITICAL_SECTION MutexType;
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
// Needed for pthread_rwlock_*. If it causes problems, you could take it
// out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it
// *does* cause problems for FreeBSD, or MacOSX, but isn't needed
// for locking there.)
# ifdef __linux__
# ifndef _XOPEN_SOURCE // Some other header might have already set it for us.
# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
# endif
# endif
# include <pthread.h>
typedef pthread_rwlock_t MutexType;
#elif defined(HAVE_PTHREAD)
# include <pthread.h>
typedef pthread_mutex_t MutexType;
#else
# error Need to implement mutex.h for your architecture, or #define NO_THREADS
#endif
// We need to include these header files after defining _XOPEN_SOURCE
// as they may define the _XOPEN_SOURCE macro.
#include <cassert>
#include <cstdlib> // for abort()
#define MUTEX_NAMESPACE glog_internal_namespace_
namespace MUTEX_NAMESPACE {
class Mutex {
public:
// Create a Mutex that is not held by anybody. This constructor is
// typically used for Mutexes allocated on the heap or the stack.
// See below for a recommendation for constructing global Mutex
// objects.
inline Mutex();
// Destructor
inline ~Mutex();
inline void Lock(); // Block if needed until free then acquire exclusively
inline void Unlock(); // Release a lock acquired via Lock()
#ifdef GMUTEX_TRYLOCK
inline bool TryLock(); // If free, Lock() and return true, else return false
#endif
// Note that on systems that don't support read-write locks, these may
// be implemented as synonyms to Lock() and Unlock(). So you can use
// these for efficiency, but don't use them anyplace where being able
// to do shared reads is necessary to avoid deadlock.
inline void ReaderLock(); // Block until free or shared then acquire a share
inline void ReaderUnlock(); // Release a read share of this Mutex
inline void WriterLock() { Lock(); } // Acquire an exclusive lock
inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
// TODO(hamaji): Do nothing, implement correctly.
inline void AssertHeld() {}
private:
MutexType mutex_;
// We want to make sure that the compiler sets is_safe_ to true only
// when we tell it to, and never makes assumptions is_safe_ is
// always true. volatile is the most reliable way to do that.
volatile bool is_safe_;
inline void SetIsSafe() { is_safe_ = true; }
// Catch the error of writing Mutex when intending MutexLock.
Mutex(Mutex* /*ignored*/) {}
// Disallow "evil" constructors
Mutex(const Mutex&);
void operator=(const Mutex&);
};
// Now the implementation of Mutex for various systems
#if defined(NO_THREADS)
// When we don't have threads, we can be either reading or writing,
// but not both. We can have lots of readers at once (in no-threads
// mode, that's most likely to happen in recursive function calls),
// but only one writer. We represent this by having mutex_ be -1 when
// writing and a number > 0 when reading (and 0 when no lock is held).
//
// In debug mode, we assert these invariants, while in non-debug mode
// we do nothing, for efficiency. That's why everything is in an
// assert.
Mutex::Mutex() : mutex_(0) { }
Mutex::~Mutex() { assert(mutex_ == 0); }
void Mutex::Lock() { assert(--mutex_ == -1); }
void Mutex::Unlock() { assert(mutex_++ == -1); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
#endif
void Mutex::ReaderLock() { assert(++mutex_ > 0); }
void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
#elif defined(_WIN32) || defined(__CYGWIN__)
Mutex::Mutex() { InitializeCriticalSection(&mutex_); SetIsSafe(); }
Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return is_safe_ ?
TryEnterCriticalSection(&mutex_) != 0 : true; }
#endif
void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
void Mutex::ReaderUnlock() { Unlock(); }
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
} while (0)
Mutex::Mutex() {
SetIsSafe();
if (is_safe_ && pthread_rwlock_init(&mutex_, NULL) != 0) abort();
}
Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return is_safe_ ?
pthread_rwlock_trywrlock(&mutex_) == 0 :
true; }
#endif
void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
#undef SAFE_PTHREAD
#elif defined(HAVE_PTHREAD)
#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
} while (0)
Mutex::Mutex() {
SetIsSafe();
if (is_safe_ && pthread_mutex_init(&mutex_, NULL) != 0) abort();
}
Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return is_safe_ ?
pthread_mutex_trylock(&mutex_) == 0 : true; }
#endif
void Mutex::ReaderLock() { Lock(); }
void Mutex::ReaderUnlock() { Unlock(); }
#undef SAFE_PTHREAD
#endif
// --------------------------------------------------------------------------
// Some helper classes
// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
class MutexLock {
public:
explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
~MutexLock() { mu_->Unlock(); }
private:
Mutex * const mu_;
// Disallow "evil" constructors
MutexLock(const MutexLock&);
void operator=(const MutexLock&);
};
// ReaderMutexLock and WriterMutexLock do the same, for rwlocks
class ReaderMutexLock {
public:
explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
~ReaderMutexLock() { mu_->ReaderUnlock(); }
private:
Mutex * const mu_;
// Disallow "evil" constructors
ReaderMutexLock(const ReaderMutexLock&);
void operator=(const ReaderMutexLock&);
};
class WriterMutexLock {
public:
explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
~WriterMutexLock() { mu_->WriterUnlock(); }
private:
Mutex * const mu_;
// Disallow "evil" constructors
WriterMutexLock(const WriterMutexLock&);
void operator=(const WriterMutexLock&);
};
// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
#define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name)
#define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name)
#define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name)
} // namespace MUTEX_NAMESPACE
using namespace MUTEX_NAMESPACE;
#undef MUTEX_NAMESPACE
#endif /* #define GOOGLE_MUTEX_H__ */

View File

@ -1,4 +1,4 @@
// Copyright (c) 2021, Google Inc. // Copyright (c) 2024, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -27,23 +27,22 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <glog/logging.h>
#include <glog/raw_logging.h>
#include "base/commandlineflags.h" #include "base/commandlineflags.h"
#include "glog/logging.h"
#include "glog/raw_logging.h"
#include "googletest.h" #include "googletest.h"
#ifdef HAVE_LIB_GFLAGS #ifdef GLOG_USE_GFLAGS
#include <gflags/gflags.h> # include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE; using namespace GFLAGS_NAMESPACE;
#endif #endif
#ifdef HAVE_LIB_GMOCK #ifdef HAVE_LIB_GMOCK
#include <gmock/gmock.h> # include <gmock/gmock.h>
#include "mock-log.h" # include "mock-log.h"
// Introduce several symbols from gmock. // Introduce several symbols from gmock.
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog; using google::glog_testing::ScopedMockLog;
using testing::_; using testing::_;
using testing::AllOf; using testing::AllOf;
using testing::AnyNumber; using testing::AnyNumber;
@ -53,11 +52,12 @@ using testing::StrictMock;
using testing::StrNe; using testing::StrNe;
#endif #endif
using namespace GOOGLE_NAMESPACE; using namespace google;
TEST(CleanImmediately, logging) { TEST(CleanImmediately, logging) {
using namespace std::chrono_literals;
google::SetLogFilenameExtension(".foobar"); google::SetLogFilenameExtension(".foobar");
google::EnableLogCleaner(0); google::EnableLogCleaner(0h);
for (unsigned i = 0; i < 1000; ++i) { for (unsigned i = 0; i < 1000; ++i) {
LOG(INFO) << "cleanup test"; LOG(INFO) << "cleanup test";
@ -66,15 +66,15 @@ TEST(CleanImmediately, logging) {
google::DisableLogCleaner(); google::DisableLogCleaner();
} }
int main(int argc, char **argv) { int main(int argc, char** argv) {
FLAGS_colorlogtostderr = false; FLAGS_colorlogtostderr = false;
FLAGS_timestamp_in_logfile_name = true; FLAGS_timestamp_in_logfile_name = true;
#ifdef HAVE_LIB_GFLAGS #ifdef GLOG_USE_GFLAGS
ParseCommandLineFlags(&argc, &argv, true); ParseCommandLineFlags(&argc, &argv, true);
#endif #endif
// Make sure stderr is not buffered as stderr seems to be buffered // Make sure stderr is not buffered as stderr seems to be buffered
// on recent windows. // on recent windows.
setbuf(stderr, NULL); setbuf(stderr, nullptr);
// Test some basics before InitGoogleLogging: // Test some basics before InitGoogleLogging:
CaptureTestStderr(); CaptureTestStderr();

View File

@ -1,4 +1,4 @@
// Copyright (c) 2021, Google Inc. // Copyright (c) 2024, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -27,23 +27,22 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <glog/logging.h>
#include <glog/raw_logging.h>
#include "base/commandlineflags.h" #include "base/commandlineflags.h"
#include "glog/logging.h"
#include "glog/raw_logging.h"
#include "googletest.h" #include "googletest.h"
#ifdef HAVE_LIB_GFLAGS #ifdef GLOG_USE_GFLAGS
#include <gflags/gflags.h> # include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE; using namespace GFLAGS_NAMESPACE;
#endif #endif
#ifdef HAVE_LIB_GMOCK #ifdef HAVE_LIB_GMOCK
#include <gmock/gmock.h> # include <gmock/gmock.h>
#include "mock-log.h" # include "mock-log.h"
// Introduce several symbols from gmock. // Introduce several symbols from gmock.
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog; using google::glog_testing::ScopedMockLog;
using testing::_; using testing::_;
using testing::AllOf; using testing::AllOf;
using testing::AnyNumber; using testing::AnyNumber;
@ -53,10 +52,11 @@ using testing::StrictMock;
using testing::StrNe; using testing::StrNe;
#endif #endif
using namespace GOOGLE_NAMESPACE; using namespace google;
TEST(CleanImmediatelyWithAbsolutePrefix, logging) { TEST(CleanImmediatelyWithAbsolutePrefix, logging) {
google::EnableLogCleaner(0); using namespace std::chrono_literals;
google::EnableLogCleaner(0h);
google::SetLogFilenameExtension(".barfoo"); google::SetLogFilenameExtension(".barfoo");
google::SetLogDestination(GLOG_INFO, "test_cleanup_"); google::SetLogDestination(GLOG_INFO, "test_cleanup_");
@ -71,15 +71,15 @@ TEST(CleanImmediatelyWithAbsolutePrefix, logging) {
google::DisableLogCleaner(); google::DisableLogCleaner();
} }
int main(int argc, char **argv) { int main(int argc, char** argv) {
FLAGS_colorlogtostderr = false; FLAGS_colorlogtostderr = false;
FLAGS_timestamp_in_logfile_name = true; FLAGS_timestamp_in_logfile_name = true;
#ifdef HAVE_LIB_GFLAGS #ifdef GLOG_USE_GFLAGS
ParseCommandLineFlags(&argc, &argv, true); ParseCommandLineFlags(&argc, &argv, true);
#endif #endif
// Make sure stderr is not buffered as stderr seems to be buffered // Make sure stderr is not buffered as stderr seems to be buffered
// on recent windows. // on recent windows.
setbuf(stderr, NULL); setbuf(stderr, nullptr);
// Test some basics before InitGoogleLogging: // Test some basics before InitGoogleLogging:
CaptureTestStderr(); CaptureTestStderr();

View File

@ -1,4 +1,4 @@
// Copyright (c) 2021, Google Inc. // Copyright (c) 2024, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -27,23 +27,22 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <glog/logging.h>
#include <glog/raw_logging.h>
#include "base/commandlineflags.h" #include "base/commandlineflags.h"
#include "glog/logging.h"
#include "glog/raw_logging.h"
#include "googletest.h" #include "googletest.h"
#ifdef HAVE_LIB_GFLAGS #ifdef GLOG_USE_GFLAGS
#include <gflags/gflags.h> # include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE; using namespace GFLAGS_NAMESPACE;
#endif #endif
#ifdef HAVE_LIB_GMOCK #ifdef HAVE_LIB_GMOCK
#include <gmock/gmock.h> # include <gmock/gmock.h>
#include "mock-log.h" # include "mock-log.h"
// Introduce several symbols from gmock. // Introduce several symbols from gmock.
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog; using google::glog_testing::ScopedMockLog;
using testing::_; using testing::_;
using testing::AllOf; using testing::AllOf;
using testing::AnyNumber; using testing::AnyNumber;
@ -53,10 +52,11 @@ using testing::StrictMock;
using testing::StrNe; using testing::StrNe;
#endif #endif
using namespace GOOGLE_NAMESPACE; using namespace google;
TEST(CleanImmediatelyWithRelativePrefix, logging) { TEST(CleanImmediatelyWithRelativePrefix, logging) {
google::EnableLogCleaner(0); using namespace std::chrono_literals;
google::EnableLogCleaner(0h);
google::SetLogFilenameExtension(".relativefoo"); google::SetLogFilenameExtension(".relativefoo");
google::SetLogDestination(GLOG_INFO, "test_subdir/test_cleanup_"); google::SetLogDestination(GLOG_INFO, "test_subdir/test_cleanup_");
@ -67,15 +67,15 @@ TEST(CleanImmediatelyWithRelativePrefix, logging) {
google::DisableLogCleaner(); google::DisableLogCleaner();
} }
int main(int argc, char **argv) { int main(int argc, char** argv) {
FLAGS_colorlogtostderr = false; FLAGS_colorlogtostderr = false;
FLAGS_timestamp_in_logfile_name = true; FLAGS_timestamp_in_logfile_name = true;
#ifdef HAVE_LIB_GFLAGS #ifdef GLOG_USE_GFLAGS
ParseCommandLineFlags(&argc, &argv, true); ParseCommandLineFlags(&argc, &argv, true);
#endif #endif
// Make sure stderr is not buffered as stderr seems to be buffered // Make sure stderr is not buffered as stderr seems to be buffered
// on recent windows. // on recent windows.
setbuf(stderr, NULL); setbuf(stderr, nullptr);
// Test some basics before InitGoogleLogging: // Test some basics before InitGoogleLogging:
CaptureTestStderr(); CaptureTestStderr();

View File

@ -1,23 +1,17 @@
#ifndef GLOG_CONFIG_H #ifndef GLOG_CONFIG_H
#define GLOG_CONFIG_H #define GLOG_CONFIG_H
/* define if glog doesn't use RTTI */
#cmakedefine DISABLE_RTTI
/* Namespace for Google classes */
#cmakedefine GOOGLE_NAMESPACE ${GOOGLE_NAMESPACE}
/* Define if you have the `dladdr' function */ /* Define if you have the `dladdr' function */
#cmakedefine HAVE_DLADDR #cmakedefine HAVE_DLADDR
/* Define if you have the `snprintf' function */
#cmakedefine HAVE_SNPRINTF
/* Define to 1 if you have the <dlfcn.h> header file. */ /* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_DLFCN_H #cmakedefine HAVE_DLFCN_H
/* Define to 1 if you have the <execinfo.h> header file. */ /* Define if you have the `backtrace' function in <execinfo.h> */
#cmakedefine HAVE_EXECINFO_H #cmakedefine HAVE_EXECINFO_BACKTRACE
/* Define if you have the `backtrace_symbols' function in <execinfo.h> */
#cmakedefine HAVE_EXECINFO_BACKTRACE_SYMBOLS
/* Define if you have the `fcntl' function */ /* Define if you have the `fcntl' function */
#cmakedefine HAVE_FCNTL #cmakedefine HAVE_FCNTL
@ -25,15 +19,6 @@
/* Define to 1 if you have the <glob.h> header file. */ /* Define to 1 if you have the <glob.h> header file. */
#cmakedefine HAVE_GLOB_H #cmakedefine HAVE_GLOB_H
/* Define to 1 if you have the <inttypes.h> header file. */
#cmakedefine HAVE_INTTYPES_H ${HAVE_INTTYPES_H}
/* Define to 1 if you have the `pthread' library (-lpthread). */
#cmakedefine HAVE_LIBPTHREAD
/* define if you have google gflags library */
#cmakedefine HAVE_LIB_GFLAGS
/* define if you have google gmock library */ /* define if you have google gmock library */
#cmakedefine HAVE_LIB_GMOCK #cmakedefine HAVE_LIB_GMOCK
@ -43,23 +28,11 @@
/* define if you have dbghelp library */ /* define if you have dbghelp library */
#cmakedefine HAVE_DBGHELP #cmakedefine HAVE_DBGHELP
/* define if you have libunwind */
#cmakedefine HAVE_LIB_UNWIND
/* Define to 1 if you have the <memory.h> header file. */
#cmakedefine HAVE_MEMORY_H
/* define to disable multithreading support. */
#cmakedefine NO_THREADS
/* define if the compiler implements namespaces */
#cmakedefine HAVE_NAMESPACES
/* Define if you have the 'pread' function */ /* Define if you have the 'pread' function */
#cmakedefine HAVE_PREAD #cmakedefine HAVE_PREAD
/* Define if you have POSIX threads libraries and header files. */ /* Define if you have the 'posix_fadvise' function in <fcntl.h> */
#cmakedefine HAVE_PTHREAD #cmakedefine HAVE_POSIX_FADVISE
/* Define to 1 if you have the <pwd.h> header file. */ /* Define to 1 if you have the <pwd.h> header file. */
#cmakedefine HAVE_PWD_H #cmakedefine HAVE_PWD_H
@ -67,29 +40,26 @@
/* Define if you have the 'pwrite' function */ /* Define if you have the 'pwrite' function */
#cmakedefine HAVE_PWRITE #cmakedefine HAVE_PWRITE
/* define if the compiler implements pthread_rwlock_* */
#cmakedefine HAVE_RWLOCK
/* Define if you have the 'sigaction' function */ /* Define if you have the 'sigaction' function */
#cmakedefine HAVE_SIGACTION #cmakedefine HAVE_SIGACTION
/* Define if you have the `sigaltstack' function */ /* Define if you have the `sigaltstack' function */
#cmakedefine HAVE_SIGALTSTACK #cmakedefine HAVE_SIGALTSTACK
/* Define to 1 if you have the <stdint.h> header file. */
#cmakedefine HAVE_STDINT_H ${HAVE_STDINT_H}
/* Define to 1 if you have the <strings.h> header file. */
#cmakedefine HAVE_STRINGS_H
/* Define to 1 if you have the <syscall.h> header file. */ /* Define to 1 if you have the <syscall.h> header file. */
#cmakedefine HAVE_SYSCALL_H #cmakedefine HAVE_SYSCALL_H
/* Define to 1 if you have the <syslog.h> header file. */ /* Define to 1 if you have the <syslog.h> header file. */
#cmakedefine HAVE_SYSLOG_H #cmakedefine HAVE_SYSLOG_H
/* Define to 1 if you have the <sys/stat.h> header file. */ /* Define to 1 if you have the <elf.h> header file. */
#cmakedefine HAVE_SYS_STAT_H #cmakedefine HAVE_ELF_H
/* Define to 1 if you have the <sys/exec_elf.h> header file. */
#cmakedefine HAVE_SYS_EXEC_ELF_H
/* Define to 1 if you have the <link.h> header file. */
#cmakedefine HAVE_LINK_H
/* Define to 1 if you have the <sys/syscall.h> header file. */ /* Define to 1 if you have the <sys/syscall.h> header file. */
#cmakedefine HAVE_SYS_SYSCALL_H #cmakedefine HAVE_SYS_SYSCALL_H
@ -98,7 +68,7 @@
#cmakedefine HAVE_SYS_TIME_H #cmakedefine HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */ /* Define to 1 if you have the <sys/types.h> header file. */
#cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H} #cmakedefine HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/ucontext.h> header file. */ /* Define to 1 if you have the <sys/ucontext.h> header file. */
#cmakedefine HAVE_SYS_UCONTEXT_H #cmakedefine HAVE_SYS_UCONTEXT_H
@ -115,23 +85,11 @@
/* Define to 1 if you have the <unistd.h> header file. */ /* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H} #cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H}
/* Define if you have the <unwind.h> header file. */ /* define if you have unwind */
#cmakedefine HAVE_UNWIND_H #cmakedefine HAVE_UNWIND
/* Define if you linking to _Unwind_Backtrace is possible. */ /* define if you have libunwind */
#cmakedefine HAVE__UNWIND_BACKTRACE #cmakedefine HAVE_LIBUNWIND
/* define if the compiler supports using expression for operator */
#cmakedefine HAVE_USING_OPERATOR
/* define if your compiler has __attribute__ */
#cmakedefine HAVE___ATTRIBUTE__
/* define if your compiler has __builtin_expect */
#cmakedefine HAVE___BUILTIN_EXPECT ${HAVE___BUILTIN_EXPECT}
/* define if your compiler has __sync_val_compare_and_swap */
#cmakedefine HAVE___SYNC_VAL_COMPARE_AND_SWAP
/* define if symbolize support is available */ /* define if symbolize support is available */
#cmakedefine HAVE_SYMBOLIZE #cmakedefine HAVE_SYMBOLIZE
@ -142,90 +100,43 @@
/* define if gmtime_r is available in time.h */ /* define if gmtime_r is available in time.h */
#cmakedefine HAVE_GMTIME_R #cmakedefine HAVE_GMTIME_R
/* Define to the sub-directory in which libtool stores uninstalled libraries. /* define if _chsize_s is available in io.h */
*/ #cmakedefine HAVE__CHSIZE_S
#cmakedefine LT_OBJDIR
/* Name of package */ /* define if ssize_t is defined */
#cmakedefine PACKAGE #cmakedefine HAVE_SSIZE_T
/* Define to the address where bug reports for this package should be sent. */ /* define if mode_t is defined */
#cmakedefine PACKAGE_BUGREPORT #cmakedefine HAVE_MODE_T
/* Define to the full name of this package. */
#cmakedefine PACKAGE_NAME
/* Define to the full name and version of this package. */
#cmakedefine PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#cmakedefine PACKAGE_TARNAME
/* Define to the home page for this package. */
#cmakedefine PACKAGE_URL
/* Define to the version of this package. */
#cmakedefine PACKAGE_VERSION
/* How to access the PC from a struct ucontext */ /* How to access the PC from a struct ucontext */
#cmakedefine PC_FROM_UCONTEXT #cmakedefine PC_FROM_UCONTEXT ${PC_FROM_UCONTEXT}
/* define if we should print file offsets in traces instead of symbolizing. */ /* define if we should print file offsets in traces instead of symbolizing. */
#cmakedefine PRINT_UNSYMBOLIZED_STACK_TRACES #cmakedefine PRINT_UNSYMBOLIZED_STACK_TRACES
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#cmakedefine PTHREAD_CREATE_JOINABLE
/* The size of `void *', as computed by sizeof. */ /* The size of `void *', as computed by sizeof. */
#cmakedefine SIZEOF_VOID_P ${SIZEOF_VOID_P} #cmakedefine SIZEOF_VOID_P ${SIZEOF_VOID_P}
/* Define to 1 if you have the ANSI C header files. */
#cmakedefine STDC_HEADERS
/* the namespace where STL code like vector<> is defined */
#cmakedefine STL_NAMESPACE ${STL_NAMESPACE}
/* location of source code */ /* location of source code */
#cmakedefine TEST_SRC_DIR ${TEST_SRC_DIR} #cmakedefine TEST_SRC_DIR ${TEST_SRC_DIR}
/* Define to necessary thread-local storage attribute. */ /* Define if thread-local storage is enabled. */
#cmakedefine GLOG_THREAD_LOCAL_STORAGE ${GLOG_THREAD_LOCAL_STORAGE} #cmakedefine GLOG_THREAD_LOCAL_STORAGE
/* Check whether aligned_storage and alignof present */ /* define if abi::__cxa_demangle is available in cxxabi.h */
#cmakedefine HAVE_ALIGNED_STORAGE ${HAVE_ALIGNED_STORAGE} #cmakedefine HAVE___CXA_DEMANGLE
/* Check whether C++11 atomic is available */ /* define if __argv is available in cstdlib */
#cmakedefine HAVE_CXX11_ATOMIC ${HAVE_CXX11_ATOMIC} #cmakedefine HAVE___ARGV
/* Check whether C++11 chrono is available */ /* define if __progname is available */
#cmakedefine HAVE_CXX11_CHRONO ${HAVE_CXX11_CHRONO} #cmakedefine HAVE___PROGNAME
/* Check whether C++11 nullptr_t is available */ /* define if getprogname is available in cstdlib */
#cmakedefine HAVE_CXX11_NULLPTR_T ${HAVE_CXX11_NULLPTR_T} #cmakedefine HAVE_GETPROGNAME
/* Version number of package */ /* define if program_invocation_short_name is available in cerrno */
#cmakedefine VERSION #cmakedefine HAVE_PROGRAM_INVOCATION_SHORT_NAME
#ifdef GLOG_BAZEL_BUILD
/* TODO(rodrigoq): remove this workaround once bazel#3979 is resolved:
* https://github.com/bazelbuild/bazel/issues/3979 */
#define _START_GOOGLE_NAMESPACE_ namespace GOOGLE_NAMESPACE {
#define _END_GOOGLE_NAMESPACE_ }
#else
/* Stops putting the code inside the Google namespace */
#cmakedefine _END_GOOGLE_NAMESPACE_ ${_END_GOOGLE_NAMESPACE_}
/* Puts following code inside the Google namespace */
#cmakedefine _START_GOOGLE_NAMESPACE_ ${_START_GOOGLE_NAMESPACE_}
#endif
/* Replacement for deprecated syscall(SYS_gettid) on macOS. */
#cmakedefine HAVE_PTHREAD_THREADID_NP ${HAVE_PTHREAD_THREADID_NP}
#endif // GLOG_CONFIG_H #endif // GLOG_CONFIG_H

View File

@ -0,0 +1,7 @@
cmake_minimum_required (VERSION 3.16)
project (glog_log_severity LANGUAGES CXX)
find_package (glog REQUIRED NO_MODULE)
add_executable (glog_dcheck glog_dcheck.cc)
target_link_libraries (glog_dcheck PRIVATE glog::glog)

View File

@ -0,0 +1,53 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sergiu Deitsch
#include <glog/logging.h>
int main(int /*argc*/, char** argv) {
google::InitGoogleLogging(argv[0]);
google::InstallFailureSignalHandler();
#if defined(_MSC_VER)
// Avoid presenting an interactive dialog that will cause the test to time
// out.
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif // defined(_MSC_VER)
DLOG(INFO) << "no output";
DLOG(WARNING) << "no output";
DLOG(ERROR) << "no output";
// Must not fail in release build
DLOG_ASSERT(false);
// Must be the last expression
DLOG(FATAL) << "no output";
}

File diff suppressed because it is too large Load Diff

View File

@ -67,19 +67,28 @@
// C++ ABI in the future. // C++ ABI in the future.
// //
#ifndef BASE_DEMANGLE_H_ #ifndef GLOG_INTERNAL_DEMANGLE_H
#define BASE_DEMANGLE_H_ #define GLOG_INTERNAL_DEMANGLE_H
#include "config.h" #include <cstddef>
#include <glog/logging.h>
_START_GOOGLE_NAMESPACE_ #if defined(GLOG_USE_GLOG_EXPORT)
# include "glog/export.h"
#endif
#if !defined(GLOG_NO_EXPORT)
# error "demangle.h" was not included correctly.
#endif
namespace google {
inline namespace glog_internal_namespace_ {
// Demangle "mangled". On success, return true and write the // Demangle "mangled". On success, return true and write the
// demangled symbol name to "out". Otherwise, return false. // demangled symbol name to "out". Otherwise, return false.
// "out" is modified even if demangling is unsuccessful. // "out" is modified even if demangling is unsuccessful.
bool GLOG_EXPORT Demangle(const char *mangled, char *out, size_t out_size); bool GLOG_NO_EXPORT Demangle(const char* mangled, char* out, size_t out_size);
_END_GOOGLE_NAMESPACE_ } // namespace glog_internal_namespace_
} // namespace google
#endif // BASE_DEMANGLE_H_ #endif // GLOG_INTERNAL_DEMANGLE_H

View File

@ -31,18 +31,19 @@
// //
// Unit tests for functions in demangle.c. // Unit tests for functions in demangle.c.
#include "demangle.h"
#include <fstream>
#include <iostream>
#include <string>
#include "config.h"
#include "glog/logging.h"
#include "googletest.h"
#include "utilities.h" #include "utilities.h"
#include <iostream> #ifdef GLOG_USE_GFLAGS
#include <fstream> # include <gflags/gflags.h>
#include <string>
#include <glog/logging.h>
#include "demangle.h"
#include "googletest.h"
#include "config.h"
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE; using namespace GFLAGS_NAMESPACE;
#endif #endif
@ -50,10 +51,10 @@ GLOG_DEFINE_bool(demangle_filter, false,
"Run demangle_unittest in filter mode"); "Run demangle_unittest in filter mode");
using namespace std; using namespace std;
using namespace GOOGLE_NAMESPACE; using namespace google;
// A wrapper function for Demangle() to make the unit test simple. // A wrapper function for Demangle() to make the unit test simple.
static const char *DemangleIt(const char * const mangled) { static const char* DemangleIt(const char* const mangled) {
static char demangled[4096]; static char demangled[4096];
if (Demangle(mangled, demangled, sizeof(demangled))) { if (Demangle(mangled, demangled, sizeof(demangled))) {
return demangled; return demangled;
@ -64,28 +65,25 @@ static const char *DemangleIt(const char * const mangled) {
#if defined(GLOG_OS_WINDOWS) #if defined(GLOG_OS_WINDOWS)
#if defined(HAVE_DBGHELP) && !defined(NDEBUG) # if defined(HAVE_DBGHELP) && !defined(NDEBUG)
TEST(Demangle, Windows) { TEST(Demangle, Windows) {
EXPECT_STREQ( EXPECT_STREQ("public: static void __cdecl Foo::func(int)",
"public: static void __cdecl Foo::func(int)", DemangleIt("?func@Foo@@SAXH@Z"));
DemangleIt("?func@Foo@@SAXH@Z")); EXPECT_STREQ("public: static void __cdecl Foo::func(int)",
EXPECT_STREQ( DemangleIt("@ILT+1105(?func@Foo@@SAXH@Z)"));
"public: static void __cdecl Foo::func(int)", EXPECT_STREQ("int __cdecl foobarArray(int * const)",
DemangleIt("@ILT+1105(?func@Foo@@SAXH@Z)")); DemangleIt("?foobarArray@@YAHQAH@Z"));
EXPECT_STREQ(
"int __cdecl foobarArray(int * const)",
DemangleIt("?foobarArray@@YAHQAH@Z"));
} }
#endif # endif
#else #else
// Test corner cases of bounary conditions. // Test corner cases of boundary conditions.
TEST(Demangle, CornerCases) { TEST(Demangle, CornerCases) {
const size_t size = 10; const size_t size = 10;
char tmp[size] = { 0 }; char tmp[size] = {0};
const char *demangled = "foobar()"; const char* demangled = "foobar()";
const char *mangled = "_Z6foobarv"; const char* mangled = "_Z6foobarv";
EXPECT_TRUE(Demangle(mangled, tmp, sizeof(tmp))); EXPECT_TRUE(Demangle(mangled, tmp, sizeof(tmp)));
// sizeof("foobar()") == size - 1 // sizeof("foobar()") == size - 1
EXPECT_STREQ(demangled, tmp); EXPECT_STREQ(demangled, tmp);
@ -94,7 +92,7 @@ TEST(Demangle, CornerCases) {
EXPECT_FALSE(Demangle(mangled, tmp, size - 2)); // Not enough. EXPECT_FALSE(Demangle(mangled, tmp, size - 2)); // Not enough.
EXPECT_FALSE(Demangle(mangled, tmp, 1)); EXPECT_FALSE(Demangle(mangled, tmp, 1));
EXPECT_FALSE(Demangle(mangled, tmp, 0)); EXPECT_FALSE(Demangle(mangled, tmp, 0));
EXPECT_FALSE(Demangle(mangled, NULL, 0)); // Should not cause SEGV. EXPECT_FALSE(Demangle(mangled, nullptr, 0)); // Should not cause SEGV.
} }
// Test handling of functions suffixed with .clone.N, which is used by GCC // Test handling of functions suffixed with .clone.N, which is used by GCC
@ -146,11 +144,11 @@ TEST(Demangle, FromFile) {
#endif #endif
int main(int argc, char **argv) { int main(int argc, char** argv) {
#ifdef HAVE_LIB_GFLAGS InitGoogleTest(&argc, argv);
#ifdef GLOG_USE_GFLAGS
ParseCommandLineFlags(&argc, &argv, true); ParseCommandLineFlags(&argc, &argv, true);
#endif #endif
InitGoogleTest(&argc, argv);
FLAGS_logtostderr = true; FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]); InitGoogleLogging(argv[0]);

View File

@ -143,3 +143,10 @@ _Zrm1XS_ operator%()
# Template argument packs can start with I or J. # Template argument packs can start with I or J.
_Z3addIIiEEvDpT_ add<>() _Z3addIIiEEvDpT_ add<>()
_Z3addIJiEEvDpT_ add<>() _Z3addIJiEEvDpT_ add<>()
# Nested templates with pack expansion
_ZSt13__invoke_implIvPFvPiEJDnEET_St14__invoke_otherOT0_DpOT1_ std::__invoke_impl<>()
_ZSt8__invokeIPFvPiEJDnEENSt15__invoke_resultIT_JDpT0_EE4typeEOS4_DpOS5_ std::__invoke<>()
_ZNSt6thread8_InvokerISt5tupleIJPFvPiEDnEEE9_M_invokeIJLm0ELm1EEEEvSt12_Index_tupleIJXspT_EEE std::thread::_Invoker<>::_M_invoke<>()
_ZNSt6thread8_InvokerISt5tupleIJPFvPiEDnEEEclEv std::thread::_Invoker<>::operator()()
_ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJPFvPiEDnEEEEE6_M_runEv std::thread::_State_impl<>::_M_run()

158
src/flags.cc Normal file
View File

@ -0,0 +1,158 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "glog/flags.h"
#include <cstdlib>
#include <cstring>
#include "base/commandlineflags.h"
#include "glog/log_severity.h"
namespace {
// Compute the default value for --log_dir
static const char* DefaultLogDir() {
constexpr const char* const names[]{"GOOGLE_LOG_DIR", "TEST_TMPDIR"};
for (const char* const name : names) {
const char* const env = std::getenv(name);
if (env != nullptr && env[0] != '\0') {
return env;
}
}
return "";
}
bool BoolFromEnv(const char* varname, bool defval) {
const char* const valstr = getenv(varname);
if (!valstr) {
return defval;
}
return std::memchr("tTyY1\0", valstr[0], 6) != nullptr;
}
} // namespace
GLOG_DEFINE_bool(timestamp_in_logfile_name,
BoolFromEnv("GOOGLE_TIMESTAMP_IN_LOGFILE_NAME", true),
"put a timestamp at the end of the log file name");
GLOG_DEFINE_bool(logtostderr, BoolFromEnv("GOOGLE_LOGTOSTDERR", false),
"log messages go to stderr instead of logfiles");
GLOG_DEFINE_bool(alsologtostderr, BoolFromEnv("GOOGLE_ALSOLOGTOSTDERR", false),
"log messages go to stderr in addition to logfiles");
GLOG_DEFINE_bool(colorlogtostderr, false,
"color messages logged to stderr (if supported by terminal)");
GLOG_DEFINE_bool(colorlogtostdout, false,
"color messages logged to stdout (if supported by terminal)");
GLOG_DEFINE_bool(logtostdout, BoolFromEnv("GOOGLE_LOGTOSTDOUT", false),
"log messages go to stdout instead of logfiles");
#ifdef GLOG_OS_LINUX
GLOG_DEFINE_bool(
drop_log_memory, true,
"Drop in-memory buffers of log contents. "
"Logs can grow very quickly and they are rarely read before they "
"need to be evicted from memory. Instead, drop them from memory "
"as soon as they are flushed to disk.");
#endif
// By default, errors (including fatal errors) get logged to stderr as
// well as the file.
//
// The default is ERROR instead of FATAL so that users can see problems
// when they run a program without having to look in another file.
GLOG_DEFINE_int32(
stderrthreshold, google::GLOG_ERROR,
"log messages at or above this level are copied to stderr in "
"addition to logfiles. This flag obsoletes --alsologtostderr.");
GLOG_DEFINE_string(alsologtoemail, "",
"log messages go to these email addresses "
"in addition to logfiles");
GLOG_DEFINE_bool(log_file_header, true,
"Write the file header at the start of each log file");
GLOG_DEFINE_bool(log_prefix, true,
"Prepend the log prefix to the start of each log line");
GLOG_DEFINE_bool(log_year_in_prefix, true,
"Include the year in the log prefix");
GLOG_DEFINE_int32(minloglevel, 0,
"Messages logged at a lower level than this don't "
"actually get logged anywhere");
GLOG_DEFINE_int32(logbuflevel, 0,
"Buffer log messages logged at this level or lower"
" (-1 means don't buffer; 0 means buffer INFO only;"
" ...)");
GLOG_DEFINE_int32(logbufsecs, 30,
"Buffer log messages for at most this many seconds");
GLOG_DEFINE_int32(logcleansecs, 60 * 5, // every 5 minutes
"Clean overdue logs every this many seconds");
GLOG_DEFINE_int32(logemaillevel, 999,
"Email log messages logged at this level or higher"
" (0 means email all; 3 means email FATAL only;"
" ...)");
GLOG_DEFINE_string(logmailer, "", "Mailer used to send logging email");
GLOG_DEFINE_int32(logfile_mode, 0664, "Log file mode/permissions.");
GLOG_DEFINE_string(
log_dir, DefaultLogDir(),
"If specified, logfiles are written into this directory instead "
"of the default logging directory.");
GLOG_DEFINE_string(log_link, "",
"Put additional links to the log "
"files in this directory");
GLOG_DEFINE_uint32(max_log_size, 1800,
"approx. maximum log file size (in MB). A value of 0 will "
"be silently overridden to 1.");
GLOG_DEFINE_bool(stop_logging_if_full_disk, false,
"Stop attempting to log to disk if the disk is full.");
GLOG_DEFINE_string(log_backtrace_at, "",
"Emit a backtrace when logging at file:linenum.");
GLOG_DEFINE_bool(log_utc_time, false, "Use UTC time for logging.");
GLOG_DEFINE_int32(v, 0,
"Show all VLOG(m) messages for m <= this."
" Overridable by --vmodule.");
GLOG_DEFINE_string(
vmodule, "",
"per-module verbose level."
" Argument is a comma-separated list of <module name>=<log level>."
" <module name> is a glob pattern, matched against the filename base"
" (that is, name ignoring .cc/.h./-inl.h)."
" <log level> overrides any value given by --v.");
GLOG_DEFINE_bool(symbolize_stacktrace, true,
"Symbolize the stack trace in the tombstone");

32
src/fuzz_demangle.cc Normal file
View File

@ -0,0 +1,32 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
#include <cstring>
#include "demangle.h"
extern "C" int LLVMFuzzerTestOneInput(const unsigned char* Data,
unsigned Size) {
if (Size >= 4095) {
return 0;
}
char Buffer[Size + 1];
std::memcpy(Buffer, Data, Size);
Buffer[Size] = 0;
char demangled[4096];
google::Demangle(Buffer, demangled, Size);
return 0;
}

191
src/glog/flags.h Normal file
View File

@ -0,0 +1,191 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#ifndef GLOG_FLAGS_H
#define GLOG_FLAGS_H
#include <string>
#if defined(GLOG_USE_GFLAGS)
# include <gflags/gflags.h>
#endif
#if defined(GLOG_USE_GLOG_EXPORT)
# include "glog/export.h"
#endif
#if !defined(GLOG_EXPORT)
# error <glog/flags.h> was not included correctly. See the documentation for how to consume the library.
#endif
#include "glog/platform.h"
#include "glog/types.h"
#pragma push_macro("DECLARE_VARIABLE")
#pragma push_macro("DECLARE_bool")
#pragma push_macro("DECLARE_string")
#pragma push_macro("DECLARE_int32")
#pragma push_macro("DECLARE_uint32")
#ifdef DECLARE_VARIABLE
# undef DECLARE_VARIABLE
#endif
#ifdef DECLARE_bool
# undef DECLARE_bool
#endif
#ifdef DECLARE_string
# undef DECLARE_string
#endif
#ifdef DECLARE_int32
# undef DECLARE_int32
#endif
#ifdef DECLARE_uint32
# undef DECLARE_uint32
#endif
#ifndef DECLARE_VARIABLE
# define DECLARE_VARIABLE(type, shorttype, name, tn) \
namespace fL##shorttype { \
extern GLOG_EXPORT type FLAGS_##name; \
} \
using fL##shorttype::FLAGS_##name
// bool specialization
# define DECLARE_bool(name) DECLARE_VARIABLE(bool, B, name, bool)
// int32 specialization
# define DECLARE_int32(name) DECLARE_VARIABLE(google::int32, I, name, int32)
# if !defined(DECLARE_uint32)
// uint32 specialization
# define DECLARE_uint32(name) \
DECLARE_VARIABLE(google::uint32, U, name, uint32)
# endif // !defined(DECLARE_uint32) && !defined(GLOG_USE_GFLAGS)
// Special case for string, because we have to specify the namespace
// std::string, which doesn't play nicely with our FLAG__namespace hackery.
# define DECLARE_string(name) \
namespace fLS { \
extern GLOG_EXPORT std::string& FLAGS_##name; \
} \
using fLS::FLAGS_##name
#endif
DECLARE_int32(logemaillevel);
DECLARE_int32(logcleansecs);
#ifdef GLOG_OS_LINUX
DECLARE_bool(drop_log_memory);
#endif
DECLARE_string(alsologtoemail);
DECLARE_string(log_backtrace_at);
// Set whether appending a timestamp to the log file name
DECLARE_bool(timestamp_in_logfile_name);
// Set whether log messages go to stdout instead of logfiles
DECLARE_bool(logtostdout);
// Set color messages logged to stdout (if supported by terminal).
DECLARE_bool(colorlogtostdout);
// Set whether log messages go to stderr instead of logfiles
DECLARE_bool(logtostderr);
// Set whether log messages go to stderr in addition to logfiles.
DECLARE_bool(alsologtostderr);
// Set color messages logged to stderr (if supported by terminal).
DECLARE_bool(colorlogtostderr);
// Log messages at a level >= this flag are automatically sent to
// stderr in addition to log files.
DECLARE_int32(stderrthreshold);
// Set whether the log file header should be written upon creating a file.
DECLARE_bool(log_file_header);
// Set whether the log prefix should be prepended to each line of output.
DECLARE_bool(log_prefix);
// Set whether the year should be included in the log prefix.
DECLARE_bool(log_year_in_prefix);
// Log messages at a level <= this flag are buffered.
// Log messages at a higher level are flushed immediately.
DECLARE_int32(logbuflevel);
// Sets the maximum number of seconds which logs may be buffered for.
DECLARE_int32(logbufsecs);
// Log suppression level: messages logged at a lower level than this
// are suppressed.
DECLARE_int32(minloglevel);
// If specified, logfiles are written into this directory instead of the
// default logging directory.
DECLARE_string(log_dir);
// Set the log file mode.
DECLARE_int32(logfile_mode);
// Sets the path of the directory into which to put additional links
// to the log files.
DECLARE_string(log_link);
DECLARE_int32(v); // in vlog_is_on.cc
DECLARE_string(vmodule); // also in vlog_is_on.cc
// Sets the maximum log file size (in MB).
DECLARE_uint32(max_log_size);
// Sets whether to avoid logging to the disk if the disk is full.
DECLARE_bool(stop_logging_if_full_disk);
// Use UTC time for logging
DECLARE_bool(log_utc_time);
// Mailer used to send logging email
DECLARE_string(logmailer);
DECLARE_bool(symbolize_stacktrace);
#pragma pop_macro("DECLARE_VARIABLE")
#pragma pop_macro("DECLARE_bool")
#pragma pop_macro("DECLARE_string")
#pragma pop_macro("DECLARE_int32")
#pragma pop_macro("DECLARE_uint32")
#endif // GLOG_FLAGS_H

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007, Google Inc. // Copyright (c) 2024, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -30,6 +30,16 @@
#ifndef BASE_LOG_SEVERITY_H__ #ifndef BASE_LOG_SEVERITY_H__
#define BASE_LOG_SEVERITY_H__ #define BASE_LOG_SEVERITY_H__
#if defined(GLOG_USE_GLOG_EXPORT)
# include "glog/export.h"
#endif
#if !defined(GLOG_EXPORT)
# error <glog/log_severity.h> was not included correctly. See the documentation for how to consume the library.
#endif
namespace google {
// The recommended semantics of the log levels are as follows: // The recommended semantics of the log levels are as follows:
// //
// INFO: // INFO:
@ -48,27 +58,43 @@
// Variables of type LogSeverity are widely taken to lie in the range // Variables of type LogSeverity are widely taken to lie in the range
// [0, NUM_SEVERITIES-1]. Be careful to preserve this assumption if // [0, NUM_SEVERITIES-1]. Be careful to preserve this assumption if
// you ever need to change their values or add a new severity. // you ever need to change their values or add a new severity.
typedef int LogSeverity;
const int GLOG_INFO = 0, GLOG_WARNING = 1, GLOG_ERROR = 2, GLOG_FATAL = 3, enum LogSeverity {
NUM_SEVERITIES = 4; GLOG_INFO = 0,
GLOG_WARNING = 1,
GLOG_ERROR = 2,
GLOG_FATAL = 3,
#ifndef GLOG_NO_ABBREVIATED_SEVERITIES #ifndef GLOG_NO_ABBREVIATED_SEVERITIES
# ifdef ERROR # ifdef ERROR
# error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail. # error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail.
# endif # endif
const int INFO = GLOG_INFO, WARNING = GLOG_WARNING, INFO = GLOG_INFO,
ERROR = GLOG_ERROR, FATAL = GLOG_FATAL; WARNING = GLOG_WARNING,
ERROR = GLOG_ERROR,
FATAL = GLOG_FATAL
#endif #endif
};
#if defined(__cpp_inline_variables)
# if (__cpp_inline_variables >= 201606L)
# define GLOG_INLINE_VARIABLE inline
# endif // (__cpp_inline_variables >= 201606L)
#endif // defined(__cpp_inline_variables)
#if !defined(GLOG_INLINE_VARIABLE)
# define GLOG_INLINE_VARIABLE
#endif // !defined(GLOG_INLINE_VARIABLE)
GLOG_INLINE_VARIABLE
constexpr int NUM_SEVERITIES = 4;
// DFATAL is FATAL in debug mode, ERROR in normal mode // DFATAL is FATAL in debug mode, ERROR in normal mode
#ifdef NDEBUG #ifdef NDEBUG
#define DFATAL_LEVEL ERROR # define DFATAL_LEVEL ERROR
#else #else
#define DFATAL_LEVEL FATAL # define DFATAL_LEVEL FATAL
#endif #endif
extern GLOG_EXPORT const char* const LogSeverityNames[NUM_SEVERITIES];
// NDEBUG usage helpers related to (RAW_)DCHECK: // NDEBUG usage helpers related to (RAW_)DCHECK:
// //
// DEBUG_MODE is for small !NDEBUG uses like // DEBUG_MODE is for small !NDEBUG uses like
@ -89,10 +115,12 @@ extern GLOG_EXPORT const char* const LogSeverityNames[NUM_SEVERITIES];
// //
#ifdef NDEBUG #ifdef NDEBUG
enum { DEBUG_MODE = 0 }; enum { DEBUG_MODE = 0 };
#define IF_DEBUG_MODE(x) # define IF_DEBUG_MODE(x)
#else #else
enum { DEBUG_MODE = 1 }; enum { DEBUG_MODE = 1 };
#define IF_DEBUG_MODE(x) x # define IF_DEBUG_MODE(x) x
#endif #endif
} // namespace google
#endif // BASE_LOG_SEVERITY_H__ #endif // BASE_LOG_SEVERITY_H__

1679
src/glog/logging.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// Copyright (c) 2008, Google Inc. // Copyright (c) 2024, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -35,24 +35,27 @@
#define GLOG_PLATFORM_H #define GLOG_PLATFORM_H
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
#define GLOG_OS_WINDOWS # define GLOG_OS_WINDOWS
#elif defined(__CYGWIN__) || defined(__CYGWIN32__) #elif defined(__CYGWIN__) || defined(__CYGWIN32__)
#define GLOG_OS_CYGWIN # define GLOG_OS_CYGWIN
#elif defined(linux) || defined(__linux) || defined(__linux__) #elif defined(linux) || defined(__linux) || defined(__linux__)
#ifndef GLOG_OS_LINUX # define GLOG_OS_LINUX
#define GLOG_OS_LINUX # if defined(__ANDROID__)
#endif # define GLOG_OS_ANDROID
# endif
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
#define GLOG_OS_MACOSX # define GLOG_OS_MACOSX
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__)
#define GLOG_OS_FREEBSD # define GLOG_OS_FREEBSD
#elif defined(__NetBSD__) #elif defined(__NetBSD__)
#define GLOG_OS_NETBSD # define GLOG_OS_NETBSD
#elif defined(__OpenBSD__) #elif defined(__OpenBSD__)
#define GLOG_OS_OPENBSD # define GLOG_OS_OPENBSD
#elif defined(__EMSCRIPTEN__)
# define GLOG_OS_EMSCRIPTEN
#else #else
// TODO(hamaji): Add other platforms. // TODO(hamaji): Add other platforms.
#error Platform not supported by glog. Please consider to contribute platform information by submitting a pull request on Github. #error Platform not supported by glog. Please consider to contribute platform information by submitting a pull request on Github.
#endif #endif
#endif // GLOG_PLATFORM_H #endif // GLOG_PLATFORM_H

View File

@ -1,4 +1,4 @@
// Copyright (c) 2006, Google Inc. // Copyright (c) 2024, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -36,19 +36,19 @@
#ifndef GLOG_RAW_LOGGING_H #ifndef GLOG_RAW_LOGGING_H
#define GLOG_RAW_LOGGING_H #define GLOG_RAW_LOGGING_H
#include <ctime> #if defined(GLOG_USE_GLOG_EXPORT)
# include "glog/export.h"
@ac_google_start_namespace@
#include <glog/log_severity.h>
#include <glog/logging.h>
#include <glog/vlog_is_on.h>
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wvariadic-macros"
#endif #endif
#if !defined(GLOG_EXPORT)
# error <glog/raw_logging.h> was not included correctly. See the documentation for how to consume the library.
#endif
#include "glog/log_severity.h"
#include "glog/vlog_is_on.h"
namespace google {
// This is similar to LOG(severity) << format... and VLOG(level) << format.., // This is similar to LOG(severity) << format... and VLOG(level) << format..,
// but // but
// * it is to be used ONLY by low-level modules that can't use normal LOG() // * it is to be used ONLY by low-level modules that can't use normal LOG()
@ -63,108 +63,101 @@
// These will print an almost standard log lines like this to stderr only: // These will print an almost standard log lines like this to stderr only:
// E20200821 211317 file.cc:123] RAW: Failed foo with 22: bad_file // E20200821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
// I20200821 211317 file.cc:142] RAW: status is 20 // I20200821 211317 file.cc:142] RAW: status is 20
#define RAW_LOG(severity, ...) \ #define RAW_LOG(severity, ...) \
do { \ do { \
switch (@ac_google_namespace@::GLOG_ ## severity) { \ switch (google::GLOG_##severity) { \
case 0: \ case 0: \
RAW_LOG_INFO(__VA_ARGS__); \ RAW_LOG_INFO(__VA_ARGS__); \
break; \ break; \
case 1: \ case 1: \
RAW_LOG_WARNING(__VA_ARGS__); \ RAW_LOG_WARNING(__VA_ARGS__); \
break; \ break; \
case 2: \ case 2: \
RAW_LOG_ERROR(__VA_ARGS__); \ RAW_LOG_ERROR(__VA_ARGS__); \
break; \ break; \
case 3: \ case 3: \
RAW_LOG_FATAL(__VA_ARGS__); \ RAW_LOG_FATAL(__VA_ARGS__); \
break; \ break; \
default: \ default: \
break; \ break; \
} \ } \
} while (0) } while (0)
// The following STRIP_LOG testing is performed in the header file so that it's // The following STRIP_LOG testing is performed in the header file so that it's
// possible to completely compile out the logging code and the log messages. // possible to completely compile out the logging code and the log messages.
#if !defined(STRIP_LOG) || STRIP_LOG == 0 #if !defined(STRIP_LOG) || STRIP_LOG == 0
#define RAW_VLOG(verboselevel, ...) \ # define RAW_VLOG(verboselevel, ...) \
do { \ do { \
if (VLOG_IS_ON(verboselevel)) { \ if (VLOG_IS_ON(verboselevel)) { \
RAW_LOG_INFO(__VA_ARGS__); \ RAW_LOG_INFO(__VA_ARGS__); \
} \ } \
} while (0) } while (0)
#else #else
#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__) # define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG == 0 #endif // STRIP_LOG == 0
#if !defined(STRIP_LOG) || STRIP_LOG == 0 #if !defined(STRIP_LOG) || STRIP_LOG == 0
#define RAW_LOG_INFO(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_INFO, \ # define RAW_LOG_INFO(...) \
__FILE__, __LINE__, __VA_ARGS__) google::RawLog__(google::GLOG_INFO, __FILE__, __LINE__, __VA_ARGS__)
#else #else
#define RAW_LOG_INFO(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__) # define RAW_LOG_INFO(...) google::RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG == 0 #endif // STRIP_LOG == 0
#if !defined(STRIP_LOG) || STRIP_LOG <= 1 #if !defined(STRIP_LOG) || STRIP_LOG <= 1
#define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_WARNING, \ # define RAW_LOG_WARNING(...) \
__FILE__, __LINE__, __VA_ARGS__) google::RawLog__(google::GLOG_WARNING, __FILE__, __LINE__, __VA_ARGS__)
#else #else
#define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__) # define RAW_LOG_WARNING(...) google::RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG <= 1 #endif // STRIP_LOG <= 1
#if !defined(STRIP_LOG) || STRIP_LOG <= 2 #if !defined(STRIP_LOG) || STRIP_LOG <= 2
#define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_ERROR, \ # define RAW_LOG_ERROR(...) \
__FILE__, __LINE__, __VA_ARGS__) google::RawLog__(google::GLOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
#else #else
#define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__) # define RAW_LOG_ERROR(...) google::RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG <= 2 #endif // STRIP_LOG <= 2
#if !defined(STRIP_LOG) || STRIP_LOG <= 3 #if !defined(STRIP_LOG) || STRIP_LOG <= 3
#define RAW_LOG_FATAL(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_FATAL, \ # define RAW_LOG_FATAL(...) \
__FILE__, __LINE__, __VA_ARGS__) google::RawLog__(google::GLOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
#else #else
#define RAW_LOG_FATAL(...) \ # define RAW_LOG_FATAL(...) \
do { \ do { \
@ac_google_namespace@::RawLogStub__(0, __VA_ARGS__); \ google::RawLogStub__(0, __VA_ARGS__); \
exit(EXIT_FAILURE); \ exit(EXIT_FAILURE); \
} while (0) } while (0)
#endif // STRIP_LOG <= 3 #endif // STRIP_LOG <= 3
// Similar to CHECK(condition) << message, // Similar to CHECK(condition) << message,
// but for low-level modules: we use only RAW_LOG that does not allocate memory. // but for low-level modules: we use only RAW_LOG that does not allocate memory.
// We do not want to provide args list here to encourage this usage: // We do not want to provide args list here to encourage this usage:
// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args); // if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
// so that the args are not computed when not needed. // so that the args are not computed when not needed.
#define RAW_CHECK(condition, message) \ #define RAW_CHECK(condition, message) \
do { \ do { \
if (!(condition)) { \ if (!(condition)) { \
RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \ RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
} \ } \
} while (0) } while (0)
// Debug versions of RAW_LOG and RAW_CHECK // Debug versions of RAW_LOG and RAW_CHECK
#ifndef NDEBUG #ifndef NDEBUG
#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__) # define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__)
#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message) # define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)
#else // NDEBUG #else // NDEBUG
#define RAW_DLOG(severity, ...) \ # define RAW_DLOG(severity, ...) \
while (false) \ while (false) RAW_LOG(severity, __VA_ARGS__)
RAW_LOG(severity, __VA_ARGS__) # define RAW_DCHECK(condition, message) \
#define RAW_DCHECK(condition, message) \ while (false) RAW_CHECK(condition, message)
while (false) \
RAW_CHECK(condition, message)
#endif // NDEBUG #endif // NDEBUG
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
// Stub log function used to work around for unused variable warnings when // Stub log function used to work around for unused variable warnings when
// building with STRIP_LOG > 0. // building with STRIP_LOG > 0.
static inline void RawLogStub__(int /* ignored */, ...) { static inline void RawLogStub__(int /* ignored */, ...) {}
}
// Helper function to implement RAW_LOG and RAW_VLOG // Helper function to implement RAW_LOG and RAW_VLOG
// Logs format... at "severity" level, reporting it // Logs format... at "severity" level, reporting it
@ -172,8 +165,12 @@ static inline void RawLogStub__(int /* ignored */, ...) {
// This does not allocate memory or acquire locks. // This does not allocate memory or acquire locks.
GLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line, GLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line,
const char* format, ...) const char* format, ...)
@ac_cv___attribute___printf_4_5@; #if defined(__has_attribute)
# if __has_attribute(used)
@ac_google_end_namespace@ __attribute__((__format__(__printf__, 4, 5)))
# endif
#endif
;
} // namespace google
#endif // GLOG_RAW_LOGGING_H #endif // GLOG_RAW_LOGGING_H

View File

@ -1,4 +1,4 @@
// Copyright (c) 2003, Google Inc. // Copyright (c) 2023, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -35,149 +35,95 @@
// vector<int> v1, v2; // vector<int> v1, v2;
// CHECK_EQ(v1, v2); // CHECK_EQ(v1, v2);
// //
// If you want to use this header file with hash maps or slist, you
// need to define macros before including this file:
//
// - GLOG_STL_LOGGING_FOR_UNORDERED - <unordered_map> and <unordered_set>
// - GLOG_STL_LOGGING_FOR_TR1_UNORDERED - <tr1/unordered_(map|set)>
// - GLOG_STL_LOGGING_FOR_EXT_HASH - <ext/hash_(map|set)>
// - GLOG_STL_LOGGING_FOR_EXT_SLIST - <ext/slist>
//
#ifndef UTIL_GTL_STL_LOGGING_INL_H_ #ifndef GLOG_STL_LOGGING_H
#define UTIL_GTL_STL_LOGGING_INL_H_ #define GLOG_STL_LOGGING_H
#if !@ac_cv_cxx_using_operator@
# error We do not support stl_logging for this compiler
#endif
#include <deque> #include <deque>
#include <list> #include <list>
#include <map> #include <map>
#include <ostream> #include <ostream>
#include <set> #include <set>
#include <unordered_map>
#include <unordered_set>
#include <utility> #include <utility>
#include <vector> #include <vector>
#if defined(GLOG_STL_LOGGING_FOR_UNORDERED) && __cplusplus >= 201103L
# include <unordered_map>
# include <unordered_set>
#endif
#ifdef GLOG_STL_LOGGING_FOR_TR1_UNORDERED
# include <tr1/unordered_map>
# include <tr1/unordered_set>
#endif
#ifdef GLOG_STL_LOGGING_FOR_EXT_HASH
# include <ext/hash_set>
# include <ext/hash_map>
#endif
#ifdef GLOG_STL_LOGGING_FOR_EXT_SLIST
# include <ext/slist>
#endif
// Forward declare these two, and define them after all the container streams // Forward declare these two, and define them after all the container streams
// operators so that we can recurse from pair -> container -> container -> pair // operators so that we can recurse from pair -> container -> container -> pair
// properly. // properly.
template<class First, class Second> template <class First, class Second>
std::ostream& operator<<(std::ostream& out, const std::pair<First, Second>& p); std::ostream& operator<<(std::ostream& out, const std::pair<First, Second>& p);
@ac_google_start_namespace@ namespace google {
template<class Iter> template <class Iter>
void PrintSequence(std::ostream& out, Iter begin, Iter end); void PrintSequence(std::ostream& out, Iter begin, Iter end);
@ac_google_end_namespace@
#define OUTPUT_TWO_ARG_CONTAINER(Sequence) \
template<class T1, class T2> \
inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2>& seq) { \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \
} }
#define OUTPUT_TWO_ARG_CONTAINER(Sequence) \
template <class T1, class T2> \
inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2>& seq) { \
google::PrintSequence(out, seq.begin(), seq.end()); \
return out; \
}
OUTPUT_TWO_ARG_CONTAINER(std::vector) OUTPUT_TWO_ARG_CONTAINER(std::vector)
OUTPUT_TWO_ARG_CONTAINER(std::deque) OUTPUT_TWO_ARG_CONTAINER(std::deque)
OUTPUT_TWO_ARG_CONTAINER(std::list) OUTPUT_TWO_ARG_CONTAINER(std::list)
#ifdef GLOG_STL_LOGGING_FOR_EXT_SLIST
OUTPUT_TWO_ARG_CONTAINER(__gnu_cxx::slist)
#endif
#undef OUTPUT_TWO_ARG_CONTAINER #undef OUTPUT_TWO_ARG_CONTAINER
#define OUTPUT_THREE_ARG_CONTAINER(Sequence) \ #define OUTPUT_THREE_ARG_CONTAINER(Sequence) \
template<class T1, class T2, class T3> \ template <class T1, class T2, class T3> \
inline std::ostream& operator<<(std::ostream& out, \ inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3>& seq) { \ const Sequence<T1, T2, T3>& seq) { \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \ google::PrintSequence(out, seq.begin(), seq.end()); \
return out; \ return out; \
} }
OUTPUT_THREE_ARG_CONTAINER(std::set) OUTPUT_THREE_ARG_CONTAINER(std::set)
OUTPUT_THREE_ARG_CONTAINER(std::multiset) OUTPUT_THREE_ARG_CONTAINER(std::multiset)
#undef OUTPUT_THREE_ARG_CONTAINER #undef OUTPUT_THREE_ARG_CONTAINER
#define OUTPUT_FOUR_ARG_CONTAINER(Sequence) \ #define OUTPUT_FOUR_ARG_CONTAINER(Sequence) \
template<class T1, class T2, class T3, class T4> \ template <class T1, class T2, class T3, class T4> \
inline std::ostream& operator<<(std::ostream& out, \ inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3, T4>& seq) { \ const Sequence<T1, T2, T3, T4>& seq) { \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \ google::PrintSequence(out, seq.begin(), seq.end()); \
return out; \ return out; \
} }
OUTPUT_FOUR_ARG_CONTAINER(std::map) OUTPUT_FOUR_ARG_CONTAINER(std::map)
OUTPUT_FOUR_ARG_CONTAINER(std::multimap) OUTPUT_FOUR_ARG_CONTAINER(std::multimap)
#if defined(GLOG_STL_LOGGING_FOR_UNORDERED) && __cplusplus >= 201103L
OUTPUT_FOUR_ARG_CONTAINER(std::unordered_set) OUTPUT_FOUR_ARG_CONTAINER(std::unordered_set)
OUTPUT_FOUR_ARG_CONTAINER(std::unordered_multiset) OUTPUT_FOUR_ARG_CONTAINER(std::unordered_multiset)
#endif
#ifdef GLOG_STL_LOGGING_FOR_TR1_UNORDERED
OUTPUT_FOUR_ARG_CONTAINER(std::tr1::unordered_set)
OUTPUT_FOUR_ARG_CONTAINER(std::tr1::unordered_multiset)
#endif
#ifdef GLOG_STL_LOGGING_FOR_EXT_HASH
OUTPUT_FOUR_ARG_CONTAINER(__gnu_cxx::hash_set)
OUTPUT_FOUR_ARG_CONTAINER(__gnu_cxx::hash_multiset)
#endif
#undef OUTPUT_FOUR_ARG_CONTAINER #undef OUTPUT_FOUR_ARG_CONTAINER
#define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \ #define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \
template<class T1, class T2, class T3, class T4, class T5> \ template <class T1, class T2, class T3, class T4, class T5> \
inline std::ostream& operator<<(std::ostream& out, \ inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3, T4, T5>& seq) { \ const Sequence<T1, T2, T3, T4, T5>& seq) { \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \ google::PrintSequence(out, seq.begin(), seq.end()); \
return out; \ return out; \
} }
#if defined(GLOG_STL_LOGGING_FOR_UNORDERED) && __cplusplus >= 201103L
OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map) OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map)
OUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap) OUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap)
#endif
#ifdef GLOG_STL_LOGGING_FOR_TR1_UNORDERED
OUTPUT_FIVE_ARG_CONTAINER(std::tr1::unordered_map)
OUTPUT_FIVE_ARG_CONTAINER(std::tr1::unordered_multimap)
#endif
#ifdef GLOG_STL_LOGGING_FOR_EXT_HASH
OUTPUT_FIVE_ARG_CONTAINER(__gnu_cxx::hash_map)
OUTPUT_FIVE_ARG_CONTAINER(__gnu_cxx::hash_multimap)
#endif
#undef OUTPUT_FIVE_ARG_CONTAINER #undef OUTPUT_FIVE_ARG_CONTAINER
template<class First, class Second> template <class First, class Second>
inline std::ostream& operator<<(std::ostream& out, inline std::ostream& operator<<(std::ostream& out,
const std::pair<First, Second>& p) { const std::pair<First, Second>& p) {
out << '(' << p.first << ", " << p.second << ')'; out << '(' << p.first << ", " << p.second << ')';
return out; return out;
} }
@ac_google_start_namespace@ namespace google {
template<class Iter> template <class Iter>
inline void PrintSequence(std::ostream& out, Iter begin, Iter end) { inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
// Output at most 100 elements -- appropriate if used for logging. // Output at most 100 elements -- appropriate if used for logging.
for (int i = 0; begin != end && i < 100; ++i, ++begin) { for (int i = 0; begin != end && i < 100; ++i, ++begin) {
@ -189,7 +135,7 @@ inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
} }
} }
@ac_google_end_namespace@ } // namespace google
// Note that this is technically undefined behavior! We are adding things into // Note that this is technically undefined behavior! We are adding things into
// the std namespace for a reason though -- we are providing new operations on // the std namespace for a reason though -- we are providing new operations on
@ -215,6 +161,8 @@ inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
// move all of the *definitions* into namespace std, bet we need to ensure no // move all of the *definitions* into namespace std, bet we need to ensure no
// one references them first. This lets us take that step. We cannot define them // one references them first. This lets us take that step. We cannot define them
// in both because that would create ambiguous overloads when both are found. // in both because that would create ambiguous overloads when both are found.
namespace std { using ::operator<<; } namespace std {
using ::operator<<;
}
#endif // UTIL_GTL_STL_LOGGING_INL_H_ #endif // GLOG_STL_LOGGING_H

81
src/glog/types.h Normal file
View File

@ -0,0 +1,81 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#ifndef GLOG_TYPES_H
#define GLOG_TYPES_H
#include <cstddef>
#include <cstdint>
namespace google {
using int32 = std::int32_t;
using uint32 = std::uint32_t;
using int64 = std::int64_t;
using uint64 = std::uint64_t;
} // namespace google
#if defined(__has_feature)
# if __has_feature(thread_sanitizer)
# define GLOG_SANITIZE_THREAD 1
# endif
#endif
#if !defined(GLOG_SANITIZE_THREAD) && defined(__SANITIZE_THREAD__) && \
__SANITIZE_THREAD__
# define GLOG_SANITIZE_THREAD 1
#endif
#if defined(GLOG_SANITIZE_THREAD)
# define GLOG_IFDEF_THREAD_SANITIZER(X) X
#else
# define GLOG_IFDEF_THREAD_SANITIZER(X)
#endif
#if defined(_MSC_VER)
# define GLOG_MSVC_PUSH_DISABLE_WARNING(n) \
__pragma(warning(push)) __pragma(warning(disable : n))
# define GLOG_MSVC_POP_WARNING() __pragma(warning(pop))
#else
# define GLOG_MSVC_PUSH_DISABLE_WARNING(n)
# define GLOG_MSVC_POP_WARNING()
#endif
#if defined(GLOG_SANITIZE_THREAD)
// We need to identify the static variables as "benign" races
// to avoid noisy reports from TSAN.
extern "C" void AnnotateBenignRaceSized(const char* file, int line,
const volatile void* mem, size_t size,
const char* description);
#endif // defined(GLOG_SANITIZE_THREAD)
#endif // GLOG_TYPES_H

View File

@ -1,4 +1,4 @@
// Copyright (c) 1999, 2007, Google Inc. // Copyright (c) 2024, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -58,10 +58,21 @@
// CAVEAT: --vmodule functionality is not available in non gcc compilers. // CAVEAT: --vmodule functionality is not available in non gcc compilers.
// //
#ifndef BASE_VLOG_IS_ON_H_ #ifndef GLOG_VLOG_IS_ON_H
#define BASE_VLOG_IS_ON_H_ #define GLOG_VLOG_IS_ON_H
#include <glog/log_severity.h> #include <cstddef>
#if defined(GLOG_USE_GLOG_EXPORT)
# include "glog/export.h"
#endif
#if !defined(GLOG_EXPORT)
# error <glog/vlog_is_on.h> was not included correctly. See the documentation for how to consume the library.
#endif
#include "glog/flags.h"
#include "glog/types.h"
#if defined(__GNUC__) #if defined(__GNUC__)
// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site. // We emit an anonymous static int* variable at every VLOG_IS_ON(n) site.
@ -70,19 +81,25 @@
// it's either FLAGS_v or an appropriate internal variable // it's either FLAGS_v or an appropriate internal variable
// matching the current source file that represents results of // matching the current source file that represents results of
// parsing of --vmodule flag and/or SetVLOGLevel calls. // parsing of --vmodule flag and/or SetVLOGLevel calls.
#define VLOG_IS_ON(verboselevel) \ # define VLOG_IS_ON(verboselevel) \
__extension__ \ __extension__({ \
({ static @ac_google_namespace@::SiteFlag vlocal__ = {NULL, NULL, 0, NULL}; \ static google::SiteFlag vlocal__ = {nullptr, nullptr, 0, nullptr}; \
@ac_google_namespace@::int32 verbose_level__ = (verboselevel); \ GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized( \
(vlocal__.level == NULL ? @ac_google_namespace@::InitVLOG3__(&vlocal__, &FLAGS_v, \ __FILE__, __LINE__, &vlocal__, sizeof(google::SiteFlag), "")); \
__FILE__, verbose_level__) : *vlocal__.level >= verbose_level__); \ google::int32 verbose_level__ = (verboselevel); \
}) (vlocal__.level == nullptr \
? google::InitVLOG3__(&vlocal__, &FLAGS_v, __FILE__, \
verbose_level__) \
: *vlocal__.level >= verbose_level__); \
})
#else #else
// GNU extensions not available, so we do not support --vmodule. // GNU extensions not available, so we do not support --vmodule.
// Dynamic value of FLAGS_v always controls the logging level. // Dynamic value of FLAGS_v always controls the logging level.
#define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel)) # define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel))
#endif #endif
namespace google {
// Set VLOG(_IS_ON) level for module_pattern to log_level. // Set VLOG(_IS_ON) level for module_pattern to log_level.
// This lets us dynamically control what is normally set by the --vmodule flag. // This lets us dynamically control what is normally set by the --vmodule flag.
// Returns the level that previously applied to module_pattern. // Returns the level that previously applied to module_pattern.
@ -96,13 +113,13 @@ extern GLOG_EXPORT int SetVLOGLevel(const char* module_pattern, int log_level);
// Various declarations needed for VLOG_IS_ON above: ========================= // Various declarations needed for VLOG_IS_ON above: =========================
struct SiteFlag { struct SiteFlag {
@ac_google_namespace@::int32* level; int32* level;
const char* base_name; const char* base_name;
size_t base_len; std::size_t base_len;
SiteFlag* next; SiteFlag* next;
}; };
// Helper routine which determines the logging info for a particalur VLOG site. // Helper routine which determines the logging info for a particular VLOG site.
// site_flag is the address of the site-local pointer to the controlling // site_flag is the address of the site-local pointer to the controlling
// verbosity level // verbosity level
// site_default is the default to use for *site_flag // site_default is the default to use for *site_flag
@ -110,9 +127,10 @@ struct SiteFlag {
// verbose_level is the argument to VLOG_IS_ON // verbose_level is the argument to VLOG_IS_ON
// We will return the return value for VLOG_IS_ON // We will return the return value for VLOG_IS_ON
// and if possible set *site_flag appropriately. // and if possible set *site_flag appropriately.
extern GLOG_EXPORT bool InitVLOG3__( extern GLOG_EXPORT bool InitVLOG3__(SiteFlag* site_flag,
@ac_google_namespace@::SiteFlag* site_flag, int32* site_default,
@ac_google_namespace@::int32* site_default, const char* fname, const char* fname,
@ac_google_namespace@::int32 verbose_level); int32 verbose_level);
} // namespace google
#endif // BASE_VLOG_IS_ON_H_ #endif // GLOG_VLOG_IS_ON_H

View File

@ -1,4 +1,4 @@
// Copyright (c) 2009, Google Inc. // Copyright (c) 2024, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -31,11 +31,13 @@
// (based on googletest: http://code.google.com/p/googletest/) // (based on googletest: http://code.google.com/p/googletest/)
#ifdef GOOGLETEST_H__ #ifdef GOOGLETEST_H__
#error You must not include this file twice. # error You must not include this file twice.
#endif #endif
#define GOOGLETEST_H__ #define GOOGLETEST_H__
#include "utilities.h" #include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <cctype> #include <cctype>
#include <csetjmp> #include <csetjmp>
@ -43,41 +45,46 @@
#include <cstdlib> #include <cstdlib>
#include <ctime> #include <ctime>
#include <map> #include <map>
#include <new>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#include <sys/types.h> #include "config.h"
#include <sys/stat.h>
#include <fcntl.h>
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
# include <unistd.h> # include <unistd.h>
#endif #endif
#if defined(GLOG_USE_WINDOWS_PORT)
# include "port.h"
#endif // defined(GLOG_USE_WINDOWS_PORT)
#include "base/commandlineflags.h" #include "base/commandlineflags.h"
#include "utilities.h"
#if __cplusplus < 201103L && !defined(_MSC_VER) #if __cplusplus < 201103L && !defined(_MSC_VER)
#define GOOGLE_GLOG_THROW_BAD_ALLOC throw (std::bad_alloc) # define GOOGLE_GLOG_THROW_BAD_ALLOC throw(std::bad_alloc)
#else #else
#define GOOGLE_GLOG_THROW_BAD_ALLOC # define GOOGLE_GLOG_THROW_BAD_ALLOC
#endif #endif
using std::map; using std::map;
using std::string; using std::string;
using std::vector; using std::vector;
_START_GOOGLE_NAMESPACE_ namespace google {
extern void (*g_logging_fail_func)();
extern GLOG_EXPORT void (*g_logging_fail_func)(); extern void GetExistingTempDirectories(std::vector<std::string>& list);
extern int posix_strerror_r(int err, char* buf, size_t len);
_END_GOOGLE_NAMESPACE_ extern std::string StrError(int err);
} // namespace google
#undef GLOG_EXPORT #undef GLOG_EXPORT
#define GLOG_EXPORT #define GLOG_EXPORT
static inline string GetTempDir() { static inline string GetTempDir() {
vector<string> temp_directories_list; vector<string> temp_directories_list;
google::GetExistingTempDirectories(&temp_directories_list); google::GetExistingTempDirectories(temp_directories_list);
if (temp_directories_list.empty()) { if (temp_directories_list.empty()) {
fprintf(stderr, "No temporary directory found\n"); fprintf(stderr, "No temporary directory found\n");
@ -93,7 +100,7 @@ static inline string GetTempDir() {
// (e.g., glog/vsproject/logging_unittest). // (e.g., glog/vsproject/logging_unittest).
static const char TEST_SRC_DIR[] = "../.."; static const char TEST_SRC_DIR[] = "../..";
#elif !defined(TEST_SRC_DIR) #elif !defined(TEST_SRC_DIR)
# warning TEST_SRC_DIR should be defined in config.h # warning TEST_SRC_DIR should be defined in config.h
static const char TEST_SRC_DIR[] = "."; static const char TEST_SRC_DIR[] = ".";
#endif #endif
@ -110,14 +117,14 @@ DEFINE_int32(benchmark_iters, 100000, "Number of iterations per benchmark");
#endif #endif
#ifdef HAVE_LIB_GTEST #ifdef HAVE_LIB_GTEST
# include <gtest/gtest.h> # include <gtest/gtest.h>
// Use our ASSERT_DEATH implementation. // Use our ASSERT_DEATH implementation.
# undef ASSERT_DEATH # undef ASSERT_DEATH
# undef ASSERT_DEBUG_DEATH # undef ASSERT_DEBUG_DEATH
using testing::InitGoogleTest; using testing::InitGoogleTest;
#else #else
_START_GOOGLE_NAMESPACE_ namespace google {
void InitGoogleTest(int*, char**); void InitGoogleTest(int*, char**);
@ -125,81 +132,94 @@ void InitGoogleTest(int*, char**) {}
// The following is some bare-bones testing infrastructure // The following is some bare-bones testing infrastructure
#define EXPECT_NEAR(val1, val2, abs_error) \ # define EXPECT_NEAR(val1, val2, abs_error) \
do { \ do { \
if (abs(val1 - val2) > abs_error) { \ if (abs(val1 - val2) > abs_error) { \
fprintf(stderr, "Check failed: %s within %s of %s\n", #val1, #abs_error, \ fprintf(stderr, "Check failed: %s within %s of %s\n", #val1, \
#val2); \ #abs_error, #val2); \
exit(EXIT_FAILURE); \ exit(EXIT_FAILURE); \
} \ } \
} while (0) } while (0)
#define EXPECT_TRUE(cond) \ # define EXPECT_TRUE(cond) \
do { \ do { \
if (!(cond)) { \ if (!(cond)) { \
fprintf(stderr, "Check failed: %s\n", #cond); \ fprintf(stderr, "Check failed: %s\n", #cond); \
exit(EXIT_FAILURE); \ exit(EXIT_FAILURE); \
} \ } \
} while (0) } while (0)
#define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond)) # define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond))
#define EXPECT_OP(op, val1, val2) \ # define EXPECT_OP(op, val1, val2) \
do { \ do { \
if (!((val1) op (val2))) { \ if (!((val1)op(val2))) { \
fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \ fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
exit(EXIT_FAILURE); \ exit(EXIT_FAILURE); \
} \ } \
} while (0) } while (0)
#define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2) # define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2)
#define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2) # define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2)
#define EXPECT_GT(val1, val2) EXPECT_OP(>, val1, val2) # define EXPECT_GT(val1, val2) EXPECT_OP(>, val1, val2)
#define EXPECT_LT(val1, val2) EXPECT_OP(<, val1, val2) # define EXPECT_LT(val1, val2) EXPECT_OP(<, val1, val2)
#define EXPECT_NAN(arg) \ # define EXPECT_NAN(arg) \
do { \ do { \
if (!isnan(arg)) { \ if (!isnan(arg)) { \
fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \ fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \
exit(EXIT_FAILURE); \ exit(EXIT_FAILURE); \
} \ } \
} while (0) } while (0)
#define EXPECT_INF(arg) \ # define EXPECT_INF(arg) \
do { \ do { \
if (!isinf(arg)) { \ if (!isinf(arg)) { \
fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \ fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \
exit(EXIT_FAILURE); \ exit(EXIT_FAILURE); \
} \ } \
} while (0) } while (0)
#define EXPECT_DOUBLE_EQ(val1, val2) \ # define EXPECT_DOUBLE_EQ(val1, val2) \
do { \ do { \
if (((val1) < (val2) - 0.001 || (val1) > (val2) + 0.001)) { \ if (((val1) < (val2)-0.001 || (val1) > (val2) + 0.001)) { \
fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \ fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \
exit(EXIT_FAILURE); \ exit(EXIT_FAILURE); \
} \ } \
} while (0) } while (0)
#define EXPECT_STREQ(val1, val2) \ # define EXPECT_STREQ(val1, val2) \
do { \ do { \
if (strcmp((val1), (val2)) != 0) { \ if (strcmp((val1), (val2)) != 0) { \
fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \ fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \
exit(EXIT_FAILURE); \ exit(EXIT_FAILURE); \
} \ } \
} while (0) } while (0)
# define EXPECT_THROW(statement, exception) \
do { \
try { \
statement; \
} catch (const exception&) { \
printf("ok\n"); \
} catch (...) { \
fprintf(stderr, "%s\n", "Unexpected exception thrown"); \
exit(EXIT_FAILURE); \
} \
} while (0)
vector<void (*)()> g_testlist; // the tests to run vector<void (*)()> g_testlist; // the tests to run
# define TEST(a, b) \
#define TEST(a, b) \ struct Test_##a##_##b { \
struct Test_##a##_##b { \ Test_##a##_##b() { g_testlist.push_back(&Run); } \
Test_##a##_##b() { g_testlist.push_back(&Run); } \ static void Run() { \
static void Run() { FlagSaver fs; RunTest(); } \ FlagSaver fs; \
static void RunTest(); \ RunTest(); \
}; \ } \
static Test_##a##_##b g_test_##a##_##b; \ static void RunTest(); \
void Test_##a##_##b::RunTest() }; \
static Test_##a##_##b g_test_##a##_##b; \
void Test_##a##_##b::RunTest()
static inline int RUN_ALL_TESTS() { static inline int RUN_ALL_TESTS() {
vector<void (*)()>::const_iterator it; vector<void (*)()>::const_iterator it;
@ -211,11 +231,11 @@ static inline int RUN_ALL_TESTS() {
return 0; return 0;
} }
_END_GOOGLE_NAMESPACE_ } // namespace google
#endif // ! HAVE_LIB_GTEST #endif // ! HAVE_LIB_GTEST
_START_GOOGLE_NAMESPACE_ namespace google {
static bool g_called_abort; static bool g_called_abort;
static jmp_buf g_jmp_buf; static jmp_buf g_jmp_buf;
@ -226,33 +246,33 @@ static inline void CalledAbort() {
#ifdef GLOG_OS_WINDOWS #ifdef GLOG_OS_WINDOWS
// TODO(hamaji): Death test somehow doesn't work in Windows. // TODO(hamaji): Death test somehow doesn't work in Windows.
#define ASSERT_DEATH(fn, msg) # define ASSERT_DEATH(fn, msg)
#else #else
#define ASSERT_DEATH(fn, msg) \ # define ASSERT_DEATH(fn, msg) \
do { \ do { \
g_called_abort = false; \ g_called_abort = false; \
/* in logging.cc */ \ /* in logging.cc */ \
void (*original_logging_fail_func)() = g_logging_fail_func; \ void (*original_logging_fail_func)() = g_logging_fail_func; \
g_logging_fail_func = &CalledAbort; \ g_logging_fail_func = &CalledAbort; \
if (!setjmp(g_jmp_buf)) fn; \ if (!setjmp(g_jmp_buf)) fn; \
/* set back to their default */ \ /* set back to their default */ \
g_logging_fail_func = original_logging_fail_func; \ g_logging_fail_func = original_logging_fail_func; \
if (!g_called_abort) { \ if (!g_called_abort) { \
fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \ fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \
exit(EXIT_FAILURE); \ exit(EXIT_FAILURE); \
} \ } \
} while (0) } while (0)
#endif #endif
#ifdef NDEBUG #ifdef NDEBUG
#define ASSERT_DEBUG_DEATH(fn, msg) # define ASSERT_DEBUG_DEATH(fn, msg)
#else #else
#define ASSERT_DEBUG_DEATH(fn, msg) ASSERT_DEATH(fn, msg) # define ASSERT_DEBUG_DEATH(fn, msg) ASSERT_DEATH(fn, msg)
#endif // NDEBUG #endif // NDEBUG
// Benchmark tools. // Benchmark tools.
#define BENCHMARK(n) static BenchmarkRegisterer __benchmark_ ## n (#n, &n); #define BENCHMARK(n) static BenchmarkRegisterer __benchmark_##n(#n, &n);
map<string, void (*)(int)> g_benchlist; // the benchmarks to run map<string, void (*)(int)> g_benchlist; // the benchmarks to run
@ -270,21 +290,19 @@ static inline void RunSpecifiedBenchmarks() {
int iter_cnt = FLAGS_benchmark_iters; int iter_cnt = FLAGS_benchmark_iters;
puts("Benchmark\tTime(ns)\tIterations"); puts("Benchmark\tTime(ns)\tIterations");
for (map<string, void (*)(int)>::const_iterator iter = g_benchlist.begin(); for (auto& iter : g_benchlist) {
iter != g_benchlist.end();
++iter) {
clock_t start = clock(); clock_t start = clock();
iter->second(iter_cnt); iter.second(iter_cnt);
double elapsed_ns = (static_cast<double>(clock()) - start) / double elapsed_ns = (static_cast<double>(clock()) - start) /
CLOCKS_PER_SEC * 1000 * 1000 * 1000; CLOCKS_PER_SEC * 1000 * 1000 * 1000;
#if defined(__GNUC__) && !defined(__clang__) #if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push # pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat=" # pragma GCC diagnostic ignored "-Wformat="
#endif #endif
printf("%s\t%8.2lf\t%10d\n", printf("%s\t%8.2lf\t%10d\n", iter.first.c_str(), elapsed_ns / iter_cnt,
iter->first.c_str(), elapsed_ns / iter_cnt, iter_cnt); iter_cnt);
#if defined(__GNUC__) && !defined(__clang__) #if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
} }
puts(""); puts("");
@ -296,78 +314,70 @@ static inline void RunSpecifiedBenchmarks() {
class CapturedStream { class CapturedStream {
public: public:
CapturedStream(int fd, const string & filename) : CapturedStream(int fd, string filename)
fd_(fd), : fd_(fd), filename_(std::move(filename)) {
uncaptured_fd_(-1),
filename_(filename) {
Capture(); Capture();
} }
~CapturedStream() {
if (uncaptured_fd_ != -1) {
CHECK(close(uncaptured_fd_) != -1);
}
}
// Start redirecting output to a file // Start redirecting output to a file
void Capture() { void Capture() {
// Keep original stream for later // Keep original stream for later
CHECK(uncaptured_fd_ == -1) << ", Stream " << fd_ << " already captured!"; CHECK(!uncaptured_fd_) << ", Stream " << fd_ << " already captured!";
uncaptured_fd_ = dup(fd_); uncaptured_fd_.reset(dup(fd_));
CHECK(uncaptured_fd_ != -1); CHECK(uncaptured_fd_);
// Open file to save stream to // Open file to save stream to
int cap_fd = open(filename_.c_str(), FileDescriptor cap_fd{open(filename_.c_str(), O_CREAT | O_TRUNC | O_WRONLY,
O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR)};
S_IRUSR | S_IWUSR); CHECK(cap_fd);
CHECK(cap_fd != -1);
// Send stdout/stderr to this file // Send stdout/stderr to this file
fflush(NULL); fflush(nullptr);
CHECK(dup2(cap_fd, fd_) != -1); CHECK(dup2(cap_fd.get(), fd_) != -1);
CHECK(close(cap_fd) != -1); CHECK(cap_fd.close() != -1);
} }
// Remove output redirection // Remove output redirection
void StopCapture() { void StopCapture() {
// Restore original stream // Restore original stream
if (uncaptured_fd_ != -1) { if (uncaptured_fd_) {
fflush(NULL); fflush(nullptr);
CHECK(dup2(uncaptured_fd_, fd_) != -1); CHECK(dup2(uncaptured_fd_.get(), fd_) != -1);
} }
} }
const string & filename() const { return filename_; } const string& filename() const { return filename_; }
private: private:
int fd_; // file descriptor being captured int fd_; // file descriptor being captured
int uncaptured_fd_; // where the stream was originally being sent to FileDescriptor
uncaptured_fd_; // where the stream was originally being sent to
string filename_; // file where stream is being saved string filename_; // file where stream is being saved
}; };
static CapturedStream * s_captured_streams[STDERR_FILENO+1]; static std::map<int, std::unique_ptr<CapturedStream>> s_captured_streams;
// Redirect a file descriptor to a file. // Redirect a file descriptor to a file.
// fd - Should be STDOUT_FILENO or STDERR_FILENO // fd - Should be stdout or stderr
// filename - File where output should be stored // filename - File where output should be stored
static inline void CaptureTestOutput(int fd, const string & filename) { static inline void CaptureTestOutput(int fd, const string& filename) {
CHECK((fd == STDOUT_FILENO) || (fd == STDERR_FILENO)); CHECK((fd == fileno(stdout)) || (fd == fileno(stderr)));
CHECK(s_captured_streams[fd] == NULL); CHECK(s_captured_streams.find(fd) == s_captured_streams.end());
s_captured_streams[fd] = new CapturedStream(fd, filename); s_captured_streams[fd] = std::make_unique<CapturedStream>(fd, filename);
} }
static inline void CaptureTestStdout() { static inline void CaptureTestStdout() {
CaptureTestOutput(STDOUT_FILENO, FLAGS_test_tmpdir + "/captured.out"); CaptureTestOutput(fileno(stdout), FLAGS_test_tmpdir + "/captured.out");
} }
static inline void CaptureTestStderr() { static inline void CaptureTestStderr() {
CaptureTestOutput(STDERR_FILENO, FLAGS_test_tmpdir + "/captured.err"); CaptureTestOutput(fileno(stderr), FLAGS_test_tmpdir + "/captured.err");
} }
// Return the size (in bytes) of a file // Return the size (in bytes) of a file
static inline size_t GetFileSize(FILE * file) { static inline size_t GetFileSize(FILE* file) {
fseek(file, 0, SEEK_END); fseek(file, 0, SEEK_END);
return static_cast<size_t>(ftell(file)); return static_cast<size_t>(ftell(file));
} }
// Read the entire content of a file as a string // Read the entire content of a file as a string
static inline string ReadEntireFile(FILE * file) { static inline string ReadEntireFile(FILE* file) {
const size_t file_size = GetFileSize(file); const size_t file_size = GetFileSize(file);
char * const buffer = new char[file_size]; std::vector<char> content(file_size);
size_t bytes_last_read = 0; // # of bytes read in the last fread() size_t bytes_last_read = 0; // # of bytes read in the last fread()
size_t bytes_read = 0; // # of bytes read so far size_t bytes_read = 0; // # of bytes read so far
@ -377,39 +387,33 @@ static inline string ReadEntireFile(FILE * file) {
// Keep reading the file until we cannot read further or the // Keep reading the file until we cannot read further or the
// pre-determined file size is reached. // pre-determined file size is reached.
do { do {
bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); bytes_last_read =
fread(content.data() + bytes_read, 1, file_size - bytes_read, file);
bytes_read += bytes_last_read; bytes_read += bytes_last_read;
} while (bytes_last_read > 0 && bytes_read < file_size); } while (bytes_last_read > 0 && bytes_read < file_size);
const string content = string(buffer, buffer+bytes_read); return std::string(content.data(), bytes_read);
delete[] buffer;
return content;
} }
// Get the captured stdout (when fd is STDOUT_FILENO) or stderr (when // Get the captured stdout or stderr as a string
// fd is STDERR_FILENO) as a string
static inline string GetCapturedTestOutput(int fd) { static inline string GetCapturedTestOutput(int fd) {
CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO); CHECK((fd == fileno(stdout)) || (fd == fileno(stderr)));
CapturedStream * const cap = s_captured_streams[fd]; std::unique_ptr<CapturedStream> cap = std::move(s_captured_streams.at(fd));
CHECK(cap) s_captured_streams.erase(fd);
<< ": did you forget CaptureTestStdout() or CaptureTestStderr()?"; CHECK(cap) << ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
// Make sure everything is flushed. // Make sure everything is flushed.
cap->StopCapture(); cap->StopCapture();
// Read the captured file. // Read the captured file.
FILE * const file = fopen(cap->filename().c_str(), "r"); std::unique_ptr<FILE> file{fopen(cap->filename().c_str(), "r")};
const string content = ReadEntireFile(file); const string content = ReadEntireFile(file.get());
fclose(file); file.reset();
delete cap;
s_captured_streams[fd] = NULL;
return content; return content;
} }
// Get the captured stderr of a test as a string. // Get the captured stderr of a test as a string.
static inline string GetCapturedTestStderr() { static inline string GetCapturedTestStderr() {
return GetCapturedTestOutput(STDERR_FILENO); return GetCapturedTestOutput(fileno(stderr));
} }
static const std::size_t kLoggingPrefixLength = 9; static const std::size_t kLoggingPrefixLength = 9;
@ -421,7 +425,7 @@ static inline bool IsLoggingPrefix(const string& s) {
} }
if (!strchr("IWEF", s[0])) return false; if (!strchr("IWEF", s[0])) return false;
for (size_t i = 1; i <= 8; ++i) { for (size_t i = 1; i <= 8; ++i) {
if (!isdigit(s[i]) && s[i] != "YEARDATE"[i-1]) return false; if (!isdigit(s[i]) && s[i] != "YEARDATE"[i - 1]) return false;
} }
return true; return true;
} }
@ -461,16 +465,15 @@ static inline string MungeLine(const string& line) {
} }
size_t index = thread_lineinfo.find(':'); size_t index = thread_lineinfo.find(':');
CHECK_NE(string::npos, index); CHECK_NE(string::npos, index);
thread_lineinfo = thread_lineinfo.substr(0, index+1) + "LINE]"; thread_lineinfo = thread_lineinfo.substr(0, index + 1) + "LINE]";
string rest; string rest;
std::getline(iss, rest); std::getline(iss, rest);
return (before + logcode_date[0] + "YEARDATE TIME__ " + thread_lineinfo + return (before + logcode_date[0] + "YEARDATE TIME__ " + thread_lineinfo +
MungeLine(rest)); MungeLine(rest));
} }
static inline void StringReplace(string* str, static inline void StringReplace(string* str, const string& oldsub,
const string& oldsub, const string& newsub) {
const string& newsub) {
size_t pos = str->find(oldsub); size_t pos = str->find(oldsub);
if (pos != string::npos) { if (pos != string::npos) {
str->replace(pos, oldsub.size(), newsub); str->replace(pos, oldsub.size(), newsub);
@ -478,17 +481,18 @@ static inline void StringReplace(string* str,
} }
static inline string Munge(const string& filename) { static inline string Munge(const string& filename) {
FILE* fp = fopen(filename.c_str(), "rb"); std::unique_ptr<FILE> fp{fopen(filename.c_str(), "rb")};
CHECK(fp != NULL) << filename << ": couldn't open"; CHECK(fp != nullptr) << filename << ": couldn't open";
char buf[4096]; char buf[4096];
string result; string result;
while (fgets(buf, 4095, fp)) { while (fgets(buf, 4095, fp.get())) {
string line = MungeLine(buf); string line = MungeLine(buf);
const size_t str_size = 256; const size_t str_size = 256;
char null_str[str_size]; char null_str[str_size];
char ptr_str[str_size]; char ptr_str[str_size];
snprintf(null_str, str_size, "%p", static_cast<void*>(NULL)); std::snprintf(null_str, str_size, "%p", static_cast<void*>(nullptr));
snprintf(ptr_str, str_size, "%p", reinterpret_cast<void*>(PTR_TEST_VALUE)); std::snprintf(ptr_str, str_size, "%p",
reinterpret_cast<void*>(PTR_TEST_VALUE));
StringReplace(&line, "__NULLP__", null_str); StringReplace(&line, "__NULLP__", null_str);
StringReplace(&line, "__PTRTEST__", ptr_str); StringReplace(&line, "__PTRTEST__", ptr_str);
@ -500,19 +504,19 @@ static inline string Munge(const string& filename) {
StringReplace(&line, "__ENOEXEC__", StrError(ENOEXEC)); StringReplace(&line, "__ENOEXEC__", StrError(ENOEXEC));
result += line + "\n"; result += line + "\n";
} }
fclose(fp);
return result; return result;
} }
static inline void WriteToFile(const string& body, const string& file) { static inline void WriteToFile(const string& body, const string& file) {
FILE* fp = fopen(file.c_str(), "wb"); std::unique_ptr<FILE> fp{fopen(file.c_str(), "wb")};
fwrite(body.data(), 1, body.size(), fp); fwrite(body.data(), 1, body.size(), fp.get());
fclose(fp);
} }
static inline bool MungeAndDiffTest(const string& golden_filename, static inline bool MungeAndDiffTest(const string& golden_filename,
CapturedStream* cap) { CapturedStream* cap) {
if (cap == s_captured_streams[STDOUT_FILENO]) { auto pos = s_captured_streams.find(fileno(stdout));
if (pos != s_captured_streams.end() && cap == pos->second.get()) {
CHECK(cap) << ": did you forget CaptureTestStdout()?"; CHECK(cap) << ": did you forget CaptureTestStdout()?";
} else { } else {
CHECK(cap) << ": did you forget CaptureTestStderr()?"; CHECK(cap) << ": did you forget CaptureTestStderr()?";
@ -547,126 +551,68 @@ static inline bool MungeAndDiffTest(const string& golden_filename,
} }
static inline bool MungeAndDiffTestStderr(const string& golden_filename) { static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
return MungeAndDiffTest(golden_filename, s_captured_streams[STDERR_FILENO]); return MungeAndDiffTest(golden_filename,
s_captured_streams.at(fileno(stderr)).get());
} }
static inline bool MungeAndDiffTestStdout(const string& golden_filename) { static inline bool MungeAndDiffTestStdout(const string& golden_filename) {
return MungeAndDiffTest(golden_filename, s_captured_streams[STDOUT_FILENO]); return MungeAndDiffTest(golden_filename,
s_captured_streams.at(fileno(stdout)).get());
} }
// Save flags used from logging_unittest.cc. // Save flags used from logging_unittest.cc.
#ifndef HAVE_LIB_GFLAGS #ifndef GLOG_USE_GFLAGS
struct FlagSaver { struct FlagSaver {
FlagSaver() FlagSaver()
: v_(FLAGS_v), : v_(FLAGS_v),
stderrthreshold_(FLAGS_stderrthreshold), stderrthreshold_(FLAGS_stderrthreshold),
logtostderr_(FLAGS_logtostderr), logtostderr_(FLAGS_logtostderr),
alsologtostderr_(FLAGS_alsologtostderr) {} alsologtostderr_(FLAGS_alsologtostderr),
logmailer_(FLAGS_logmailer) {}
~FlagSaver() { ~FlagSaver() {
FLAGS_v = v_; FLAGS_v = v_;
FLAGS_stderrthreshold = stderrthreshold_; FLAGS_stderrthreshold = stderrthreshold_;
FLAGS_logtostderr = logtostderr_; FLAGS_logtostderr = logtostderr_;
FLAGS_alsologtostderr = alsologtostderr_; FLAGS_alsologtostderr = alsologtostderr_;
FLAGS_logmailer = logmailer_;
} }
int v_; int v_;
int stderrthreshold_; int stderrthreshold_;
bool logtostderr_; bool logtostderr_;
bool alsologtostderr_; bool alsologtostderr_;
std::string logmailer_;
}; };
#endif #endif
class Thread {
public:
virtual ~Thread() {}
void SetJoinable(bool) {}
#if defined(GLOG_OS_WINDOWS) && !defined(GLOG_OS_CYGWIN)
void Start() {
handle_ = CreateThread(NULL,
0,
&Thread::InvokeThreadW,
this,
0,
&th_);
CHECK(handle_) << "CreateThread";
}
void Join() {
WaitForSingleObject(handle_, INFINITE);
}
#elif defined(HAVE_PTHREAD)
void Start() {
pthread_create(&th_, NULL, &Thread::InvokeThread, this);
}
void Join() {
pthread_join(th_, NULL);
}
#else
# error No thread implementation.
#endif
protected:
virtual void Run() = 0;
private:
static void* InvokeThread(void* self) {
(static_cast<Thread*>(self))->Run();
return NULL;
}
#if defined(GLOG_OS_WINDOWS) && !defined(GLOG_OS_CYGWIN)
static DWORD __stdcall InvokeThreadW(LPVOID self) {
InvokeThread(self);
return 0;
}
HANDLE handle_;
DWORD th_;
#else
pthread_t th_;
#endif
};
static inline void SleepForMilliseconds(unsigned t) {
#ifndef GLOG_OS_WINDOWS
# if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
const struct timespec req = {0, t * 1000 * 1000};
nanosleep(&req, NULL);
# else
usleep(t * 1000);
# endif
#else
Sleep(t);
#endif
}
// Add hook for operator new to ensure there are no memory allocation. // Add hook for operator new to ensure there are no memory allocation.
void (*g_new_hook)() = NULL; void (*g_new_hook)() = nullptr;
_END_GOOGLE_NAMESPACE_ } // namespace google
void* operator new(size_t size) GOOGLE_GLOG_THROW_BAD_ALLOC { void* operator new(size_t size, const std::nothrow_t&) noexcept {
if (GOOGLE_NAMESPACE::g_new_hook) { if (google::g_new_hook) {
GOOGLE_NAMESPACE::g_new_hook(); google::g_new_hook();
} }
return malloc(size); return malloc(size);
} }
void* operator new(size_t size) GOOGLE_GLOG_THROW_BAD_ALLOC {
void* p = ::operator new(size, std::nothrow);
if (p == nullptr) {
throw std::bad_alloc{};
}
return p;
}
void* operator new[](size_t size) GOOGLE_GLOG_THROW_BAD_ALLOC { void* operator new[](size_t size) GOOGLE_GLOG_THROW_BAD_ALLOC {
return ::operator new(size); return ::operator new(size);
} }
void operator delete(void* p) throw() { void operator delete(void* p) noexcept { free(p); }
free(p);
}
void operator delete(void* p, size_t) throw() { void operator delete(void* p, size_t) noexcept { ::operator delete(p); }
::operator delete(p);
}
void operator delete[](void* p) throw() { void operator delete[](void* p) noexcept { ::operator delete(p); }
::operator delete(p);
}
void operator delete[](void* p, size_t) throw() { void operator delete[](void* p, size_t) noexcept { ::operator delete(p); }
::operator delete(p);
}

View File

@ -0,0 +1,16 @@
cmake_minimum_required (VERSION 3.16)
project (glog_includes LANGUAGES CXX)
find_package (glog REQUIRED NO_MODULE)
add_executable (glog_includes_logging glog_includes_logging.cc)
target_link_libraries (glog_includes_logging PRIVATE glog::glog)
add_executable (glog_includes_vlog_is_on glog_includes_vlog_is_on.cc)
target_link_libraries (glog_includes_vlog_is_on PRIVATE glog::glog)
add_executable (glog_includes_raw_logging glog_includes_raw_logging.cc)
target_link_libraries (glog_includes_raw_logging PRIVATE glog::glog)
add_executable (glog_includes_stl_logging glog_includes_stl_logging.cc)
target_link_libraries (glog_includes_stl_logging PRIVATE glog::glog)

View File

@ -0,0 +1,39 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sergiu Deitsch
#include <glog/logging.h>
int main() {
LOG(INFO) << "info";
LOG(WARNING) << "warning";
LOG(ERROR) << "error";
LOG(FATAL) << "fatal";
}

View File

@ -0,0 +1,39 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sergiu Deitsch
#include <glog/raw_logging.h>
int main() {
RAW_LOG(INFO, "info");
RAW_LOG(WARNING, "warning");
RAW_LOG(ERROR, "error");
RAW_LOG(FATAL, "fatal");
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007, Google Inc. // Copyright (c) 2024, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -27,9 +27,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// //
// Author: Sergey Ioffe // Author: Sergiu Deitsch
#define GOOGLE_STRIP_LOG 2 #include <glog/stl_logging.h>
// Include the actual test. int main() {}
#include "logging_striptest_main.cc"

View File

@ -1,4 +1,4 @@
// Copyright (c) 2007, Google Inc. // Copyright (c) 2024, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -27,9 +27,8 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// //
// Author: Sergey Ioffe // Author: Sergiu Deitsch
#define GOOGLE_STRIP_LOG 10 #include <glog/vlog_is_on.h>
// Include the actual test. int main() { VLOG_IS_ON(0); }
#include "logging_striptest_main.cc"

View File

@ -0,0 +1,10 @@
cmake_minimum_required (VERSION 3.16)
project (glog_log_severity LANGUAGES CXX)
find_package (glog REQUIRED NO_MODULE)
add_executable (glog_log_severity_constants glog_log_severity_constants.cc)
target_link_libraries (glog_log_severity_constants PRIVATE glog::glog)
add_executable (glog_log_severity_conversion glog_log_severity_conversion.cc)
target_link_libraries (glog_log_severity_conversion PRIVATE glog::glog)

View File

@ -0,0 +1,40 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sergiu Deitsch
#include <glog/logging.h>
int main() {
// Must not compile
LOG(0) << "type unsafe info";
LOG(1) << "type unsafe info";
LOG(2) << "type unsafe info";
LOG(3) << "type unsafe info";
}

View File

@ -0,0 +1,42 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sergiu Deitsch
#include <glog/logging.h>
int main() {
// Must not compile
google::LogMessage{__FILE__, __LINE__, -1};
// Cast to int to avoid implicit conversoin to nullptr
google::LogMessage{__FILE__, __LINE__, static_cast<int>(0)};
google::LogMessage{__FILE__, __LINE__, 1};
google::LogMessage{__FILE__, __LINE__, 2};
google::LogMessage{__FILE__, __LINE__, 3};
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,308 +0,0 @@
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=2 logtostderr=0 alsologtostderr=0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log error
WARNING: Logging before InitGoogleLogging() is written to STDERR
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info every 1 expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0 every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=0 logtostderr=0 alsologtostderr=0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info every 1 expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0 every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] foo bar 10 3.4
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Plog every 2, iteration 1: __SUCCESS__ [0]
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log every 3, iteration 1
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log every 4, iteration 1
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log if every 5, iteration 1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log if every 1, iteration 1
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log if less than 3 every 2, iteration 1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log if every 1, iteration 2
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Plog every 2, iteration 3: __ENOENT__ [2]
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log if every 1, iteration 3
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log if less than 3 every 2, iteration 3
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log every 3, iteration 4
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log if every 1, iteration 4
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Plog every 2, iteration 5: __EINTR__ [4]
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log every 4, iteration 5
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log if every 1, iteration 5
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log if every 5, iteration 6
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log if every 1, iteration 6
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Plog every 2, iteration 7: __ENXIO__ [6]
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log every 3, iteration 7
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log if every 1, iteration 7
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log if every 1, iteration 8
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Plog every 2, iteration 9: __ENOEXEC__ [8]
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log every 4, iteration 9
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log if every 1, iteration 9
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log every 3, iteration 10
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Log if every 1, iteration 10
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if this
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] array
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] const array
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] foo 1000 1000 3e8
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] foo 1
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] inner
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] outer
no prefix
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: foo bar 10 3.400000
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: array
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: const array
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: ptr __PTRTEST__
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: ptr __NULLP__
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: foo 1000 0000001000 3e8
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: foo 1000
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: foo 1000
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: RAW_LOG ERROR: The Message was too long!
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: RAW_LOG ERROR: The Message was too long!
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog 0 on
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog 1 on
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog 2 on
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=0 logtostderr=0 alsologtostderr=0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info every 1 expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0 every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Test: v=1 stderrthreshold=0 logtostderr=0 alsologtostderr=0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog 1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog 1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info every 1 expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0 every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Test: v=-1 stderrthreshold=0 logtostderr=0 alsologtostderr=0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info every 1 expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=1 logtostderr=0 alsologtostderr=0
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log error
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log error
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=2 logtostderr=0 alsologtostderr=0
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log error
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log error
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=3 logtostderr=0 alsologtostderr=0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=3 logtostderr=1 alsologtostderr=0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info every 1 expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0 every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Test: v=0 stderrthreshold=3 logtostderr=0 alsologtostderr=1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info every 1 expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0 every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Test: v=1 stderrthreshold=1 logtostderr=0 alsologtostderr=0
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log error
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log error
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Test: v=1 stderrthreshold=3 logtostderr=0 alsologtostderr=1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: vlog 1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: log error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog 1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if -1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if info every 1 expr
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] log_if error every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] vlog_if 0 every 1 expr
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_STRING: reported info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_STRING: reported warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_STRING: reported error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Captured by LOG_STRING: LOG_STRING: collected info
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Captured by LOG_STRING: LOG_STRING: collected warning
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Captured by LOG_STRING: LOG_STRING: collected error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_SINK: collected info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_SINK: collected warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_SINK: collected error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_SINK: reported info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_SINK: reported warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_SINK: reported error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Captured by LOG_TO_SINK:
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_SINK: collected info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_SINK: collected warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_SINK: collected error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_SINK_BUT_NOT_TO_LOGFILE: collected info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_SINK_BUT_NOT_TO_LOGFILE: collected warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_SINK_BUT_NOT_TO_LOGFILE: collected error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_STRING: collected info
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Captured by LOG_TO_STRING: LOG_TO_STRING: collected info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_STRING: collected warning
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Captured by LOG_TO_STRING: LOG_TO_STRING: collected warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_STRING: collected error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Captured by LOG_TO_STRING: LOG_TO_STRING: collected error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_STRING: reported info
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_STRING: reported warning
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] LOG_TO_STRING: reported error
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Message 1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Buffering
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Buffered
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Waiting
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Sink got a messages
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Waited
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Sink is sending out a message: IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Message 1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Have 0 left
EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Message 2
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Buffering
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Buffered
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Waiting
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Sink got a messages
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Waited
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Sink is sending out a message: EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Message 2
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Have 0 left
WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Message 3
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Buffering
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Buffered
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Waiting
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Sink got a messages
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] RAW: Waited
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Sink is sending out a message: WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Message 3
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Have 0 left
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Sink capture: IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Message 1
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Sink capture: EYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Message 2
IYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Sink capture: WYEARDATE TIME__ THREADID logging_custom_prefix_unittest.cc:LINE] Message 3

View File

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# #
# Copyright (c) 2007, Google Inc. # Copyright (c) 2023, Google Inc.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -32,15 +32,15 @@
# Author: Sergey Ioffe # Author: Sergey Ioffe
get_strings () { get_strings () {
if test -e ".libs/$1"; then if test -e "$1"; then
binary=".libs/$1" binary="$1"
elif test -e "$1.exe"; then elif test -e "$1.exe"; then
binary="$1.exe" binary="$1.exe"
else else
echo "We coundn't find $1 binary." echo "We coundn't find $1 binary."
exit 1 exit 1
fi fi
strings -n 10 $binary | sort | awk '/TESTMESSAGE/ {printf "%s ", $2}' strings -n 10 $binary | sort | awk '/TESTMESSAGE/ {printf "%s ", $2}'
} }
@ -60,20 +60,21 @@ die () {
# Check that the string literals are appropriately stripped. This will # Check that the string literals are appropriately stripped. This will
# not be the case in debug mode. # not be the case in debug mode.
mode=`GLOG_check_mode=1 ./logging_striptest0 2> /dev/null` mode=`GLOG_check_mode=1 ./striplog0_unittest 2> /dev/null`
echo $mode
if [ "$mode" = "opt" ]; if [ "$mode" = "opt" ];
then then
echo "In OPT mode" echo "In OPT mode"
check_eq "`get_strings logging_striptest0`" "COND ERROR FATAL INFO USAGE WARNING " check_eq "`get_strings striplog0_unittest`" "COND ERROR FATAL INFO WARNING "
check_eq "`get_strings logging_striptest2`" "COND ERROR FATAL USAGE " check_eq "`get_strings striplog2_unittest`" "COND ERROR FATAL "
check_eq "`get_strings logging_striptest10`" "" check_eq "`get_strings striplog10_unittest`" ""
else else
echo "In DBG mode; not checking strings" echo "In DBG mode; not checking strings"
fi fi
# Check that LOG(FATAL) aborts even for large STRIP_LOG # Check that LOG(FATAL) aborts even for large STRIP_LOG
./logging_striptest2 2>/dev/null && die "Did not abort for STRIP_LOG=2" ./striplog2_unittest 2>/dev/null && die "Did not abort for STRIP_LOG=2"
./logging_striptest10 2>/dev/null && die "Did not abort for STRIP_LOG=10" ./striplog10_unittest 2>/dev/null && die "Did not abort for STRIP_LOG=10"
echo "PASS" echo "PASS"

File diff suppressed because it is too large Load Diff

View File

@ -35,16 +35,15 @@
#ifndef GLOG_SRC_MOCK_LOG_H_ #ifndef GLOG_SRC_MOCK_LOG_H_
#define GLOG_SRC_MOCK_LOG_H_ #define GLOG_SRC_MOCK_LOG_H_
// For GOOGLE_NAMESPACE. This must go first so we get _XOPEN_SOURCE. // For google. This must go first so we get _XOPEN_SOURCE.
#include "utilities.h" #include <gmock/gmock.h>
#include <string> #include <string>
#include <gmock/gmock.h> #include "glog/logging.h"
#include "utilities.h"
#include <glog/logging.h> namespace google {
_START_GOOGLE_NAMESPACE_
namespace glog_testing { namespace glog_testing {
// A ScopedMockLog object intercepts LOG() messages issued during its // A ScopedMockLog object intercepts LOG() messages issued during its
@ -65,14 +64,14 @@ namespace glog_testing {
// //
// Foo(); // Exercises the code under test. // Foo(); // Exercises the code under test.
// } // }
class ScopedMockLog : public GOOGLE_NAMESPACE::LogSink { class ScopedMockLog : public google::LogSink {
public: public:
// When a ScopedMockLog object is constructed, it starts to // When a ScopedMockLog object is constructed, it starts to
// intercept logs. // intercept logs.
ScopedMockLog() { AddLogSink(this); } ScopedMockLog() { AddLogSink(this); }
// When the object is destructed, it stops intercepting logs. // When the object is destructed, it stops intercepting logs.
~ScopedMockLog() { RemoveLogSink(this); } ~ScopedMockLog() override { RemoveLogSink(this); }
// Implements the mock method: // Implements the mock method:
// //
@ -87,9 +86,9 @@ class ScopedMockLog : public GOOGLE_NAMESPACE::LogSink {
// for messages from different threads. In fact, if the same or multiple // for messages from different threads. In fact, if the same or multiple
// expectations are matched on two threads concurrently, their actions will // expectations are matched on two threads concurrently, their actions will
// be executed concurrently as well and may interleave. // be executed concurrently as well and may interleave.
MOCK_METHOD3(Log, void(GOOGLE_NAMESPACE::LogSeverity severity, MOCK_METHOD3(Log,
const std::string& file_path, void(google::LogSeverity severity, const std::string& file_path,
const std::string& message)); const std::string& message));
private: private:
// Implements the send() virtual function in class LogSink. // Implements the send() virtual function in class LogSink.
@ -113,11 +112,10 @@ class ScopedMockLog : public GOOGLE_NAMESPACE::LogSink {
// be running simultaneously, we ensure thread-safety of the exchange between // be running simultaneously, we ensure thread-safety of the exchange between
// send() and WaitTillSent(), and that for each message, LOG(), send(), // send() and WaitTillSent(), and that for each message, LOG(), send(),
// WaitTillSent() and Log() are executed in the same thread. // WaitTillSent() and Log() are executed in the same thread.
virtual void send(GOOGLE_NAMESPACE::LogSeverity severity, void send(google::LogSeverity severity, const char* full_filename,
const char* full_filename, const char* /*base_filename*/, int /*line*/,
const char* /*base_filename*/, int /*line*/, const LogMessageTime& /*logmsgtime*/, const char* message,
const LogMessageTime & /*logmsgtime*/, size_t message_len) override {
const char* message, size_t message_len) {
// We are only interested in the log severity, full file name, and // We are only interested in the log severity, full file name, and
// log message. // log message.
message_info_.severity = severity; message_info_.severity = severity;
@ -132,7 +130,7 @@ class ScopedMockLog : public GOOGLE_NAMESPACE::LogSink {
// //
// LOG(), send(), WaitTillSent() and Log() will occur in the same thread for // LOG(), send(), WaitTillSent() and Log() will occur in the same thread for
// a given log message. // a given log message.
virtual void WaitTillSent() { void WaitTillSent() override {
// First, and very importantly, we save a copy of the message being // First, and very importantly, we save a copy of the message being
// processed before calling Log(), since Log() may indirectly call send() // processed before calling Log(), since Log() may indirectly call send()
// and WaitTillSent() in the same thread again. // and WaitTillSent() in the same thread again.
@ -143,7 +141,7 @@ class ScopedMockLog : public GOOGLE_NAMESPACE::LogSink {
// All relevant information about a logged message that needs to be passed // All relevant information about a logged message that needs to be passed
// from send() to WaitTillSent(). // from send() to WaitTillSent().
struct MessageInfo { struct MessageInfo {
GOOGLE_NAMESPACE::LogSeverity severity; google::LogSeverity severity;
std::string file_path; std::string file_path;
std::string message; std::string message;
}; };
@ -151,6 +149,6 @@ class ScopedMockLog : public GOOGLE_NAMESPACE::LogSink {
}; };
} // namespace glog_testing } // namespace glog_testing
_END_GOOGLE_NAMESPACE_ } // namespace google
#endif // GLOG_SRC_MOCK_LOG_H_ #endif // GLOG_SRC_MOCK_LOG_H_

View File

@ -33,17 +33,17 @@
#include "mock-log.h" #include "mock-log.h"
#include <string>
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <string>
namespace { namespace {
using GOOGLE_NAMESPACE::GLOG_ERROR; using google::GLOG_ERROR;
using GOOGLE_NAMESPACE::GLOG_INFO; using google::GLOG_INFO;
using GOOGLE_NAMESPACE::GLOG_WARNING; using google::GLOG_WARNING;
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog; using google::glog_testing::ScopedMockLog;
using std::string; using std::string;
using testing::_; using testing::_;
using testing::EndsWith; using testing::EndsWith;
@ -57,8 +57,7 @@ TEST(ScopedMockLogTest, InterceptsLog) {
InSequence s; InSequence s;
EXPECT_CALL(log, EXPECT_CALL(log,
Log(GLOG_WARNING, EndsWith("mock-log_unittest.cc"), "Fishy.")); Log(GLOG_WARNING, EndsWith("mock-log_unittest.cc"), "Fishy."));
EXPECT_CALL(log, Log(GLOG_INFO, _, "Working...")) EXPECT_CALL(log, Log(GLOG_INFO, _, "Working...")).Times(2);
.Times(2);
EXPECT_CALL(log, Log(GLOG_ERROR, _, "Bad!!")); EXPECT_CALL(log, Log(GLOG_ERROR, _, "Bad!!"));
LOG(WARNING) << "Fishy."; LOG(WARNING) << "Fishy.";
@ -67,13 +66,9 @@ TEST(ScopedMockLogTest, InterceptsLog) {
LOG(ERROR) << "Bad!!"; LOG(ERROR) << "Bad!!";
} }
void LogBranch() { void LogBranch() { LOG(INFO) << "Logging a branch..."; }
LOG(INFO) << "Logging a branch...";
}
void LogTree() { void LogTree() { LOG(INFO) << "Logging the whole tree..."; }
LOG(INFO) << "Logging the whole tree...";
}
void LogForest() { void LogForest() {
LOG(INFO) << "Logging the entire forest."; LOG(INFO) << "Logging the entire forest.";
@ -99,8 +94,8 @@ TEST(ScopedMockLogTest, LogDuringIntercept) {
} // namespace } // namespace
int main(int argc, char **argv) { int main(int argc, char** argv) {
GOOGLE_NAMESPACE::InitGoogleLogging(argv[0]); google::InitGoogleLogging(argv[0]);
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
testing::InitGoogleMock(&argc, argv); testing::InitGoogleMock(&argc, argv);

View File

@ -1,6 +1,3 @@
#include <glog/logging.h> #include "glog/logging.h"
int main(int /*argc*/, char** argv) int main(int /*argc*/, char** argv) { google::InitGoogleLogging(argv[0]); }
{
google::InitGoogleLogging(argv[0]);
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2006, Google Inc. // Copyright (c) 2024, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -31,57 +31,60 @@
// //
// logging_unittest.cc covers the functionality herein // logging_unittest.cc covers the functionality herein
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <mutex>
#include <ostream>
#include <streambuf>
#include <thread>
#include "config.h"
#ifdef HAVE_UNISTD_H
# include <unistd.h> // for close() and write()
#endif
#if defined(HAVE_SYSCALL_H)
# include <syscall.h> // for syscall()
#elif defined(HAVE_SYS_SYSCALL_H)
# include <sys/syscall.h> // for syscall()
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h> // for open()
#include "glog/logging.h"
#include "glog/raw_logging.h"
#include "stacktrace.h"
#include "utilities.h" #include "utilities.h"
#include <stdarg.h> #if (defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)) && \
#include <cstdio> (!(defined(GLOG_OS_MACOSX)) && !(defined(GLOG_OS_OPENBSD))) && \
#include <cerrno> !defined(GLOG_OS_EMSCRIPTEN)
#ifdef HAVE_UNISTD_H # define safe_write(fd, s, len) syscall(SYS_write, fd, s, len)
# include <unistd.h> // for close() and write()
#endif
#include <fcntl.h> // for open()
#include <ctime>
#include "config.h"
#include <glog/logging.h> // To pick up flag settings etc.
#include <glog/raw_logging.h>
#include "base/commandlineflags.h"
#ifdef HAVE_STACKTRACE
# include "stacktrace.h"
#endif
#if defined(HAVE_SYSCALL_H)
#include <syscall.h> // for syscall()
#elif defined(HAVE_SYS_SYSCALL_H)
#include <sys/syscall.h> // for syscall()
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#if (defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)) && (!(defined(GLOG_OS_MACOSX)))
# define safe_write(fd, s, len) syscall(SYS_write, fd, s, len)
#else #else
// Not so safe, but what can you do? // Not so safe, but what can you do?
# define safe_write(fd, s, len) write(fd, s, len) # define safe_write(fd, s, len) write(fd, s, len)
#endif #endif
_START_GOOGLE_NAMESPACE_ namespace google {
#if defined(__GNUC__) #if defined(__GNUC__)
#define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck) \ # define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck) \
__attribute__((format(archetype, stringIndex, firstToCheck))) __attribute__((format(archetype, stringIndex, firstToCheck)))
#define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex) \ # define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex) \
__attribute__((format_arg(stringIndex))) __attribute__((format_arg(stringIndex)))
#else #else
#define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck) # define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck)
#define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex) # define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex)
#endif #endif
// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths // CAVEAT: std::vsnprintf called from *DoRawLog below has some (exotic) code
// that invoke malloc() and getenv() that might acquire some locks. // paths that invoke malloc() and getenv() that might acquire some locks. If
// If this becomes a problem we should reimplement a subset of vsnprintf // this becomes a problem we should reimplement a subset of std::vsnprintf that
// that does not need locks and malloc. // does not need locks and malloc.
// Helper for RawLog__ below. // Helper for RawLog__ below.
// *DoRawLog writes to *buf of *size and move them past the written portion. // *DoRawLog writes to *buf of *size and move them past the written portion.
@ -90,7 +93,7 @@ GLOG_ATTRIBUTE_FORMAT(printf, 3, 4)
static bool DoRawLog(char** buf, size_t* size, const char* format, ...) { static bool DoRawLog(char** buf, size_t* size, const char* format, ...) {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
int n = vsnprintf(*buf, *size, format, ap); int n = std::vsnprintf(*buf, *size, format, ap);
va_end(ap); va_end(ap);
if (n < 0 || static_cast<size_t>(n) > *size) return false; if (n < 0 || static_cast<size_t>(n) > *size) return false;
*size -= static_cast<size_t>(n); *size -= static_cast<size_t>(n);
@ -99,15 +102,15 @@ static bool DoRawLog(char** buf, size_t* size, const char* format, ...) {
} }
// Helper for RawLog__ below. // Helper for RawLog__ below.
inline static bool VADoRawLog(char** buf, size_t* size, inline static bool VADoRawLog(char** buf, size_t* size, const char* format,
const char* format, va_list ap) { va_list ap) {
#if defined(__GNUC__) #if defined(__GNUC__)
#pragma GCC diagnostic push # pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral" # pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif #endif
int n = vsnprintf(*buf, *size, format, ap); int n = std::vsnprintf(*buf, *size, format, ap);
#if defined(__GNUC__) #if defined(__GNUC__)
#pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
if (n < 0 || static_cast<size_t>(n) > *size) return false; if (n < 0 || static_cast<size_t>(n) > *size) return false;
*size -= static_cast<size_t>(n); *size -= static_cast<size_t>(n);
@ -116,9 +119,29 @@ inline static bool VADoRawLog(char** buf, size_t* size,
} }
static const int kLogBufSize = 3000; static const int kLogBufSize = 3000;
static bool crashed = false; static std::once_flag crashed;
static CrashReason crash_reason; static logging::internal::CrashReason crash_reason;
static char crash_buf[kLogBufSize + 1] = { 0 }; // Will end in '\0' static char crash_buf[kLogBufSize + 1] = {0}; // Will end in '\0'
namespace {
template <std::size_t N>
class StaticStringBuf : public std::streambuf {
public:
StaticStringBuf() {
setp(std::begin(data_), std::end(data_));
setg(std::begin(data_), std::begin(data_), std::end(data_));
}
const char* data() noexcept {
if (pptr() != pbase() && pptr() != epptr() && *(pptr() - 1) != '\0') {
sputc('\0');
}
return data_;
}
private:
char data_[N];
};
} // namespace
GLOG_ATTRIBUTE_FORMAT(printf, 4, 5) GLOG_ATTRIBUTE_FORMAT(printf, 4, 5)
void RawLog__(LogSeverity severity, const char* file, int line, void RawLog__(LogSeverity severity, const char* file, int line,
@ -128,16 +151,25 @@ void RawLog__(LogSeverity severity, const char* file, int line,
!IsGoogleLoggingInitialized())) { !IsGoogleLoggingInitialized())) {
return; // this stderr log message is suppressed return; // this stderr log message is suppressed
} }
// We do not have any any option other that string streams to obtain the
// thread identifier as the corresponding value is not convertible to an
// integer. Use a statically allocated buffer to avoid dynamic memory
// allocations.
StaticStringBuf<kLogBufSize> sbuf;
std::ostream oss(&sbuf);
oss << std::setw(5) << std::this_thread::get_id();
// can't call localtime_r here: it can allocate // can't call localtime_r here: it can allocate
char buffer[kLogBufSize]; char buffer[kLogBufSize];
char* buf = buffer; char* buf = buffer;
size_t size = sizeof(buffer); size_t size = sizeof(buffer);
// NOTE: this format should match the specification in base/logging.h // NOTE: this format should match the specification in base/logging.h
DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %5u %s:%d] RAW: ", DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %s %s:%d] RAW: ",
LogSeverityNames[severity][0], GetLogSeverityName(severity)[0], sbuf.data(),
static_cast<unsigned int>(GetTID()), const_basename(const_cast<char*>(file)), line);
const_basename(const_cast<char *>(file)), line);
// Record the position and size of the buffer after the prefix // Record the position and size of the buffer after the prefix
const char* msg_start = buf; const char* msg_start = buf;
@ -156,9 +188,9 @@ void RawLog__(LogSeverity severity, const char* file, int line,
// avoiding FILE buffering (to avoid invoking malloc()), and bypassing // avoiding FILE buffering (to avoid invoking malloc()), and bypassing
// libc (to side-step any libc interception). // libc (to side-step any libc interception).
// We write just once to avoid races with other invocations of RawLog__. // We write just once to avoid races with other invocations of RawLog__.
safe_write(STDERR_FILENO, buffer, strlen(buffer)); safe_write(fileno(stderr), buffer, strlen(buffer));
if (severity == GLOG_FATAL) { if (severity == GLOG_FATAL) {
if (!sync_val_compare_and_swap(&crashed, false, true)) { std::call_once(crashed, [file, line, msg_start, msg_size] {
crash_reason.filename = file; crash_reason.filename = file;
crash_reason.line_number = line; crash_reason.line_number = line;
memcpy(crash_buf, msg_start, msg_size); // Don't include prefix memcpy(crash_buf, msg_start, msg_size); // Don't include prefix
@ -170,9 +202,9 @@ void RawLog__(LogSeverity severity, const char* file, int line,
crash_reason.depth = 0; crash_reason.depth = 0;
#endif #endif
SetCrashReason(&crash_reason); SetCrashReason(&crash_reason);
} });
LogMessage::Fail(); // abort() LogMessage::Fail(); // abort()
} }
} }
_END_GOOGLE_NAMESPACE_ } // namespace google

View File

@ -1,4 +1,4 @@
// Copyright (c) 2008, Google Inc. // Copyright (c) 2024, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -31,22 +31,36 @@
// //
// Implementation of InstallFailureSignalHandler(). // Implementation of InstallFailureSignalHandler().
#include "utilities.h" #include <algorithm>
#include <csignal>
#include <cstring>
#include <ctime>
#include <mutex>
#include <sstream>
#include <thread>
#include "config.h"
#include "glog/logging.h"
#include "glog/platform.h"
#include "stacktrace.h" #include "stacktrace.h"
#include "symbolize.h" #include "symbolize.h"
#include <glog/logging.h> #include "utilities.h"
#include <csignal>
#include <ctime>
#ifdef HAVE_UCONTEXT_H #ifdef HAVE_UCONTEXT_H
# include <ucontext.h> # include <ucontext.h>
#endif #endif
#ifdef HAVE_SYS_UCONTEXT_H #ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h> # include <sys/ucontext.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#if defined(HAVE_SYS_SYSCALL_H) && defined(HAVE_SYS_TYPES_H)
# include <sys/syscall.h>
# include <sys/types.h>
#endif #endif
#include <algorithm>
_START_GOOGLE_NAMESPACE_ namespace google {
namespace { namespace {
@ -57,32 +71,31 @@ namespace {
// The list should be synced with the comment in signalhandler.h. // The list should be synced with the comment in signalhandler.h.
const struct { const struct {
int number; int number;
const char *name; const char* name;
} kFailureSignals[] = { } kFailureSignals[] = {
{ SIGSEGV, "SIGSEGV" }, {SIGSEGV, "SIGSEGV"}, {SIGILL, "SIGILL"},
{ SIGILL, "SIGILL" }, {SIGFPE, "SIGFPE"}, {SIGABRT, "SIGABRT"},
{ SIGFPE, "SIGFPE" },
{ SIGABRT, "SIGABRT" },
#if !defined(GLOG_OS_WINDOWS) #if !defined(GLOG_OS_WINDOWS)
{ SIGBUS, "SIGBUS" }, {SIGBUS, "SIGBUS"},
#endif #endif
{ SIGTERM, "SIGTERM" }, {SIGTERM, "SIGTERM"},
}; };
static bool kFailureSignalHandlerInstalled = false; static bool kFailureSignalHandlerInstalled = false;
#if !defined(GLOG_OS_WINDOWS) #if !defined(GLOG_OS_WINDOWS)
// Returns the program counter from signal context, NULL if unknown. // Returns the program counter from signal context, nullptr if unknown.
void* GetPC(void* ucontext_in_void) { void* GetPC(void* ucontext_in_void) {
#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT) # if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && \
if (ucontext_in_void != NULL) { defined(PC_FROM_UCONTEXT)
ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void); if (ucontext_in_void != nullptr) {
ucontext_t* context = reinterpret_cast<ucontext_t*>(ucontext_in_void);
return (void*)context->PC_FROM_UCONTEXT; return (void*)context->PC_FROM_UCONTEXT;
} }
#else # else
(void)ucontext_in_void; (void)ucontext_in_void;
#endif # endif
return NULL; return nullptr;
} }
#endif #endif
@ -90,14 +103,13 @@ void* GetPC(void* ucontext_in_void) {
// as it's not async signal safe. // as it's not async signal safe.
class MinimalFormatter { class MinimalFormatter {
public: public:
MinimalFormatter(char *buffer, size_t size) MinimalFormatter(char* buffer, size_t size)
: buffer_(buffer), : buffer_(buffer), cursor_(buffer), end_(buffer + size) {}
cursor_(buffer),
end_(buffer + size) {
}
// Returns the number of bytes written in the buffer. // Returns the number of bytes written in the buffer.
std::size_t num_bytes_written() const { return static_cast<std::size_t>(cursor_ - buffer_); } std::size_t num_bytes_written() const {
return static_cast<std::size_t>(cursor_ - buffer_);
}
// Appends string from "str" and updates the internal cursor. // Appends string from "str" and updates the internal cursor.
void AppendString(const char* str) { void AppendString(const char* str) {
@ -143,14 +155,14 @@ class MinimalFormatter {
} }
private: private:
char *buffer_; char* buffer_;
char *cursor_; char* cursor_;
const char * const end_; const char* const end_;
}; };
// Writes the given data with the size to the standard error. // Writes the given data with the size to the standard error.
void WriteToStderr(const char* data, size_t size) { void WriteToStderr(const char* data, size_t size) {
if (write(STDERR_FILENO, data, size) < 0) { if (write(fileno(stderr), data, size) < 0) {
// Ignore errors. // Ignore errors.
} }
} }
@ -161,7 +173,7 @@ void (*g_failure_writer)(const char* data, size_t size) = WriteToStderr;
// Dumps time information. We don't dump human-readable time information // Dumps time information. We don't dump human-readable time information
// as localtime() is not guaranteed to be async signal safe. // as localtime() is not guaranteed to be async signal safe.
void DumpTimeInfo() { void DumpTimeInfo() {
time_t time_in_sec = time(NULL); time_t time_in_sec = time(nullptr);
char buf[256]; // Big enough for time info. char buf[256]; // Big enough for time info.
MinimalFormatter formatter(buf, sizeof(buf)); MinimalFormatter formatter(buf, sizeof(buf));
formatter.AppendString("*** Aborted at "); formatter.AppendString("*** Aborted at ");
@ -174,15 +186,15 @@ void DumpTimeInfo() {
} }
// TODO(hamaji): Use signal instead of sigaction? // TODO(hamaji): Use signal instead of sigaction?
#ifdef HAVE_SIGACTION #if defined(HAVE_STACKTRACE) && defined(HAVE_SIGACTION)
// Dumps information about the signal to STDERR. // Dumps information about the signal to STDERR.
void DumpSignalInfo(int signal_number, siginfo_t *siginfo) { void DumpSignalInfo(int signal_number, siginfo_t* siginfo) {
// Get the signal name. // Get the signal name.
const char* signal_name = NULL; const char* signal_name = nullptr;
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) { for (auto kFailureSignal : kFailureSignals) {
if (signal_number == kFailureSignals[i].number) { if (signal_number == kFailureSignal.number) {
signal_name = kFailureSignals[i].name; signal_name = kFailureSignal.name;
} }
} }
@ -203,21 +215,25 @@ void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
formatter.AppendString(")"); formatter.AppendString(")");
formatter.AppendString(" received by PID "); formatter.AppendString(" received by PID ");
formatter.AppendUint64(static_cast<uint64>(getpid()), 10); formatter.AppendUint64(static_cast<uint64>(getpid()), 10);
formatter.AppendString(" (TID 0x"); formatter.AppendString(" (TID ");
// We assume pthread_t is an integral number or a pointer, rather
// than a complex struct. In some environments, pthread_self() std::ostringstream oss;
// returns an uint64 but in some other environments pthread_self() oss << std::showbase << std::hex << std::this_thread::get_id();
// returns a pointer. formatter.AppendString(oss.str().c_str());
pthread_t id = pthread_self(); # if defined(GLOG_OS_LINUX) && defined(HAVE_SYS_SYSCALL_H) && \
formatter.AppendUint64( defined(HAVE_SYS_TYPES_H)
reinterpret_cast<uint64>(reinterpret_cast<const char*>(id)), 16); pid_t tid = syscall(SYS_gettid);
formatter.AppendString(" LWP ");
formatter.AppendUint64(static_cast<uint64>(tid), 10);
# endif
formatter.AppendString(") "); formatter.AppendString(") ");
// Only linux has the PID of the signal sender in si_pid. // Only linux has the PID of the signal sender in si_pid.
#ifdef GLOG_OS_LINUX # ifdef GLOG_OS_LINUX
formatter.AppendString("from PID "); formatter.AppendString("from PID ");
formatter.AppendUint64(static_cast<uint64>(siginfo->si_pid), 10); formatter.AppendUint64(static_cast<uint64>(siginfo->si_pid), 10);
formatter.AppendString("; "); formatter.AppendString("; ");
#endif # endif
formatter.AppendString("stack trace: ***\n"); formatter.AppendString("stack trace: ***\n");
g_failure_writer(buf, formatter.num_bytes_written()); g_failure_writer(buf, formatter.num_bytes_written());
} }
@ -227,14 +243,19 @@ void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
// Dumps information about the stack frame to STDERR. // Dumps information about the stack frame to STDERR.
void DumpStackFrameInfo(const char* prefix, void* pc) { void DumpStackFrameInfo(const char* prefix, void* pc) {
// Get the symbol name. // Get the symbol name.
const char *symbol = "(unknown)"; const char* symbol = "(unknown)";
#if defined(HAVE_SYMBOLIZE)
char symbolized[1024]; // Big enough for a sane symbol. char symbolized[1024]; // Big enough for a sane symbol.
// Symbolizes the previous address of pc because pc may be in the // Symbolizes the previous address of pc because pc may be in the
// next function. // next function.
if (Symbolize(reinterpret_cast<char *>(pc) - 1, if (Symbolize(reinterpret_cast<char*>(pc) - 1, symbolized,
symbolized, sizeof(symbolized))) { sizeof(symbolized))) {
symbol = symbolized; symbol = symbolized;
} }
#else
# pragma message( \
"Symbolize functionality is not available for target platform: stack dump will contain empty frames.")
#endif // defined(HAVE_SYMBOLIZE)
char buf[1024]; // Big enough for stack frame info. char buf[1024]; // Big enough for stack frame info.
MinimalFormatter formatter(buf, sizeof(buf)); MinimalFormatter formatter(buf, sizeof(buf));
@ -256,7 +277,7 @@ void InvokeDefaultSignalHandler(int signal_number) {
memset(&sig_action, 0, sizeof(sig_action)); memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask); sigemptyset(&sig_action.sa_mask);
sig_action.sa_handler = SIG_DFL; sig_action.sa_handler = SIG_DFL;
sigaction(signal_number, &sig_action, NULL); sigaction(signal_number, &sig_action, nullptr);
kill(getpid(), signal_number); kill(getpid(), signal_number);
#elif defined(GLOG_OS_WINDOWS) #elif defined(GLOG_OS_WINDOWS)
signal(signal_number, SIG_DFL); signal(signal_number, SIG_DFL);
@ -264,53 +285,19 @@ void InvokeDefaultSignalHandler(int signal_number) {
#endif #endif
} }
// This variable is used for protecting FailureSignalHandler() from // This variable is used for protecting FailureSignalHandler() from dumping
// dumping stuff while another thread is doing it. Our policy is to let // stuff while another thread is doing it. Our policy is to let the first
// the first thread dump stuff and let other threads wait. // thread dump stuff and let other threads do nothing.
// See also comments in FailureSignalHandler(). // See also comments in FailureSignalHandler().
static pthread_t* g_entered_thread_id_pointer = NULL; static std::once_flag signaled;
// Dumps signal and stack frame information, and invokes the default static void HandleSignal(int signal_number
// signal handler once our job is done. #if !defined(GLOG_OS_WINDOWS)
#if defined(GLOG_OS_WINDOWS) ,
void FailureSignalHandler(int signal_number) siginfo_t* signal_info, void* ucontext
#else
void FailureSignalHandler(int signal_number,
siginfo_t *signal_info,
void *ucontext)
#endif #endif
{ ) {
// First check if we've already entered the function. We use an atomic
// compare and swap operation for platforms that support it. For other
// platforms, we use a naive method that could lead to a subtle race.
// We assume pthread_self() is async signal safe, though it's not
// officially guaranteed.
pthread_t my_thread_id = pthread_self();
// NOTE: We could simply use pthread_t rather than pthread_t* for this,
// if pthread_self() is guaranteed to return non-zero value for thread
// ids, but there is no such guarantee. We need to distinguish if the
// old value (value returned from __sync_val_compare_and_swap) is
// different from the original value (in this case NULL).
pthread_t* old_thread_id_pointer =
glog_internal_namespace_::sync_val_compare_and_swap(
&g_entered_thread_id_pointer,
static_cast<pthread_t*>(NULL),
&my_thread_id);
if (old_thread_id_pointer != NULL) {
// We've already entered the signal handler. What should we do?
if (pthread_equal(my_thread_id, *g_entered_thread_id_pointer)) {
// It looks the current thread is reentering the signal handler.
// Something must be going wrong (maybe we are reentering by another
// type of signal?). Kill ourself by the default signal handler.
InvokeDefaultSignalHandler(signal_number);
}
// Another thread is dumping stuff. Let's wait until that thread
// finishes the job and kills the process.
while (true) {
sleep(1);
}
}
// This is the first time we enter the signal handler. We are going to // This is the first time we enter the signal handler. We are going to
// do some interesting stuff from here. // do some interesting stuff from here.
// TODO(satorux): We might want to set timeout here using alarm(), but // TODO(satorux): We might want to set timeout here using alarm(), but
@ -321,22 +308,26 @@ void FailureSignalHandler(int signal_number,
#if !defined(GLOG_OS_WINDOWS) #if !defined(GLOG_OS_WINDOWS)
// Get the program counter from ucontext. // Get the program counter from ucontext.
void *pc = GetPC(ucontext); void* pc = GetPC(ucontext);
DumpStackFrameInfo("PC: ", pc); DumpStackFrameInfo("PC: ", pc);
#endif #endif
#ifdef HAVE_STACKTRACE #ifdef HAVE_STACKTRACE
// Get the stack traces. // Get the stack traces.
void *stack[32]; void* stack[32];
// +1 to exclude this function. // +1 to exclude this function.
const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1); const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
# ifdef HAVE_SIGACTION # ifdef HAVE_SIGACTION
DumpSignalInfo(signal_number, signal_info); DumpSignalInfo(signal_number, signal_info);
# endif # elif !defined(GLOG_OS_WINDOWS)
(void)signal_info;
# endif
// Dump the stack traces. // Dump the stack traces.
for (int i = 0; i < depth; ++i) { for (int i = 0; i < depth; ++i) {
DumpStackFrameInfo(" ", stack[i]); DumpStackFrameInfo(" ", stack[i]);
} }
#elif !defined(GLOG_OS_WINDOWS)
(void)signal_info;
#endif #endif
// *** TRANSITION *** // *** TRANSITION ***
@ -350,15 +341,30 @@ void FailureSignalHandler(int signal_number,
// Flush the logs before we do anything in case 'anything' // Flush the logs before we do anything in case 'anything'
// causes problems. // causes problems.
FlushLogFilesUnsafe(0); FlushLogFilesUnsafe(GLOG_INFO);
// Kill ourself by the default signal handler. // Kill ourself by the default signal handler.
InvokeDefaultSignalHandler(signal_number); InvokeDefaultSignalHandler(signal_number);
} }
} // namespace // Dumps signal and stack frame information, and invokes the default
// signal handler once our job is done.
#if defined(GLOG_OS_WINDOWS)
void FailureSignalHandler(int signal_number)
#else
void FailureSignalHandler(int signal_number, siginfo_t* signal_info,
void* ucontext)
#endif
{
std::call_once(signaled, &HandleSignal, signal_number
#if !defined(GLOG_OS_WINDOWS)
,
signal_info, ucontext
#endif
);
}
namespace glog_internal_namespace_ { } // namespace
bool IsFailureSignalHandlerInstalled() { bool IsFailureSignalHandlerInstalled() {
#ifdef HAVE_SIGACTION #ifdef HAVE_SIGACTION
@ -366,7 +372,7 @@ bool IsFailureSignalHandlerInstalled() {
struct sigaction sig_action; struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action)); memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask); sigemptyset(&sig_action.sa_mask);
sigaction(SIGABRT, NULL, &sig_action); sigaction(SIGABRT, nullptr, &sig_action);
if (sig_action.sa_sigaction == &FailureSignalHandler) { if (sig_action.sa_sigaction == &FailureSignalHandler) {
return true; return true;
} }
@ -376,8 +382,6 @@ bool IsFailureSignalHandlerInstalled() {
return false; return false;
} }
} // namespace glog_internal_namespace_
void InstallFailureSignalHandler() { void InstallFailureSignalHandler() {
#ifdef HAVE_SIGACTION #ifdef HAVE_SIGACTION
// Build the sigaction struct. // Build the sigaction struct.
@ -387,14 +391,13 @@ void InstallFailureSignalHandler() {
sig_action.sa_flags |= SA_SIGINFO; sig_action.sa_flags |= SA_SIGINFO;
sig_action.sa_sigaction = &FailureSignalHandler; sig_action.sa_sigaction = &FailureSignalHandler;
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) { for (auto kFailureSignal : kFailureSignals) {
CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL)); CHECK_ERR(sigaction(kFailureSignal.number, &sig_action, nullptr));
} }
kFailureSignalHandlerInstalled = true; kFailureSignalHandlerInstalled = true;
#elif defined(GLOG_OS_WINDOWS) #elif defined(GLOG_OS_WINDOWS)
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) { for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler), CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler), SIG_ERR);
SIG_ERR);
} }
kFailureSignalHandlerInstalled = true; kFailureSignalHandlerInstalled = true;
#endif // HAVE_SIGACTION #endif // HAVE_SIGACTION
@ -406,4 +409,4 @@ void InstallFailureWriter(void (*writer)(const char* data, size_t size)) {
#endif // HAVE_SIGACTION #endif // HAVE_SIGACTION
} }
_END_GOOGLE_NAMESPACE_ } // namespace google

View File

@ -1,4 +1,4 @@
// Copyright (c) 2008, Google Inc. // Copyright (c) 2024, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -32,51 +32,52 @@
// This is a helper binary for testing signalhandler.cc. The actual test // This is a helper binary for testing signalhandler.cc. The actual test
// is done in signalhandler_unittest.sh. // is done in signalhandler_unittest.sh.
#include "utilities.h"
#if defined(HAVE_PTHREAD)
# include <pthread.h>
#endif
#include <csignal> #include <csignal>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <sstream>
#include <string> #include <string>
#include <glog/logging.h> #include <thread>
#ifdef HAVE_LIB_GFLAGS #include "config.h"
#include <gflags/gflags.h> #include "glog/logging.h"
#include "stacktrace.h"
#include "symbolize.h"
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif
#ifdef GLOG_USE_GFLAGS
# include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE; using namespace GFLAGS_NAMESPACE;
#endif #endif
#if defined(_MSC_VER)
# include <io.h> // write
#endif
using namespace GOOGLE_NAMESPACE; using namespace google;
static void* DieInThread(void*) { static void DieInThread(int* a) {
// We assume pthread_t is an integral number or a pointer, rather std::ostringstream oss;
// than a complex struct. In some environments, pthread_self() oss << std::showbase << std::hex << std::this_thread::get_id();
// returns an uint64 but in some other environments pthread_self()
// returns a pointer. fprintf(stderr, "%s is dying\n", oss.str().c_str());
fprintf( int b = 1 / *a;
stderr, "0x%px is dying\n",
static_cast<const void*>(reinterpret_cast<const char*>(pthread_self())));
// Use volatile to prevent from these to be optimized away.
volatile int a = 0;
volatile int b = 1 / a;
fprintf(stderr, "We should have died: b=%d\n", b); fprintf(stderr, "We should have died: b=%d\n", b);
return NULL;
} }
static void WriteToStdout(const char* data, size_t size) { static void WriteToStdout(const char* data, size_t size) {
if (write(STDOUT_FILENO, data, size) < 0) { if (write(fileno(stdout), data, size) < 0) {
// Ignore errors. // Ignore errors.
} }
} }
int main(int argc, char **argv) { int main(int argc, char** argv) {
#if defined(HAVE_STACKTRACE) && defined(HAVE_SYMBOLIZE) #if defined(HAVE_STACKTRACE) && defined(HAVE_SYMBOLIZE)
InitGoogleLogging(argv[0]); InitGoogleLogging(argv[0]);
#ifdef HAVE_LIB_GFLAGS # ifdef GLOG_USE_GFLAGS
ParseCommandLineFlags(&argc, &argv, true); ParseCommandLineFlags(&argc, &argv, true);
#endif # endif
InstallFailureSignalHandler(); InstallFailureSignalHandler();
const std::string command = argc > 1 ? argv[1] : "none"; const std::string command = argc > 1 ? argv[1] : "none";
if (command == "segv") { if (command == "segv") {
@ -84,26 +85,21 @@ int main(int argc, char **argv) {
LOG(INFO) << "create the log file"; LOG(INFO) << "create the log file";
LOG(INFO) << "a message before segv"; LOG(INFO) << "a message before segv";
// We assume 0xDEAD is not writable. // We assume 0xDEAD is not writable.
int *a = (int*)0xDEAD; int* a = (int*)0xDEAD;
*a = 0; *a = 0;
} else if (command == "loop") { } else if (command == "loop") {
fprintf(stderr, "looping\n"); fprintf(stderr, "looping\n");
while (true); while (true)
;
} else if (command == "die_in_thread") { } else if (command == "die_in_thread") {
#if defined(HAVE_PTHREAD) std::thread t{&DieInThread, nullptr};
pthread_t thread; t.join();
pthread_create(&thread, NULL, &DieInThread, NULL);
pthread_join(thread, NULL);
#else
fprintf(stderr, "no pthread\n");
return 1;
#endif
} else if (command == "dump_to_stdout") { } else if (command == "dump_to_stdout") {
InstallFailureWriter(WriteToStdout); InstallFailureWriter(WriteToStdout);
abort(); abort();
} else if (command == "installed") { } else if (command == "installed") {
fprintf(stderr, "signal handler installed: %s\n", fprintf(stderr, "signal handler installed: %s\n",
IsFailureSignalHandlerInstalled() ? "true" : "false"); IsFailureSignalHandlerInstalled() ? "true" : "false");
} else { } else {
// Tell the shell script // Tell the shell script
puts("OK"); puts("OK");

38
src/stacktrace.cc Normal file
View File

@ -0,0 +1,38 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Routines to extract the current stack trace. These functions are
// thread-safe.
#include "stacktrace.h"
// Make an implementation of stacktrace compiled.
#if defined(STACKTRACE_H)
# include STACKTRACE_H
#endif

View File

@ -1,4 +1,4 @@
// Copyright (c) 2000 - 2007, Google Inc. // Copyright (c) 2024, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -30,13 +30,46 @@
// Routines to extract the current stack trace. These functions are // Routines to extract the current stack trace. These functions are
// thread-safe. // thread-safe.
#ifndef BASE_STACKTRACE_H_ #ifndef GLOG_INTERNAL_STACKTRACE_H
#define BASE_STACKTRACE_H_ #define GLOG_INTERNAL_STACKTRACE_H
#include "glog/platform.h"
#if defined(GLOG_USE_GLOG_EXPORT)
# include "glog/export.h"
#endif
#if !defined(GLOG_NO_EXPORT)
# error "stacktrace.h" was not included correctly.
#endif
#include "config.h" #include "config.h"
#include <glog/logging.h> #if defined(HAVE_LIBUNWIND)
# define STACKTRACE_H "stacktrace_libunwind-inl.h"
#elif defined(HAVE_UNWIND)
# define STACKTRACE_H "stacktrace_unwind-inl.h"
#elif !defined(NO_FRAME_POINTER)
# if defined(__i386__) && __GNUC__ >= 2
# define STACKTRACE_H "stacktrace_x86-inl.h"
# elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
# define STACKTRACE_H "stacktrace_powerpc-inl.h"
# elif defined(GLOG_OS_WINDOWS)
# define STACKTRACE_H "stacktrace_windows-inl.h"
# endif
#endif
_START_GOOGLE_NAMESPACE_ #if !defined(STACKTRACE_H) && defined(HAVE_EXECINFO_BACKTRACE)
# define STACKTRACE_H "stacktrace_generic-inl.h"
#endif
#if defined(STACKTRACE_H)
# define HAVE_STACKTRACE
#endif
namespace google {
inline namespace glog_internal_namespace_ {
#if defined(HAVE_STACKTRACE)
// This is similar to the GetStackFrames routine, except that it returns // This is similar to the GetStackFrames routine, except that it returns
// the stack trace only, and not the stack frame sizes as well. // the stack trace only, and not the stack frame sizes as well.
@ -53,9 +86,12 @@ _START_GOOGLE_NAMESPACE_
// result[1] main // result[1] main
// .... ... // .... ...
// //
// "result" must not be NULL. // "result" must not be nullptr.
GLOG_EXPORT int GetStackTrace(void** result, int max_depth, int skip_count); GLOG_NO_EXPORT int GetStackTrace(void** result, int max_depth, int skip_count);
_END_GOOGLE_NAMESPACE_ #endif // defined(HAVE_STACKTRACE)
#endif // BASE_STACKTRACE_H_ } // namespace glog_internal_namespace_
} // namespace google
#endif // GLOG_INTERNAL_STACKTRACE_H

View File

@ -32,15 +32,18 @@
// Note: The glibc implementation may cause a call to malloc. // Note: The glibc implementation may cause a call to malloc.
// This can cause a deadlock in HeapProfiler. // This can cause a deadlock in HeapProfiler.
#include <execinfo.h> #include <execinfo.h>
#include <string.h>
#include <cstring>
#include "stacktrace.h" #include "stacktrace.h"
_START_GOOGLE_NAMESPACE_ namespace google {
inline namespace glog_internal_namespace_ {
// If you change this function, also change GetStackFrames below. // If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) { int GetStackTrace(void** result, int max_depth, int skip_count) {
static const int kStackLength = 64; static const int kStackLength = 64;
void * stack[kStackLength]; void* stack[kStackLength];
int size; int size;
size = backtrace(stack, kStackLength); size = backtrace(stack, kStackLength);
@ -59,4 +62,5 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
return result_count; return result_count;
} }
_END_GOOGLE_NAMESPACE_ } // namespace glog_internal_namespace_
} // namespace google

View File

@ -37,10 +37,11 @@ extern "C" {
#define UNW_LOCAL_ONLY #define UNW_LOCAL_ONLY
#include <libunwind.h> #include <libunwind.h>
} }
#include <glog/raw_logging.h> #include "glog/raw_logging.h"
#include "stacktrace.h" #include "stacktrace.h"
_START_GOOGLE_NAMESPACE_ namespace google {
inline namespace glog_internal_namespace_ {
// Sometimes, we can try to get a stack trace from within a stack // Sometimes, we can try to get a stack trace from within a stack
// trace, because libunwind can call mmap (maybe indirectly via an // trace, because libunwind can call mmap (maybe indirectly via an
@ -51,11 +52,11 @@ _START_GOOGLE_NAMESPACE_
// cases, we return 0 to indicate the situation. // cases, we return 0 to indicate the situation.
// We can use the GCC __thread syntax here since libunwind is not supported on // We can use the GCC __thread syntax here since libunwind is not supported on
// Windows. // Windows.
static __thread bool g_tl_entered; // Initialized to false. static __thread bool g_tl_entered; // Initialized to false.
// If you change this function, also change GetStackFrames below. // If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) { int GetStackTrace(void** result, int max_depth, int skip_count) {
void *ip; void* ip;
int n = 0; int n = 0;
unw_cursor_t cursor; unw_cursor_t cursor;
unw_context_t uc; unw_context_t uc;
@ -67,11 +68,11 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
unw_getcontext(&uc); unw_getcontext(&uc);
RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, "unw_init_local failed"); RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, "unw_init_local failed");
skip_count++; // Do not include the "GetStackTrace" frame skip_count++; // Do not include the "GetStackTrace" frame
while (n < max_depth) { while (n < max_depth) {
int ret = int ret =
unw_get_reg(&cursor, UNW_REG_IP, reinterpret_cast<unw_word_t *>(&ip)); unw_get_reg(&cursor, UNW_REG_IP, reinterpret_cast<unw_word_t*>(&ip));
if (ret < 0) { if (ret < 0) {
break; break;
} }
@ -90,4 +91,5 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
return n; return n;
} }
_END_GOOGLE_NAMESPACE_ } // namespace glog_internal_namespace_
} // namespace google

View File

@ -35,37 +35,41 @@
// http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK // http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK
// Linux has similar code: http://patchwork.ozlabs.org/linuxppc/patch?id=8882 // Linux has similar code: http://patchwork.ozlabs.org/linuxppc/patch?id=8882
#include <cstdint> // for uintptr_t
#include <cstdio> #include <cstdio>
#include <stdint.h> // for uintptr_t
#include "stacktrace.h" #include "stacktrace.h"
_START_GOOGLE_NAMESPACE_ namespace google {
inline namespace glog_internal_namespace_ {
// Given a pointer to a stack frame, locate and return the calling // Given a pointer to a stack frame, locate and return the calling
// stackframe, or return NULL if no stackframe can be found. Perform sanity // stackframe, or return nullptr if no stackframe can be found. Perform sanity
// checks (the strictness of which is controlled by the boolean parameter // checks (the strictness of which is controlled by the boolean parameter
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. // "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
template<bool STRICT_UNWINDING> template <bool STRICT_UNWINDING>
static void **NextStackFrame(void **old_sp) { static void** NextStackFrame(void** old_sp) {
void **new_sp = static_cast<void **>(*old_sp); void** new_sp = static_cast<void**>(*old_sp);
// Check that the transition from frame pointer old_sp to frame // Check that the transition from frame pointer old_sp to frame
// pointer new_sp isn't clearly bogus // pointer new_sp isn't clearly bogus
if (STRICT_UNWINDING) { if (STRICT_UNWINDING) {
// With the stack growing downwards, older stack frame must be // With the stack growing downwards, older stack frame must be
// at a greater address that the current one. // at a greater address that the current one.
if (new_sp <= old_sp) return NULL; if (new_sp <= old_sp) return nullptr;
// Assume stack frames larger than 100,000 bytes are bogus. // Assume stack frames larger than 100,000 bytes are bogus.
if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL; if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return nullptr;
} else { } else {
// In the non-strict mode, allow discontiguous stack frames. // In the non-strict mode, allow discontiguous stack frames.
// (alternate-signal-stacks for example). // (alternate-signal-stacks for example).
if (new_sp == old_sp) return NULL; if (new_sp == old_sp) return nullptr;
// And allow frames upto about 1MB. // And allow frames upto about 1MB.
if ((new_sp > old_sp) if ((new_sp > old_sp) &&
&& ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return NULL; ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) {
return nullptr;
}
} }
if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL; if ((uintptr_t)new_sp & (sizeof(void*) - 1)) return nullptr;
return new_sp; return new_sp;
} }
@ -75,15 +79,15 @@ void StacktracePowerPCDummyFunction() { __asm__ volatile(""); }
// If you change this function, also change GetStackFrames below. // If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) { int GetStackTrace(void** result, int max_depth, int skip_count) {
void **sp; void** sp;
// Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther) // Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
// and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a // and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a
// different asm syntax. I don't know quite the best way to discriminate // different asm syntax. I don't know quite the best way to discriminate
// systems using the old as from the new one; I've gone with __APPLE__. // systems using the old as from the new one; I've gone with __APPLE__.
#ifdef __APPLE__ #ifdef __APPLE__
__asm__ volatile ("mr %0,r1" : "=r" (sp)); __asm__ volatile("mr %0,r1" : "=r"(sp));
#else #else
__asm__ volatile ("mr %0,1" : "=r" (sp)); __asm__ volatile("mr %0,1" : "=r"(sp));
#endif #endif
// On PowerPC, the "Link Register" or "Link Record" (LR), is a stack // On PowerPC, the "Link Register" or "Link Record" (LR), is a stack
@ -108,17 +112,18 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
// linux ppc64), it's in sp[2]. For SYSV (used by linux ppc), // linux ppc64), it's in sp[2]. For SYSV (used by linux ppc),
// it's in sp[1]. // it's in sp[1].
#if defined(_CALL_AIX) || defined(_CALL_DARWIN) #if defined(_CALL_AIX) || defined(_CALL_DARWIN)
result[n++] = *(sp+2); result[n++] = *(sp + 2);
#elif defined(_CALL_SYSV) #elif defined(_CALL_SYSV)
result[n++] = *(sp+1); result[n++] = *(sp + 1);
#elif defined(__APPLE__) || ((defined(__linux) || defined(__linux__)) && defined(__PPC64__)) #elif defined(__APPLE__) || \
((defined(__linux) || defined(__linux__)) && defined(__PPC64__))
// This check is in case the compiler doesn't define _CALL_AIX/etc. // This check is in case the compiler doesn't define _CALL_AIX/etc.
result[n++] = *(sp+2); result[n++] = *(sp + 2);
#elif defined(__linux) || defined(__OpenBSD__) #elif defined(__linux) || defined(__OpenBSD__)
// This check is in case the compiler doesn't define _CALL_SYSV. // This check is in case the compiler doesn't define _CALL_SYSV.
result[n++] = *(sp+1); result[n++] = *(sp + 1);
#else #else
#error Need to specify the PPC ABI for your archiecture. # error Need to specify the PPC ABI for your architecture.
#endif #endif
} }
// Use strict unwinding rules. // Use strict unwinding rules.
@ -127,4 +132,5 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
return n; return n;
} }
_END_GOOGLE_NAMESPACE_ } // namespace glog_internal_namespace_
} // namespace google

View File

@ -27,21 +27,20 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "utilities.h" #include "stacktrace.h"
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include "config.h"
#include "base/commandlineflags.h" #include "base/commandlineflags.h"
#include <glog/logging.h> #include "config.h"
#include "stacktrace.h" #include "glog/logging.h"
#include "utilities.h"
#ifdef HAVE_EXECINFO_H #ifdef HAVE_EXECINFO_BACKTRACE_SYMBOLS
# include <execinfo.h> # include <execinfo.h>
#endif #endif
using namespace GOOGLE_NAMESPACE;
#ifdef HAVE_STACKTRACE #ifdef HAVE_STACKTRACE
// Obtain a backtrace, verify that the expected callers are present in the // Obtain a backtrace, verify that the expected callers are present in the
@ -58,81 +57,87 @@ struct AddressRange {
// Expected function [start,end] range. // Expected function [start,end] range.
AddressRange expected_range[BACKTRACE_STEPS]; AddressRange expected_range[BACKTRACE_STEPS];
#if __GNUC__ # if __GNUC__
// Using GCC extension: address of a label can be taken with '&&label'. // Using GCC extension: address of a label can be taken with '&&label'.
// Start should be a label somewhere before recursive call, end somewhere // Start should be a label somewhere before recursive call, end somewhere
// after it. // after it.
#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \ # define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
do { \ do { \
(prange)->start = &&start_label; \ (prange)->start = &&start_label; \
(prange)->end = &&end_label; \ (prange)->end = &&end_label; \
CHECK_LT((prange)->start, (prange)->end); \ CHECK_LT((prange)->start, (prange)->end); \
} while (0) } while (0)
// This macro expands into "unmovable" code (opaque to GCC), and that // This macro expands into "unmovable" code (opaque to GCC), and that
// prevents GCC from moving a_label up or down in the code. // prevents GCC from moving a_label up or down in the code.
// Without it, there is no code following the 'end' label, and GCC // Without it, there is no code following the 'end' label, and GCC
// (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before // (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before
// the recursive call. // the recursive call.
#define DECLARE_ADDRESS_LABEL(a_label) \ # define DECLARE_ADDRESS_LABEL(a_label) \
a_label: do { __asm__ __volatile__(""); } while (0) a_label: \
do { \
__asm__ __volatile__(""); \
} while (0)
// Gcc 4.4.0 may split function into multiple chunks, and the chunk // Gcc 4.4.0 may split function into multiple chunks, and the chunk
// performing recursive call may end up later in the code then the return // performing recursive call may end up later in the code then the return
// instruction (this actually happens with FDO). // instruction (this actually happens with FDO).
// Adjust function range from __builtin_return_address. // Adjust function range from __builtin_return_address.
#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \ # define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
do { \ do { \
void *ra = __builtin_return_address(0); \ void* ra = __builtin_return_address(0); \
CHECK_LT((prange)->start, ra); \ CHECK_LT((prange)->start, ra); \
if (ra > (prange)->end) { \ if (ra > (prange)->end) { \
printf("Adjusting range from %p..%p to %p..%p\n", \ printf("Adjusting range from %p..%p to %p..%p\n", (prange)->start, \
(prange)->start, (prange)->end, \ (prange)->end, (prange)->start, ra); \
(prange)->start, ra); \ (prange)->end = ra; \
(prange)->end = ra; \ } \
} \ } while (0)
} while (0) # else
#else
// Assume the Check* functions below are not longer than 256 bytes. // Assume the Check* functions below are not longer than 256 bytes.
#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \ # define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
do { \ do { \
(prange)->start = reinterpret_cast<const void *>(&fn); \ (prange)->start = reinterpret_cast<const void*>(&fn); \
(prange)->end = reinterpret_cast<const char *>(&fn) + 256; \ (prange)->end = reinterpret_cast<const char*>(&fn) + 256; \
} while (0) } while (0)
#define DECLARE_ADDRESS_LABEL(a_label) do { } while (0) # define DECLARE_ADDRESS_LABEL(a_label) \
#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) do { } while (0) do { \
#endif // __GNUC__ } while (0)
# define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
do { \
} while (0)
# endif // __GNUC__
//-----------------------------------------------------------------------// //-----------------------------------------------------------------------//
static void CheckRetAddrIsInFunction(void *ret_addr, const AddressRange &range) static void CheckRetAddrIsInFunction(void* ret_addr,
{ const AddressRange& range) {
CHECK_GE(ret_addr, range.start); CHECK_GE(ret_addr, range.start);
CHECK_LE(ret_addr, range.end); CHECK_LE(ret_addr, range.end);
} }
//-----------------------------------------------------------------------// //-----------------------------------------------------------------------//
#if defined(__clang__) # if defined(__clang__)
#pragma clang diagnostic push # pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-label-as-value" # pragma clang diagnostic ignored "-Wgnu-label-as-value"
#endif # endif
void ATTRIBUTE_NOINLINE CheckStackTrace(int); void ATTRIBUTE_NOINLINE CheckStackTrace(int);
static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf(void) { static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf() {
const int STACK_LEN = 10; const int STACK_LEN = 10;
void *stack[STACK_LEN]; void* stack[STACK_LEN];
int size; int size;
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]); ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);
INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]); INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
DECLARE_ADDRESS_LABEL(start); DECLARE_ADDRESS_LABEL(start);
size = GetStackTrace(stack, STACK_LEN, 0); size = google::GetStackTrace(stack, STACK_LEN, 0);
printf("Obtained %d stack frames.\n", size); printf("Obtained %d stack frames.\n", size);
CHECK_GE(size, 1); CHECK_GE(size, 1);
CHECK_LE(size, STACK_LEN); CHECK_LE(size, STACK_LEN);
if (1) { if (true) {
#ifdef HAVE_EXECINFO_H # ifdef HAVE_EXECINFO_BACKTRACE_SYMBOLS
char **strings = backtrace_symbols(stack, size); char** strings = backtrace_symbols(stack, size);
printf("Obtained %d stack frames.\n", size); printf("Obtained %d stack frames.\n", size);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
printf("%s %p\n", strings[i], stack[i]); printf("%s %p\n", strings[i], stack[i]);
@ -145,11 +150,11 @@ static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf(void) {
printf("CheckStackTrace() addr: %p\n", p.p2); printf("CheckStackTrace() addr: %p\n", p.p2);
free(strings); free(strings);
#endif # endif
} }
for (int i = 0; i < BACKTRACE_STEPS; i++) { for (int i = 0; i < BACKTRACE_STEPS; i++) {
printf("Backtrace %d: expected: %p..%p actual: %p ... ", printf("Backtrace %d: expected: %p..%p actual: %p ... ", i,
i, expected_range[i].start, expected_range[i].end, stack[i]); expected_range[i].start, expected_range[i].end, stack[i]);
fflush(stdout); fflush(stdout);
CheckRetAddrIsInFunction(stack[i], expected_range[i]); CheckRetAddrIsInFunction(stack[i], expected_range[i]);
printf("OK\n"); printf("OK\n");
@ -197,7 +202,7 @@ static void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
DECLARE_ADDRESS_LABEL(end); DECLARE_ADDRESS_LABEL(end);
} }
#ifndef __GNUC__ # ifndef __GNUC__
// On non-GNU environment, we use the address of `CheckStackTrace` to // On non-GNU environment, we use the address of `CheckStackTrace` to
// guess the address range of this function. This guess is wrong for // guess the address range of this function. This guess is wrong for
// non-static function on Windows. This is probably because // non-static function on Windows. This is probably because
@ -205,8 +210,9 @@ static void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
// not the actual address of `CheckStackTrace`. // not the actual address of `CheckStackTrace`.
// See https://github.com/google/glog/issues/421 for the detail. // See https://github.com/google/glog/issues/421 for the detail.
static static
#endif # endif
void ATTRIBUTE_NOINLINE CheckStackTrace(int i) { void ATTRIBUTE_NOINLINE
CheckStackTrace(int i) {
INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]); INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
DECLARE_ADDRESS_LABEL(start); DECLARE_ADDRESS_LABEL(start);
for (int j = i; j >= 0; j--) { for (int j = i; j >= 0; j--) {
@ -215,15 +221,15 @@ void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
DECLARE_ADDRESS_LABEL(end); DECLARE_ADDRESS_LABEL(end);
} }
#if defined(__clang__) # if defined(__clang__)
#pragma clang diagnostic pop # pragma clang diagnostic pop
#endif # endif
//-----------------------------------------------------------------------// //-----------------------------------------------------------------------//
int main(int, char ** argv) { int main(int, char** argv) {
FLAGS_logtostderr = true; FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]); google::InitGoogleLogging(argv[0]);
CheckStackTrace(0); CheckStackTrace(0);
@ -233,7 +239,13 @@ int main(int, char ** argv) {
#else #else
int main() { int main() {
# ifdef GLOG_BAZEL_BUILD
printf("HAVE_STACKTRACE is expected to be defined in Bazel tests\n");
exit(EXIT_FAILURE);
# endif // GLOG_BAZEL_BUILD
printf("PASS (no stacktrace support)\n"); printf("PASS (no stacktrace support)\n");
return 0; return 0;
} }
#endif // HAVE_STACKTRACE #endif // HAVE_STACKTRACE

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