feat/update_config #10

Merged
tqcq merged 26 commits from feat/update_config into master 2024-10-14 10:15:01 +08:00
106 changed files with 1002 additions and 23052 deletions
Showing only changes of commit 635db57230 - Show all commits

View File

@ -7,6 +7,7 @@ set(tile_VERSION_BUILD $ENV{CI_STEP_NUMBER})
if (NOT tile_VERSION_BUILD) if (NOT tile_VERSION_BUILD)
set(tile_VERSION_BUILD "0") set(tile_VERSION_BUILD "0")
endif() endif()
set(TILE_VERSION "${tile_VERSION_MAJOR}.${tile_VERSION_MINOR}.${tile_VERSION_PATCH}.${tile_VERSION_BUILD}")
project( project(
tile tile
VERSION "${tile_VERSION_MAJOR}.${tile_VERSION_MINOR}.${tile_VERSION_PATCH}" VERSION "${tile_VERSION_MAJOR}.${tile_VERSION_MINOR}.${tile_VERSION_PATCH}"
@ -30,7 +31,7 @@ if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
endif() endif()
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug") set(CMAKE_BUILD_TYPE "Release")
endif() endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
@ -88,7 +89,7 @@ add_subdirectory("third_party/googletest")
add_subdirectory("third_party/gflags") add_subdirectory("third_party/gflags")
set(GFLAGS_USE_TARGET_NAMESPACE ON) set(GFLAGS_USE_TARGET_NAMESPACE ON)
set(gflags_DIR "${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags") set(gflags_DIR "${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags")
add_subdirectory("third_party/glog") # add_subdirectory("third_party/glog")
# add_subdirectory("third_party/context") # add_subdirectory("third_party/context")
set(CURL_DISABLE_TESTS ON) set(CURL_DISABLE_TESTS ON)
@ -166,6 +167,9 @@ set(TILE_SRCS
"tile/base/internal/thread_pool.cc" "tile/base/internal/thread_pool.cc"
"tile/base/internal/time_keeper.cc" "tile/base/internal/time_keeper.cc"
"tile/base/internal/time_keeper.h" "tile/base/internal/time_keeper.h"
"tile/base/logging/basic_file_sink.cc"
"tile/base/logging/splitter_sink.cc"
"tile/base/logging/console_sink.cc"
"tile/base/net/endpoint.cc" "tile/base/net/endpoint.cc"
"tile/base/object_pool/disabled.cc" "tile/base/object_pool/disabled.cc"
"tile/base/object_pool/global.cc" "tile/base/object_pool/global.cc"
@ -217,7 +221,7 @@ if((NOT TILE_HAVE_GETIFADDRS) OR (NOT TILE_HAVE_FREEIFADDRS))
list(APPEND TILE_SRCS "tile/base/net/detail/android/ifaddrs.c") list(APPEND TILE_SRCS "tile/base/net/detail/android/ifaddrs.c")
endif() endif()
add_library(tile OBJECT ${TILE_SRCS}) add_library(tile SHARED ${TILE_SRCS})
set_target_properties(tile PROPERTIES VERSION ${PROJECT_VERSION} set_target_properties(tile PROPERTIES VERSION ${PROJECT_VERSION}
target_precompile_headers(tile PUBLIC inja/inja.h) target_precompile_headers(tile PUBLIC inja/inja.h)
target_precompile_headers(tile PUBLIC inja/string_view.h) target_precompile_headers(tile PUBLIC inja/string_view.h)
@ -230,8 +234,8 @@ target_include_directories(
"${CMAKE_CURRENT_SOURCE_DIR}/third_party/mustache.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/third_party/mustache.hpp"
"${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/third_party/fmt/include" "${CMAKE_CURRENT_SOURCE_DIR}/third_party/fmt/include"
"${CMAKE_CURRENT_BINARY_DIR}/third_party/glog" # "${CMAKE_CURRENT_BINARY_DIR}/third_party/glog"
"${CMAKE_CURRENT_SOURCE_DIR}/third_party/glog/src" # "${CMAKE_CURRENT_SOURCE_DIR}/third_party/glog/src"
"${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}"
${THIRD_PARTY_INCLUDE_DIRS} ${THIRD_PARTY_INCLUDE_DIRS}
RPIVATE RPIVATE
@ -241,7 +245,7 @@ target_link_libraries(
tile tile
PUBLIC # -Wl,--start-group PUBLIC # -Wl,--start-group
# nova_context # nova_context
zlib gflags::gflags glog::glog zlib gflags::gflags # glog::glog
jsoncpp_static jsoncpp_static
# -Wl,--end-group # -Wl,--end-group
libcurl fmt) libcurl fmt)
@ -302,9 +306,7 @@ function(add_test_group prefix group_name)
# convert to relative path message(STATUS "${prefix} -> ${TEST_FILE}") # convert to relative path message(STATUS "${prefix} -> ${TEST_FILE}")
file(RELATIVE_PATH TEST_NAME "${prefix}" "${SRC_FILE}") file(RELATIVE_PATH TEST_NAME "${prefix}" "${SRC_FILE}")
string(REPLACE "/" "_" TEST_NAME "${TEST_NAME}") string(REPLACE "/" "_" TEST_NAME "${TEST_NAME}")
string(REPLACE ".cpp" "" TEST_NAME "${TEST_NAME}") string(REPLACE "_test.cc" "_test" TEST_NAME "${TEST_NAME}")
string(REPLACE ".cc" "" TEST_NAME "${TEST_NAME}")
string(REPLACE ".c" "" TEST_NAME "${TEST_NAME}")
# if group_name is not empty, add suffix _ # if group_name is not empty, add suffix _
if (NOT group_name STREQUAL "") if (NOT group_name STREQUAL "")
set(TEST_NAME "${group_name}_${TEST_NAME}") set(TEST_NAME "${group_name}_${TEST_NAME}")

View File

@ -1,8 +1,3 @@
## TILE ## TILE
一个`C++11`工具库,集成常见的编码工具 一个`C++11`工具库,集成常见的编码工具
## 编译状态
[![status-badge](https://ci.uocat.com/api/badges/2/status.svg)](https://ci.uocat.com/repos/2)

View File

@ -1,58 +0,0 @@
---
tasks:
ubuntu1804:
name: "Ubuntu 18.04"
platform: ubuntu1804
build_flags:
- "--features=layering_check"
- "--copt=-Werror"
build_targets:
- "//..."
test_flags:
- "--features=layering_check"
- "--copt=-Werror"
test_targets:
- "//..."
macos:
name: "macOS: latest Xcode"
platform: macos
build_flags:
- "--features=layering_check"
- "--copt=-Werror"
build_targets:
- "//..."
test_flags:
- "--features=layering_check"
- "--copt=-Werror"
test_targets:
- "//..."
windows-msvc:
name: "Windows: MSVC 2017"
platform: windows
environment:
BAZEL_VC: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools\\VC"
build_flags:
- "--features=layering_check"
- "--copt=/WX"
build_targets:
- "//..."
test_flags:
- "--features=layering_check"
- "--copt=/WX"
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:
- "--compiler=clang-cl"
- "--features=layering_check"
build_targets:
- "//..."
test_flags:
- "--compiler=clang-cl"
- "--features=layering_check"
test_targets:
- "//..."

View File

@ -1,168 +0,0 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: true
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
SortPriority: 0
- Regex: '^<.*\.h>'
Priority: 1
SortPriority: 0
- Regex: '^<.*'
Priority: 2
SortPriority: 0
- Regex: '.*'
Priority: 3
SortPriority: 0
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: true
IndentGotoLabels: true
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
Standard: Auto
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
...

View File

@ -1,59 +0,0 @@
---
Checks: 'clang-diagnostic-*,clang-analyzer-*,google-*'
WarningsAsErrors: ''
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
FormatStyle: file
CheckOptions:
- key: cert-dcl16-c.NewSuffixes
value: 'L;LL;LU;LLU'
- key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
value: '0'
- key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
value: '1'
- key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
value: '1'
- key: google-build-namespaces.HeaderFileExtensions
value: ',h,hh,hpp,hxx'
- key: google-global-names-in-headers.HeaderFileExtensions
value: ',h,hh,hpp,hxx'
- key: google-readability-braces-around-statements.ShortStatementLines
value: '1'
- key: google-readability-function-size.BranchThreshold
value: '4294967295'
- key: google-readability-function-size.LineThreshold
value: '4294967295'
- key: google-readability-function-size.NestingThreshold
value: '4294967295'
- key: google-readability-function-size.ParameterThreshold
value: '4294967295'
- key: google-readability-function-size.StatementThreshold
value: '800'
- key: google-readability-function-size.VariableThreshold
value: '4294967295'
- key: google-readability-namespace-comments.ShortNamespaceLines
value: '10'
- key: google-readability-namespace-comments.SpacesBeforeComments
value: '2'
- key: google-runtime-int.SignedTypePrefix
value: int
- key: google-runtime-int.TypeSuffix
value: ''
- key: google-runtime-int.UnsignedTypePrefix
value: uint
- key: google-runtime-references.WhiteListTypes
value: ''
- key: modernize-loop-convert.MaxCopySize
value: '16'
- key: modernize-loop-convert.MinConfidence
value: reasonable
- key: modernize-loop-convert.NamingStyle
value: CamelCase
- key: modernize-pass-by-value.IncludeStyle
value: llvm
- key: modernize-replace-auto-ptr.IncludeStyle
value: llvm
- key: modernize-use-nullptr.NullMacros
value: 'NULL'
...

View File

@ -1 +0,0 @@
*.h linguist-language=C++

View File

@ -1,51 +0,0 @@
name: Android
on: [push, pull_request]
jobs:
build-android:
name: NDK-C++${{matrix.std}}-${{matrix.abi}}-${{matrix.build_type}}
runs-on: ubuntu-latest
defaults:
run:
shell: bash
strategy:
fail-fast: true
matrix:
std: [98, 11, 14, 17, 20]
abi: [arm64-v8a, armeabi-v7a, x86_64, x86]
build_type: [Debug, Release]
steps:
- uses: actions/checkout@v2
- name: Setup Ninja
uses: ashutoshvarma/setup-ninja@master
with:
version: 1.10.0
- 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
env:
CXXFLAGS: -Wall -Wextra -Wpedantic -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror ${{env.CXXFLAGS}}
run: |
cmake -S . -B build_${{matrix.abi}} \
-DANDROID_ABI=${{matrix.abi}} \
-DANDROID_NATIVE_API_LEVEL=28 \
-DANDROID_STL=c++_shared \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DCMAKE_CXX_EXTENSIONS=OFF \
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
-DCMAKE_CXX_STANDARD_REQUIRED=ON \
-DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake \
-G Ninja \
-Werror
- name: Build
run: |
cmake --build build_${{matrix.abi}} \
--config ${{matrix.build_type}}

View File

@ -1,150 +0,0 @@
name: Linux
on: [push, pull_request]
jobs:
build-linux:
defaults:
run:
shell: bash
name: GCC-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.extra}}
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
build_type: [Release, Debug]
extra: [no-custom-prefix, custom-prefix]
lib: [shared, static]
std: [98, 11, 14, 17, 20]
steps:
- uses: actions/checkout@v2
- name: Setup Dependencies
run: |
sudo apt-get update
DEBIAN_FRONTEND=noninteractive sudo apt-get install -y \
build-essential \
cmake \
lcov \
libgflags-dev \
libunwind-dev \
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
if: matrix.build_type == 'Debug'
run: |
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
env:
CXXFLAGS: -Wall -Wextra -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror ${{env.CXXFLAGS}}
run: |
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 \
-DWITH_CUSTOM_PREFIX=${{matrix.extra == 'custom-prefix'}} \
-G Ninja \
-Werror
- name: Build
run: |
cmake --build build_${{matrix.build_type}} \
--config ${{matrix.build_type}}
- name: Install
run: |
cmake --build build_${{matrix.build_type}} \
--config ${{matrix.build_type}} \
--target install
cmake build_${{matrix.build_type}} \
-DCMAKE_INSTALL_INCLUDEDIR=${{runner.workspace}}/foo/include \
-DCMAKE_INSTALL_LIBDIR=${{runner.workspace}}/foo/lib \
-DCMAKE_INSTALL_DATAROOTDIR=${{runner.workspace}}/foo/share
cmake --build build_${{matrix.build_type}} \
--config ${{matrix.build_type}} \
--target install
- name: Test CMake Package (relative GNUInstallDirs)
run: |
cmake -S src/package_config_unittest/working_config \
-B build_${{matrix.build_type}}_package \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DCMAKE_PREFIX_PATH=${{github.workspace}}/install \
-G Ninja
cmake --build build_${{matrix.build_type}}_package \
--config ${{matrix.build_type}}
- name: Test CMake Package (absolute GNUInstallDirs)
run: |
cmake -S src/package_config_unittest/working_config \
-B build_${{matrix.build_type}}_package_foo \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DCMAKE_PREFIX_PATH=${{runner.workspace}}/foo \
-G Ninja
cmake --build build_${{matrix.build_type}}_package_foo \
--config ${{matrix.build_type}}
- name: Test
run: |
ctest --test-dir build_${{matrix.build_type}} -j$(nproc) --output-on-failure
- name: Generate Coverage
if: matrix.build_type == 'Debug'
run: |
lcov --directory . --capture --output-file coverage.info
lcov --remove coverage.info \
'${{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
if: matrix.build_type == 'Debug'
uses: codecov/codecov-action@v2
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
verbose: true

View File

@ -1,83 +0,0 @@
name: macOS
on: [push, pull_request]
jobs:
build-macos:
name: AppleClang-C++${{matrix.std}}-${{matrix.build_type}}
runs-on: macos-10.15
strategy:
fail-fast: true
matrix:
std: [98, 11, 14, 17, 20]
include:
- generator: Ninja
- build_type: Debug
steps:
- uses: actions/checkout@v2
- name: Setup Ninja
uses: ashutoshvarma/setup-ninja@master
with:
version: 1.10.0
- name: Setup Dependencies
run: |
brew install lcov
- name: Setup Environment
if: matrix.build_type == 'Debug'
run: |
echo 'CXXFLAGS=--coverage' >> $GITHUB_ENV
- name: Configure
shell: bash
env:
CXXFLAGS: -Wall -Wextra -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror ${{env.CXXFLAGS}}
run: |
cmake -S . -B build_${{matrix.build_type}} \
-DCMAKE_CXX_EXTENSIONS=OFF \
-DCMAKE_CXX_FLAGS_DEBUG=-pedantic-errors \
-DCMAKE_CXX_FLAGS_RELEASE=-pedantic-errors \
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
-DCMAKE_CXX_STANDARD_REQUIRED=ON \
-G "${{matrix.generator}}" \
-Werror
- name: Build
run: |
cmake --build build_${{matrix.build_type}} \
--config ${{matrix.build_type}}
- name: Test
run: |
ctest --test-dir build_${{matrix.build_type}} \
--output-on-failure
- name: Generate Coverage
if: matrix.build_type == 'Debug'
run: |
lcov --directory . --capture --output-file coverage.info
lcov --remove coverage.info \
'*/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|${{github.workspace}}/glog/${name_we}.h\$|${file}|g" coverage.info
done
lcov --list coverage.info
- name: Upload Coverage to Codecov
if: matrix.build_type == 'Debug'
uses: codecov/codecov-action@v2
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
verbose: true

View File

@ -1,234 +0,0 @@
name: Windows
on: [push, pull_request]
jobs:
build-msvc:
name: ${{matrix.msvc}}-${{matrix.arch}}-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.extra}}
runs-on: ${{matrix.os}}
defaults:
run:
shell: powershell
env:
CL: /MP
CXXFLAGS: /WX /permissive-
strategy:
fail-fast: true
matrix:
arch: [Win32, x64]
build_type: [Debug, Release]
extra: [no-custom-prefix, custom-prefix]
lib: [shared, static]
msvc: [VS-16-2019, VS-17-2022]
# Visual Studio 17 2022 does not support C++11 and older language standard
std: [14, 17, 20]
include:
- msvc: VS-16-2019
os: windows-2019
generator: 'Visual Studio 16 2019'
- msvc: VS-17-2022
os: windows-2022
generator: 'Visual Studio 17 2022'
steps:
- uses: actions/checkout@v2
- name: Cache GTest
id: cache-gtest
uses: actions/cache@v2
with:
path: gtest/
key: ${{runner.os}}-gtest-1.11-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}}
- name: Download GTest
if: steps.cache-gtest.outputs.cache-hit != 'true'
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")
Expand-Archive release-1.11.0.zip .
- name: Build GTest
if: steps.cache-gtest.outputs.cache-hit != 'true'
run: |
cmake -S googletest-release-1.11.0 -B build-googletest `
-A ${{matrix.arch}} `
-DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `
-Dgtest_force_shared_crt=ON `
-DCMAKE_INSTALL_PREFIX=${{github.workspace}}/gtest
cmake --build build-googletest `
--config ${{matrix.build_type}} `
--target install
- name: Cache gflags
id: cache-gflags
uses: actions/cache@v2
with:
path: gflags/
key: ${{runner.os}}-gflags-2.2.2-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}}
- name: Download gflags
if: steps.cache-gflags.outputs.cache-hit != 'true'
run: |
(New-Object System.Net.WebClient).DownloadFile("https://github.com/gflags/gflags/archive/refs/tags/v2.2.2.zip", "v2.2.2.zip")
Expand-Archive v2.2.2.zip .
- name: Build gflags
if: steps.cache-gflags.outputs.cache-hit != 'true'
run: |
cmake -S gflags-2.2.2 -B build-gflags `
-A ${{matrix.arch}} `
-DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `
-DCMAKE_INSTALL_PREFIX=${{github.workspace}}/gflags
cmake --build build-gflags `
--config ${{matrix.build_type}} `
--target install
- name: Setup Environment
run: |
echo "GTest_ROOT=$((Get-Item .).FullName)/gtest" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
echo "gflags_ROOT=$((Get-Item .).FullName)/gflags" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
echo "${{github.workspace}}/gtest/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
echo "${{github.workspace}}/gflags/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Setup Release Environment
if: matrix.build_type != 'Debug'
run: |
echo "CXXFLAGS=/Zi ${{env.CXXFLAGS}}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
- name: Configure
run: |
cmake -S . -B build_${{matrix.build_type}} `
-A ${{matrix.arch}} `
-DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `
-DCMAKE_CXX_EXTENSIONS=OFF `
-DCMAKE_CXX_STANDARD=${{matrix.std}} `
-DCMAKE_CXX_STANDARD_REQUIRED=ON `
-DCMAKE_EXE_LINKER_FLAGS='/NOIMPLIB' `
-DCMAKE_EXE_LINKER_FLAGS_RELEASE='/INCREMENTAL:NO /DEBUG' `
-DCMAKE_INSTALL_PREFIX:PATH=./install `
-DCMAKE_MSVC_RUNTIME_LIBRARY='MultiThreaded$<$<CONFIG:Debug>:Debug>DLL' `
-DWITH_CUSTOM_PREFIX=${{matrix.extra == 'custom-prefix'}} `
-G "${{matrix.generator}}" `
-Werror
- name: Build
run: cmake --build build_${{matrix.build_type}} `
--config ${{matrix.build_type}}
- name: Test
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: |
cmake --build build_${{matrix.build_type}}/ `
--config ${{matrix.build_type}} `
--target RUN_TESTS
- name: Install
run: |
cmake --build build_${{matrix.build_type}}/ `
--config ${{matrix.build_type}} `
--target install
build-mingw:
name: ${{matrix.sys}}-${{matrix.env}}-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.extra}}
runs-on: windows-2022
env:
BUILDDIR: 'build_${{matrix.sys}}-${{matrix.env}}-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.extra}}'
defaults:
run:
shell: msys2 {0}
strategy:
fail-fast: true
matrix:
build_type: [Debug]
extra: [no-custom-prefix, custom-prefix]
lib: [shared, static]
std: [98, 11, 14, 17, 20]
sys: [mingw32, mingw64]
include:
- sys: mingw32
env: i686
- sys: mingw64
env: x86_64
steps:
- uses: actions/checkout@v2
- uses: msys2/setup-msys2@v2
with:
msystem: ${{matrix.sys}}
install: >-
lcov
mingw-w64-${{matrix.env}}-cmake
mingw-w64-${{matrix.env}}-gcc
mingw-w64-${{matrix.env}}-gflags
mingw-w64-${{matrix.env}}-ninja
- 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: Setup Environment
if: matrix.build_type == 'Debug'
run: |
echo 'CXXFLAGS=--coverage ${{env.CXXFLAGS}}' >> $GITHUB_ENV
- name: Configure
env:
CXXFLAGS: -Wall -Wextra -Wpedantic -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror ${{env.CXXFLAGS}}
run: |
cmake -S . -B build_${{matrix.build_type}}/ \
-DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DCMAKE_CXX_EXTENSIONS=OFF \
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
-DCMAKE_CXX_STANDARD_REQUIRED=ON \
-DCMAKE_INSTALL_PREFIX:PATH=./install \
-DWITH_CUSTOM_PREFIX=${{matrix.extra == 'custom-prefix'}} \
-G Ninja \
-Werror
- name: Build
run: |
cmake --build build_${{matrix.build_type}}/ --config ${{matrix.build_type}}
- name: Test
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: |
cmake --build build_${{matrix.build_type}}/ --config ${{matrix.build_type}} \
--target test
- name: Install
run: |
cmake --build build_${{matrix.build_type}}/ \
--config ${{matrix.build_type}} \
--target install
- name: Generate Coverage
if: matrix.build_type == 'Debug'
run: |
lcov --directory . --capture --output-file coverage.info
lcov --remove coverage.info \
'*/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
if: matrix.build_type == 'Debug'
uses: codecov/codecov-action@v2
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
verbose: true

View File

@ -1,3 +0,0 @@
*.orig
/build*/
bazel-*

View File

@ -1,29 +0,0 @@
# This is the official list of glog authors for copyright purposes.
# This file is distinct from the CONTRIBUTORS files.
# See the latter for an explanation.
#
# Names should be added to this file as:
# Name or Organization <email address>
# The email address is not required for organizations.
#
# Please keep the list sorted.
Abhishek Dasgupta <abhi2743@gmail.com>
Abhishek Parmar <abhishek@orng.net>
Andrew Schwartzmeyer <andrew@schwartzmeyer.com>
Andy Ying <andy@trailofbits.com>
Brian Silverman <bsilver16384@gmail.com>
Dmitriy Arbitman <d.arbitman@gmail.com>
Google Inc.
Guillaume Dumont <dumont.guillaume@gmail.com>
Marco Wang <m.aesophor@gmail.com>
Michael Tanner <michael@tannertaxpro.com>
MiniLight <MiniLightAR@Gmail.com>
romange <romange@users.noreply.github.com>
Roman Perepelitsa <roman.perepelitsa@gmail.com>
Sergiu Deitsch <sergiu.deitsch@gmail.com>
tbennun <tbennun@gmail.com>
Teddy Reed <teddy@prosauce.org>
Vijaymahantesh Sattigeri <vijaymahantesh016@gmail.com>
Zhongming Qu <qzmfranklin@gmail.com>
Zhuoran Shen <cmsflash99@gmail.com>

View File

@ -1,22 +0,0 @@
licenses(["notice"])
exports_files(["COPYING"])
load(":bazel/glog.bzl", "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",
"@bazel_tools//tools/cpp:clang-cl",
],
)

File diff suppressed because it is too large Load Diff

View File

@ -1,52 +0,0 @@
# People who have agreed to one of the CLAs and can contribute patches.
# The AUTHORS file lists the copyright holders; this file
# lists people. For example, Google employees are listed here
# but not in AUTHORS, because Google holds the copyright.
#
# Names should be added to this file only after verifying that
# the individual or the individual's organization has agreed to
# the appropriate Contributor License Agreement, found here:
#
# https://developers.google.com/open-source/cla/individual
# https://developers.google.com/open-source/cla/corporate
#
# The agreement for individuals can be filled out on the web.
#
# When adding J Random Contributor's name to this file,
# either J's name or J's organization's name should be
# added to the AUTHORS file, depending on whether the
# individual or corporate CLA was used.
#
# Names should be added to this file as:
# Name <email address>
#
# Please keep the list sorted.
Abhishek Dasgupta <abhi2743@gmail.com>
Abhishek Parmar <abhishek@orng.net>
Andrew Schwartzmeyer <andrew@schwartzmeyer.com>
Andy Ying <andy@trailofbits.com>
Bret McKee <bretmckee@google.com>
Brian Silverman <bsilver16384@gmail.com>
Dmitriy Arbitman <d.arbitman@gmail.com>
Fumitoshi Ukai <ukai@google.com>
Guillaume Dumont <dumont.guillaume@gmail.com>
Håkan L. S. Younes <hyounes@google.com>
Ivan Penkov <ivanpe@google.com>
Jacob Trimble <modmaker@google.com>
Jim Ray <jimray@google.com>
Marco Wang <m.aesophor@gmail.com>
Michael Darr <mdarr@matician.com>
Michael Tanner <michael@tannertaxpro.com>
MiniLight <MiniLightAR@Gmail.com>
Peter Collingbourne <pcc@google.com>
Rodrigo Queiro <rodrigoq@google.com>
romange <romange@users.noreply.github.com>
Roman Perepelitsa <roman.perepelitsa@gmail.com>
Sergiu Deitsch <sergiu.deitsch@gmail.com>
Shinichiro Hamaji <hamaji@google.com>
tbennun <tbennun@gmail.com>
Teddy Reed <teddy@prosauce.org>
Vijaymahantesh Sattigeri <vijaymahantesh016@gmail.com>
Zhongming Qu <qzmfranklin@gmail.com>
Zhuoran Shen <cmsflash99@gmail.com>

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,109 +0,0 @@
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>
* google-glog: version 0.5.0.
* See git log for the details.
2019-01-22 Google Inc. <opensource@google.com>
* google-glog: version 0.4.0.
* See git log for the details.
2017-05-09 Google Inc. <opensource@google.com>
* google-glog: version 0.3.5
* See git log for the details.
2015-03-09 Google Inc. <opensource@google.com>
* google-glog: version 0.3.4
* See git log for the details.
2013-02-01 Google Inc. <opensource@google.com>
* google-glog: version 0.3.3
* Add --disable-rtti option for configure.
* Visual Studio build and test fix.
* QNX build fix (thanks vanuan).
* Reduce warnings.
* Fixed LOG_SYSRESULT (thanks ukai).
* FreeBSD build fix (thanks yyanagisawa).
* Clang build fix.
* Now users can re-initialize glog after ShutdownGoogleLogging.
* Color output support by GLOG_colorlogtostderr (thanks alexs).
* Now glog's ABI around flags are compatible with gflags.
* Document mentions how to modify flags from user programs.
2012-01-12 Google Inc. <opensource@google.com>
* google-glog: version 0.3.2
* Clang support.
* Demangler and stacktrace improvement for newer GCCs.
* Now fork(2) doesn't mess up log files.
* Make valgrind happier.
* Reduce warnings for more -W options.
* Provide a workaround for ERROR defined by windows.h.
2010-06-15 Google Inc. <opensource@google.com>
* google-glog: version 0.3.1
* GLOG_* environment variables now work even when gflags is installed.
* Snow leopard support.
* Now we can build and test from out side tree.
* Add DCHECK_NOTNULL.
* Add ShutdownGoogleLogging to close syslog (thanks DGunchev)
* Fix --enable-frame-pointers option (thanks kazuki.ohta)
* Fix libunwind detection (thanks giantchen)
2009-07-30 Google Inc. <opensource@google.com>
* google-glog: version 0.3.0
* Fix a deadlock happened when user uses glog with recent gflags.
* Suppress several unnecessary warnings (thanks keir).
* NetBSD and OpenBSD support.
* Use Win32API GetComputeNameA properly (thanks magila).
* Fix user name detection for Windows (thanks ademin).
* Fix several minor bugs.
2009-04-10 Google Inc. <opensource@google.com>
* google-glog: version 0.2.1
* Fix timestamps of VC++ version.
* Add pkg-config support (thanks Tomasz)
* Fix build problem when building with gtest (thanks Michael)
* Add --with-gflags option for configure (thanks Michael)
* Fixes for GCC 4.4 (thanks John)
2009-01-23 Google Inc. <opensource@google.com>
* google-glog: version 0.2
* Add initial Windows VC++ support.
* Google testing/mocking frameworks integration.
* Link pthread library automatically.
* Flush logs in signal handlers.
* Add macros LOG_TO_STRING, LOG_AT_LEVEL, DVLOG, and LOG_TO_SINK_ONLY.
* Log microseconds.
* Add --log_backtrace_at option.
* Fix some minor bugs.
2008-11-18 Google Inc. <opensource@google.com>
* google-glog: version 0.1.2
* Add InstallFailureSignalHandler(). (satorux)
* Re-organize the way to produce stacktraces.
* Don't define unnecessary macro DISALLOW_EVIL_CONSTRUCTORS.
2008-10-15 Google Inc. <opensource@google.com>
* google-glog: version 0.1.1
* Support symbolize for MacOSX 10.5.
* BUG FIX: --vmodule didn't work with gflags.
* BUG FIX: symbolize_unittest failed with GCC 4.3.
* Several fixes on the document.
2008-10-07 Google Inc. <opensource@google.com>
* google-glog: initial release:
The glog package contains a library that implements application-level
logging. This library provides logging APIs based on C++-style
streams and various helper macros.

View File

@ -1,879 +0,0 @@
Google Logging Library
======================
|Linux Github actions| |Windows Github actions| |macOS Github actions| |Total alerts| |Language grade: C++| |Codecov|
Google Logging (glog) is a C++98 library that implements application-level
logging. The library provides logging APIs based on C++-style streams and
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
---------------
You can log a message by simply streaming things to ``LOG``\ (<a
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
:target: https://github.com/google/glog/actions
.. |Windows Github actions| image:: https://github.com/google/glog/actions/workflows/windows.yml/badge.svg
:target: https://github.com/google/glog/actions
.. |macOS Github actions| image:: https://github.com/google/glog/actions/workflows/macos.yml/badge.svg
: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
: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",
],
)

View File

@ -1,9 +0,0 @@
cc_test(
name = "main",
size = "small",
srcs = ["main.cc"],
deps = [
"//:glog",
"@com_github_gflags_gflags//:gflags",
],
)

View File

@ -1,22 +0,0 @@
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <glog/stl_logging.h>
int main(int argc, char* argv[]) {
// Initialize Google's logging library.
google::InitGoogleLogging(argv[0]);
// Optional: parse command line flags
gflags::ParseCommandLineFlags(&argc, &argv, true);
LOG(INFO) << "Hello, world!";
// glog/stl_logging.h allows logging STL containers.
std::vector<int> x;
x.push_back(1);
x.push_back(2);
x.push_back(3);
LOG(INFO) << "ABC, it's easy as " << x;
return 0;
}

View File

@ -1,276 +0,0 @@
# Implement a macro glog_library() that the BUILD.bazel file can load.
# By default, glog is built with gflags support. You can change this behavior
# by using glog_library(with_gflags=0)
#
# This file is inspired by the following sample BUILD files:
# https://github.com/google/glog/issues/61
# https://github.com/google/glog/files/393474/BUILD.txt
#
# Known issue: the namespace parameter is not supported on Win32.
def expand_template_impl(ctx):
ctx.actions.expand_template(
template = ctx.file.template,
output = ctx.outputs.out,
substitutions = ctx.attr.substitutions,
)
expand_template = rule(
implementation = expand_template_impl,
attrs = {
"template": attr.label(mandatory = True, allow_single_file = True),
"substitutions": attr.string_dict(mandatory = True),
"out": attr.output(mandatory = True),
},
)
def dict_union(x, y):
z = {}
z.update(x)
z.update(y)
return z
def glog_library(namespace = "google", with_gflags = 1, **kwargs):
if native.repository_name() != "@":
repo_name = native.repository_name().lstrip("@")
gendir = "$(GENDIR)/external/" + repo_name
src_windows = "external/%s/src/windows" % repo_name
else:
gendir = "$(GENDIR)"
src_windows = "src/windows"
# Config setting for WebAssembly target.
native.config_setting(
name = "wasm",
values = {"cpu": "wasm"},
)
# Detect when building with clang-cl on Windows.
native.config_setting(
name = "clang-cl",
values = {"compiler": "clang-cl"},
)
common_copts = [
"-DGLOG_BAZEL_BUILD",
# 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,
] + (["-DHAVE_LIB_GFLAGS"] if with_gflags else [])
wasm_copts = [
# Disable warnings that exists in glog.
"-Wno-sign-compare",
"-Wno-unused-function",
"-Wno-unused-local-typedefs",
"-Wno-unused-variable",
# Allows src/base/mutex.h to include pthread.h.
"-DHAVE_PTHREAD",
# Allows src/logging.cc to determine the host name.
"-DHAVE_SYS_UTSNAME_H",
# For src/utilities.cc.
"-DHAVE_SYS_TIME_H",
"-DHAVE_UNWIND_H",
# Enable dumping stacktrace upon sigaction.
"-DHAVE_SIGACTION",
# For logging.cc.
"-DHAVE_PREAD",
"-DHAVE___ATTRIBUTE__",
]
linux_or_darwin_copts = wasm_copts + [
"-DGLOG_EXPORT=__attribute__((visibility(\\\"default\\\")))",
# For src/utilities.cc.
"-DHAVE_SYS_SYSCALL_H",
# For src/logging.cc to create symlinks.
"-DHAVE_UNISTD_H",
"-fvisibility-inlines-hidden",
"-fvisibility=hidden",
]
freebsd_only_copts = [
# Enable declaration of _Unwind_Backtrace
"-D_GNU_SOURCE",
]
darwin_only_copts = [
# For stacktrace.
"-DHAVE_DLADDR",
# Avoid deprecated syscall().
"-DHAVE_PTHREAD_THREADID_NP",
]
windows_only_copts = [
# Override -DGLOG_EXPORT= from the cc_library's defines.
"-DGLOG_EXPORT=__declspec(dllexport)",
"-DGLOG_NO_ABBREVIATED_SEVERITIES",
"-DHAVE_SNPRINTF",
"-I" + src_windows,
]
clang_cl_only_copts = [
# Allow the override of -DGLOG_EXPORT.
"-Wno-macro-redefined",
]
windows_only_srcs = [
"src/glog/log_severity.h",
"src/windows/dirent.h",
"src/windows/port.cc",
"src/windows/port.h",
]
gflags_deps = ["@com_github_gflags_gflags//:gflags"] if with_gflags else []
native.cc_library(
name = "glog",
visibility = ["//visibility:public"],
srcs = [
":config_h",
"src/base/commandlineflags.h",
"src/base/googleinit.h",
"src/base/mutex.h",
"src/demangle.cc",
"src/demangle.h",
"src/logging.cc",
"src/raw_logging.cc",
"src/signalhandler.cc",
"src/stacktrace.h",
"src/stacktrace_generic-inl.h",
"src/stacktrace_libunwind-inl.h",
"src/stacktrace_powerpc-inl.h",
"src/stacktrace_unwind-inl.h",
"src/stacktrace_windows-inl.h",
"src/stacktrace_x86-inl.h",
"src/symbolize.cc",
"src/symbolize.h",
"src/utilities.cc",
"src/utilities.h",
"src/vlog_is_on.cc",
] + select({
"@bazel_tools//src/conditions:windows": windows_only_srcs,
"//conditions:default": [],
}),
hdrs = [
"src/glog/log_severity.h",
"src/glog/platform.h",
":logging_h",
":raw_logging_h",
":stl_logging_h",
":vlog_is_on_h",
],
strip_include_prefix = "src",
defines = select({
# GLOG_EXPORT is normally set by export.h, but that's not
# 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,
}) +
select({
":clang-cl": clang_cl_only_copts,
"//conditions:default": []
}),
deps = gflags_deps + select({
"@bazel_tools//src/conditions:windows": [":strip_include_prefix_hack"],
"//conditions:default": [],
}),
**kwargs
)
# Workaround https://github.com/bazelbuild/bazel/issues/6337 by declaring
# the dependencies without strip_include_prefix.
native.cc_library(
name = "strip_include_prefix_hack",
hdrs = [
"src/glog/log_severity.h",
":logging_h",
":raw_logging_h",
":stl_logging_h",
":vlog_is_on_h",
],
)
expand_template(
name = "config_h",
template = "src/config.h.cmake.in",
out = "glog_internal/config.h",
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,69 +0,0 @@
macro(determine_gflags_namespace VARIABLE)
if (NOT DEFINED "${VARIABLE}")
if (CMAKE_REQUIRED_INCLUDES)
set (CHECK_INCLUDE_FILE_CXX_INCLUDE_DIRS "-DINCLUDE_DIRECTORIES=${CMAKE_REQUIRED_INCLUDES}")
else ()
set (CHECK_INCLUDE_FILE_CXX_INCLUDE_DIRS)
endif ()
set(MACRO_CHECK_INCLUDE_FILE_FLAGS ${CMAKE_REQUIRED_FLAGS})
set(_NAMESPACES gflags google)
set(_check_code
"
#include <gflags/gflags.h>
int main(int argc, char**argv)
{
GLOG_GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);
}
")
if (NOT CMAKE_REQUIRED_QUIET)
message (STATUS "Looking for gflags namespace")
endif ()
if (${ARGC} EQUAL 3)
set (CMAKE_CXX_FLAGS_SAVE ${CMAKE_CXX_FLAGS})
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARGV2}")
endif ()
set (_check_file
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/DetermineGflagsNamespace.cxx)
foreach (_namespace ${_NAMESPACES})
file (WRITE "${_check_file}" "${_check_code}")
try_compile (${VARIABLE}
"${CMAKE_BINARY_DIR}" "${_check_file}"
COMPILE_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}" -DGLOG_GFLAGS_NAMESPACE=${_namespace}
LINK_LIBRARIES gflags
CMAKE_FLAGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
OUTPUT_VARIABLE OUTPUT)
if (${VARIABLE})
set (${VARIABLE} ${_namespace} CACHE INTERNAL "gflags namespace" FORCE)
break ()
else ()
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Determining the gflags namespace ${_namespace} failed with the following output:\n"
"${OUTPUT}\n\n")
endif ()
endforeach (_namespace)
if (${ARGC} EQUAL 3)
set (CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS_SAVE})
endif ()
if (${VARIABLE})
if (NOT CMAKE_REQUIRED_QUIET)
message (STATUS "Looking for gflags namespace - ${${VARIABLE}}")
endif ()
file (APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Determining the gflags namespace passed with the following output:\n"
"${OUTPUT}\n\n")
else ()
if (NOT CMAKE_REQUIRED_QUIET)
message (STATUS "Looking for gflags namespace - failed")
endif ()
set (${VARIABLE} ${_namespace} CACHE INTERNAL "gflags namespace")
endif ()
endif ()
endmacro ()

View File

@ -1,61 +0,0 @@
# - Try to find libunwind
# Once done this will define
#
# Unwind_FOUND - system has libunwind
# unwind::unwind - cmake target for libunwind
include (FindPackageHandleStandardArgs)
find_path (Unwind_INCLUDE_DIR NAMES unwind.h libunwind.h DOC "unwind include directory")
find_library (Unwind_LIBRARY NAMES unwind DOC "unwind library")
mark_as_advanced (Unwind_INCLUDE_DIR Unwind_LIBRARY)
# Extract version information
if (Unwind_LIBRARY)
set (_Unwind_VERSION_HEADER ${Unwind_INCLUDE_DIR}/libunwind-common.h)
if (EXISTS ${_Unwind_VERSION_HEADER})
file (READ ${_Unwind_VERSION_HEADER} _Unwind_VERSION_CONTENTS)
string (REGEX REPLACE ".*#define UNW_VERSION_MAJOR[ \t]+([0-9]+).*" "\\1"
Unwind_VERSION_MAJOR "${_Unwind_VERSION_CONTENTS}")
string (REGEX REPLACE ".*#define UNW_VERSION_MINOR[ \t]+([0-9]+).*" "\\1"
Unwind_VERSION_MINOR "${_Unwind_VERSION_CONTENTS}")
string (REGEX REPLACE ".*#define UNW_VERSION_EXTRA[ \t]+([0-9]+).*" "\\1"
Unwind_VERSION_PATCH "${_Unwind_VERSION_CONTENTS}")
set (Unwind_VERSION ${Unwind_VERSION_MAJOR}.${Unwind_VERSION_MINOR})
if (CMAKE_MATCH_0)
# Third version component may be empty
set (Unwind_VERSION ${Unwind_VERSION}.${Unwind_VERSION_PATCH})
set (Unwind_VERSION_COMPONENTS 3)
else (CMAKE_MATCH_0)
set (Unwind_VERSION_COMPONENTS 2)
endif (CMAKE_MATCH_0)
endif (EXISTS ${_Unwind_VERSION_HEADER})
endif (Unwind_LIBRARY)
# handle the QUIETLY and REQUIRED arguments and set Unwind_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args (Unwind
REQUIRED_VARS Unwind_INCLUDE_DIR Unwind_LIBRARY
VERSION_VAR Unwind_VERSION
)
if (Unwind_FOUND)
if (NOT TARGET unwind::unwind)
add_library (unwind::unwind INTERFACE IMPORTED)
set_property (TARGET unwind::unwind PROPERTY
INTERFACE_INCLUDE_DIRECTORIES ${Unwind_INCLUDE_DIR}
)
set_property (TARGET unwind::unwind PROPERTY
INTERFACE_LINK_LIBRARIES ${Unwind_LIBRARY}
)
set_property (TARGET unwind::unwind PROPERTY
IMPORTED_CONFIGURATIONS RELEASE
)
endif (NOT TARGET unwind::unwind)
endif (Unwind_FOUND)

View File

@ -1,70 +0,0 @@
cmake_policy (PUSH)
cmake_policy (VERSION 3.3)
include (CMakeParseArguments)
function (get_cache_variables _CACHEVARS)
set (_SINGLE)
set (_MULTI EXCLUDE)
set (_OPTIONS)
cmake_parse_arguments (_ARGS "${_OPTIONS}" "${_SINGLE}" "${_MULTI}" ${ARGS} ${ARGN})
get_cmake_property (_VARIABLES VARIABLES)
set (CACHEVARS)
foreach (_VAR ${_VARIABLES})
if (DEFINED _ARGS_EXCLUDE)
if ("${_VAR}" IN_LIST _ARGS_EXCLUDE)
continue ()
endif ("${_VAR}" IN_LIST _ARGS_EXCLUDE)
endif (DEFINED _ARGS_EXCLUDE)
get_property (_CACHEVARTYPE CACHE ${_VAR} PROPERTY TYPE)
if ("${_CACHEVARTYPE}" STREQUAL INTERNAL OR
"${_CACHEVARTYPE}" STREQUAL STATIC OR
"${_CACHEVARTYPE}" STREQUAL UNINITIALIZED)
continue ()
endif ("${_CACHEVARTYPE}" STREQUAL INTERNAL OR
"${_CACHEVARTYPE}" STREQUAL STATIC OR
"${_CACHEVARTYPE}" STREQUAL UNINITIALIZED)
get_property (_CACHEVARVAL CACHE ${_VAR} PROPERTY VALUE)
if ("${_CACHEVARVAL}" STREQUAL "")
continue ()
endif ("${_CACHEVARVAL}" STREQUAL "")
get_property (_CACHEVARDOC CACHE ${_VAR} PROPERTY HELPSTRING)
# Escape " in values
string (REPLACE "\"" "\\\"" _CACHEVARVAL "${_CACHEVARVAL}")
# Escape " in help strings
string (REPLACE "\"" "\\\"" _CACHEVARDOC "${_CACHEVARDOC}")
# Escape ; in values
string (REPLACE ";" "\\\;" _CACHEVARVAL "${_CACHEVARVAL}")
# Escape ; in help strings
string (REPLACE ";" "\\\;" _CACHEVARDOC "${_CACHEVARDOC}")
# Escape backslashes in values except those that are followed by a
# quote.
string (REGEX REPLACE "\\\\([^\"])" "\\\\\\1" _CACHEVARVAL "${_CACHEVARVAL}")
# Escape backslashes in values that are followed by a letter to avoid
# invalid escape sequence errors.
string (REGEX REPLACE "\\\\([a-zA-Z])" "\\\\\\\\1" _CACHEVARVAL "${_CACHEVARVAL}")
string (REPLACE "\\\\" "\\\\\\\\" _CACHEVARDOC "${_CACHEVARDOC}")
if (NOT "${_CACHEVARTYPE}" STREQUAL BOOL)
set (_CACHEVARVAL "\"${_CACHEVARVAL}\"")
endif (NOT "${_CACHEVARTYPE}" STREQUAL BOOL)
if (NOT "${_CACHEVARTYPE}" STREQUAL "" AND NOT "${_CACHEVARVAL}" STREQUAL "")
set (CACHEVARS "${CACHEVARS}set (${_VAR} ${_CACHEVARVAL} CACHE ${_CACHEVARTYPE} \"${_CACHEVARDOC}\")\n")
endif (NOT "${_CACHEVARTYPE}" STREQUAL "" AND NOT "${_CACHEVARVAL}" STREQUAL "")
endforeach (_VAR)
set (${_CACHEVARS} ${CACHEVARS} PARENT_SCOPE)
endfunction (get_cache_variables)
cmake_policy (POP)

View File

@ -1,22 +0,0 @@
set (RUNS 3)
foreach (iter RANGE 1 ${RUNS})
set (ENV{GOOGLE_LOG_DIR} ${TEST_DIR})
execute_process (COMMAND ${LOGCLEANUP} RESULT_VARIABLE _RESULT)
if (NOT _RESULT EQUAL 0)
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
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)
file (GLOB LOG_FILES ${TEST_DIR}/*.foobar)
list (LENGTH LOG_FILES NUM_FILES)
if (NOT NUM_FILES EQUAL 1)
message (SEND_ERROR "Expected 1 log file in log directory but found ${NUM_FILES}")
endif (NOT NUM_FILES EQUAL 1)

View File

@ -1,22 +0,0 @@
set (RUNS 3)
foreach (iter RANGE 1 ${RUNS})
execute_process (COMMAND ${LOGCLEANUP} -log_dir=${TEST_DIR}
RESULT_VARIABLE _RESULT)
if (NOT _RESULT EQUAL 0)
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
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)
file (GLOB LOG_FILES ${TEST_DIR}/test_cleanup_*.barfoo)
list (LENGTH LOG_FILES NUM_FILES)
if (NOT NUM_FILES EQUAL 1)
message (SEND_ERROR "Expected 1 log file in build directory ${TEST_DIR} but found ${NUM_FILES}")
endif (NOT NUM_FILES EQUAL 1)

View File

@ -1,28 +0,0 @@
set (RUNS 3)
# Create the subdirectory required by this unit test.
file (MAKE_DIRECTORY ${TEST_DIR}/${TEST_SUBDIR})
foreach (iter RANGE 1 ${RUNS})
execute_process (COMMAND ${LOGCLEANUP} -log_dir=${TEST_DIR}
RESULT_VARIABLE _RESULT)
if (NOT _RESULT EQUAL 0)
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
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)
file (GLOB LOG_FILES ${TEST_DIR}/${TEST_SUBDIR}/test_cleanup_*.relativefoo)
list (LENGTH LOG_FILES NUM_FILES)
if (NOT NUM_FILES EQUAL 1)
message (SEND_ERROR "Expected 1 log file in build directory ${TEST_DIR}${TEST_SUBDIR} but found ${NUM_FILES}")
endif (NOT NUM_FILES EQUAL 1)
# Remove the subdirectory required by this unit test.
file (REMOVE_RECURSE ${TEST_DIR}/${TEST_SUBDIR})

View File

@ -1,11 +0,0 @@
# 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)
file (WRITE ${INITIAL_CACHE} "${CACHEVARS}")

View File

@ -1,40 +0,0 @@
# 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)
list (APPEND _ADDITIONAL_ARGS -T ${GENERATOR_TOOLSET})
endif (GENERATOR_TOOLSET)
if (GENERATOR_PLATFORM)
list (APPEND _ADDITIONAL_ARGS -A ${GENERATOR_PLATFORM})
endif (GENERATOR_PLATFORM)
# Run CMake
execute_process (
# Capture the PATH environment variable content set during project generation
# 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
# directory containing git.exe. Incidently, the Git installation directory
# also contains sh.exe which causes MinGW Makefile generation to fail.
COMMAND ${CMAKE_COMMAND} -E env PATH=${PATH}
${CMAKE_COMMAND} -C ${INITIAL_CACHE}
-G ${GENERATOR}
${_ADDITIONAL_ARGS}
-DCMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=ON
-DCMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY=ON
-DCMAKE_PREFIX_PATH=${PACKAGE_DIR}
${SOURCE_DIR}
WORKING_DIRECTORY ${TEST_BINARY_DIR}
RESULT_VARIABLE _GENERATE_SUCCEEDED
)
if (NOT _GENERATE_SUCCEEDED EQUAL 0)
message (FATAL_ERROR "Failed to generate project files using CMake")
endif (NOT _GENERATE_SUCCEEDED EQUAL 0)

View File

@ -1,13 +0,0 @@
if (CMAKE_VERSION VERSION_LESS @glog_CMake_VERSION@)
message (FATAL_ERROR "CMake >= @glog_CMake_VERSION@ required")
endif (CMAKE_VERSION VERSION_LESS @glog_CMake_VERSION@)
@PACKAGE_INIT@
include (CMakeFindDependencyMacro)
include (${CMAKE_CURRENT_LIST_DIR}/glog-modules.cmake)
@gflags_DEPENDENCY@
@Unwind_DEPENDENCY@
include (${CMAKE_CURRENT_LIST_DIR}/glog-targets.cmake)

View File

@ -1,18 +0,0 @@
cmake_policy (PUSH)
cmake_policy (SET CMP0057 NEW)
if (CMAKE_VERSION VERSION_LESS 3.3)
message (FATAL_ERROR "glog-modules.cmake requires the consumer "
"to use CMake 3.3 (or newer)")
endif (CMAKE_VERSION VERSION_LESS 3.3)
set (glog_MODULE_PATH "@glog_FULL_CMake_DATADIR@")
list (APPEND CMAKE_MODULE_PATH ${glog_MODULE_PATH})
if (NOT glog_MODULE_PATH IN_LIST CMAKE_MODULE_PATH)
message (FATAL_ERROR "Cannot add '${glog_MODULE_PATH}' to "
"CMAKE_MODULE_PATH. This will cause glog-config.cmake to fail at "
"locating required find modules. Make sure CMAKE_MODULE_PATH is not a cache variable.")
endif (NOT glog_MODULE_PATH IN_LIST CMAKE_MODULE_PATH)
cmake_policy (POP)

View File

@ -1,11 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libglog
Description: Google Log (glog) C++ logging framework
Version: @VERSION@
Libs: -L${libdir} -lglog
Libs.private: @glog_libraries_options_for_static_linking@
Cflags: -I${includedir}

View File

@ -1,147 +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.
// ---
// This file is a compatibility layer that defines Google's version of
// command line flags that are used for configuration.
//
// We put flags into their own namespace. It is purposefully
// named in an opaque way that people should have trouble typing
// directly. The idea is that DEFINE puts the flag in the weird
// namespace, and DECLARE imports the flag from there into the
// current namespace. The net result is to force people to use
// DECLARE to get access to a flag, rather than saying
// extern bool FLAGS_logtostderr;
// or some such instead. We want this so we can put extra
// functionality (like sanity-checking) in DECLARE if we want,
// and make sure it is picked up everywhere.
//
// We also put the type of the variable in the namespace, so that
// people can't DECLARE_int32 something that they DEFINE_bool'd
// elsewhere.
#ifndef BASE_COMMANDLINEFLAGS_H__
#define BASE_COMMANDLINEFLAGS_H__
#include "config.h"
#include <cstdlib> // for getenv
#include <cstring> // for memchr
#include <string>
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
#else
#include <glog/logging.h>
#define DECLARE_VARIABLE(type, shorttype, name, tn) \
namespace fL##shorttype { \
extern GLOG_EXPORT type FLAGS_##name; \
} \
using fL##shorttype::FLAGS_##name
#define DEFINE_VARIABLE(type, shorttype, name, value, meaning, tn) \
namespace fL##shorttype { \
GLOG_EXPORT type FLAGS_##name(value); \
char FLAGS_no##name; \
} \
using fL##shorttype::FLAGS_##name
// bool specialization
#define DECLARE_bool(name) \
DECLARE_VARIABLE(bool, B, name, bool)
#define DEFINE_bool(name, value, meaning) \
DEFINE_VARIABLE(bool, B, name, value, meaning, bool)
// int32 specialization
#define DECLARE_int32(name) \
DECLARE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, int32)
#define DEFINE_int32(name, value, meaning) \
DEFINE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, value, meaning, int32)
// uint32 specialization
#ifndef DECLARE_uint32
#define DECLARE_uint32(name) \
DECLARE_VARIABLE(GOOGLE_NAMESPACE::uint32, U, name, uint32)
#endif // DECLARE_uint64
#define DEFINE_uint32(name, value, meaning) \
DEFINE_VARIABLE(GOOGLE_NAMESPACE::uint32, U, name, value, meaning, uint32)
// 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
#define DEFINE_string(name, value, meaning) \
namespace fLS { \
std::string FLAGS_##name##_buf(value); \
GLOG_EXPORT std::string& FLAGS_##name = FLAGS_##name##_buf; \
char FLAGS_no##name; \
} \
using fLS::FLAGS_##name
#endif // HAVE_LIB_GFLAGS
// Define GLOG_DEFINE_* using DEFINE_* . By using these macros, we
// have GLOG_* environ variables even if we have gflags installed.
//
// If both an environment variable and a flag are specified, the value
// specified by a flag wins. E.g., if GLOG_v=0 and --v=1, the
// verbosity will be 1, not 0.
#define GLOG_DEFINE_bool(name, value, meaning) \
DEFINE_bool(name, EnvToBool("GLOG_" #name, value), meaning)
#define GLOG_DEFINE_int32(name, value, meaning) \
DEFINE_int32(name, EnvToInt("GLOG_" #name, value), meaning)
#define GLOG_DEFINE_uint32(name, value, meaning) \
DEFINE_uint32(name, EnvToUInt("GLOG_" #name, value), meaning)
#define GLOG_DEFINE_string(name, value, meaning) \
DEFINE_string(name, EnvToString("GLOG_" #name, value), meaning)
// 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.
#define EnvToString(envname, dflt) \
(!getenv(envname) ? (dflt) : getenv(envname))
#define EnvToBool(envname, dflt) \
(!getenv(envname) ? (dflt) : memchr("tTyY1\0", getenv(envname)[0], 6) != NULL)
#define EnvToInt(envname, dflt) \
(!getenv(envname) ? (dflt) : strtol(getenv(envname), NULL, 10))
#define EnvToUInt(envname, dflt) \
(!getenv(envname) ? (dflt) : strtoul(getenv(envname), NULL, 10))
#endif // BASE_COMMANDLINEFLAGS_H__

View File

@ -1,51 +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.
// ---
// Author: Jacob Hoffman-Andrews
#ifndef _GOOGLEINIT_H
#define _GOOGLEINIT_H
class GoogleInitializer {
public:
typedef void (*void_function)(void);
GoogleInitializer(const char*, void_function f) {
f();
}
};
#define REGISTER_MODULE_INITIALIZER(name, body) \
namespace { \
static void google_init_module_##name () { body; } \
GoogleInitializer google_initializer_module_##name(#name, \
google_init_module_##name); \
}
#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,96 +0,0 @@
// Copyright (c) 2021, 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/logging.h>
#include <glog/raw_logging.h>
#include "base/commandlineflags.h"
#include "googletest.h"
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE;
#endif
#ifdef HAVE_LIB_GMOCK
#include <gmock/gmock.h>
#include "mock-log.h"
// Introduce several symbols from gmock.
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
using testing::_;
using testing::AllOf;
using testing::AnyNumber;
using testing::HasSubstr;
using testing::InitGoogleMock;
using testing::StrictMock;
using testing::StrNe;
#endif
using namespace GOOGLE_NAMESPACE;
TEST(CleanImmediately, logging) {
google::SetLogFilenameExtension(".foobar");
google::EnableLogCleaner(0);
for (unsigned i = 0; i < 1000; ++i) {
LOG(INFO) << "cleanup test";
}
google::DisableLogCleaner();
}
int main(int argc, char **argv) {
FLAGS_colorlogtostderr = false;
FLAGS_timestamp_in_logfile_name = true;
#ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true);
#endif
// Make sure stderr is not buffered as stderr seems to be buffered
// on recent windows.
setbuf(stderr, NULL);
// Test some basics before InitGoogleLogging:
CaptureTestStderr();
const string early_stderr = GetCapturedTestStderr();
EXPECT_FALSE(IsGoogleLoggingInitialized());
InitGoogleLogging(argv[0]);
EXPECT_TRUE(IsGoogleLoggingInitialized());
InitGoogleTest(&argc, argv);
#ifdef HAVE_LIB_GMOCK
InitGoogleMock(&argc, argv);
#endif
// so that death tests run before we use threads
CHECK_EQ(RUN_ALL_TESTS(), 0);
}

View File

@ -1,101 +0,0 @@
// Copyright (c) 2021, 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/logging.h>
#include <glog/raw_logging.h>
#include "base/commandlineflags.h"
#include "googletest.h"
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE;
#endif
#ifdef HAVE_LIB_GMOCK
#include <gmock/gmock.h>
#include "mock-log.h"
// Introduce several symbols from gmock.
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
using testing::_;
using testing::AllOf;
using testing::AnyNumber;
using testing::HasSubstr;
using testing::InitGoogleMock;
using testing::StrictMock;
using testing::StrNe;
#endif
using namespace GOOGLE_NAMESPACE;
TEST(CleanImmediatelyWithAbsolutePrefix, logging) {
google::EnableLogCleaner(0);
google::SetLogFilenameExtension(".barfoo");
google::SetLogDestination(GLOG_INFO, "test_cleanup_");
for (unsigned i = 0; i < 1000; ++i) {
LOG(INFO) << "cleanup test";
}
for (unsigned i = 0; i < 10; ++i) {
LOG(ERROR) << "cleanup test";
}
google::DisableLogCleaner();
}
int main(int argc, char **argv) {
FLAGS_colorlogtostderr = false;
FLAGS_timestamp_in_logfile_name = true;
#ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true);
#endif
// Make sure stderr is not buffered as stderr seems to be buffered
// on recent windows.
setbuf(stderr, NULL);
// Test some basics before InitGoogleLogging:
CaptureTestStderr();
const string early_stderr = GetCapturedTestStderr();
EXPECT_FALSE(IsGoogleLoggingInitialized());
InitGoogleLogging(argv[0]);
EXPECT_TRUE(IsGoogleLoggingInitialized());
InitGoogleTest(&argc, argv);
#ifdef HAVE_LIB_GMOCK
InitGoogleMock(&argc, argv);
#endif
// so that death tests run before we use threads
CHECK_EQ(RUN_ALL_TESTS(), 0);
}

View File

@ -1,97 +0,0 @@
// Copyright (c) 2021, 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/logging.h>
#include <glog/raw_logging.h>
#include "base/commandlineflags.h"
#include "googletest.h"
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE;
#endif
#ifdef HAVE_LIB_GMOCK
#include <gmock/gmock.h>
#include "mock-log.h"
// Introduce several symbols from gmock.
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
using testing::_;
using testing::AllOf;
using testing::AnyNumber;
using testing::HasSubstr;
using testing::InitGoogleMock;
using testing::StrictMock;
using testing::StrNe;
#endif
using namespace GOOGLE_NAMESPACE;
TEST(CleanImmediatelyWithRelativePrefix, logging) {
google::EnableLogCleaner(0);
google::SetLogFilenameExtension(".relativefoo");
google::SetLogDestination(GLOG_INFO, "test_subdir/test_cleanup_");
for (unsigned i = 0; i < 1000; ++i) {
LOG(INFO) << "cleanup test";
}
google::DisableLogCleaner();
}
int main(int argc, char **argv) {
FLAGS_colorlogtostderr = false;
FLAGS_timestamp_in_logfile_name = true;
#ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true);
#endif
// Make sure stderr is not buffered as stderr seems to be buffered
// on recent windows.
setbuf(stderr, NULL);
// Test some basics before InitGoogleLogging:
CaptureTestStderr();
const string early_stderr = GetCapturedTestStderr();
EXPECT_FALSE(IsGoogleLoggingInitialized());
InitGoogleLogging(argv[0]);
EXPECT_TRUE(IsGoogleLoggingInitialized());
InitGoogleTest(&argc, argv);
#ifdef HAVE_LIB_GMOCK
InitGoogleMock(&argc, argv);
#endif
// so that death tests run before we use threads
CHECK_EQ(RUN_ALL_TESTS(), 0);
}

View File

@ -1,231 +0,0 @@
#ifndef 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 */
#cmakedefine HAVE_DLADDR
/* Define if you have the `snprintf' function */
#cmakedefine HAVE_SNPRINTF
/* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_DLFCN_H
/* Define to 1 if you have the <execinfo.h> header file. */
#cmakedefine HAVE_EXECINFO_H
/* Define if you have the `fcntl' function */
#cmakedefine HAVE_FCNTL
/* Define to 1 if you have the <glob.h> header file. */
#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 */
#cmakedefine HAVE_LIB_GMOCK
/* define if you have google gtest library */
#cmakedefine HAVE_LIB_GTEST
/* define if you have dbghelp library */
#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 */
#cmakedefine HAVE_PREAD
/* Define if you have POSIX threads libraries and header files. */
#cmakedefine HAVE_PTHREAD
/* Define to 1 if you have the <pwd.h> header file. */
#cmakedefine HAVE_PWD_H
/* Define if you have the 'pwrite' function */
#cmakedefine HAVE_PWRITE
/* define if the compiler implements pthread_rwlock_* */
#cmakedefine HAVE_RWLOCK
/* Define if you have the 'sigaction' function */
#cmakedefine HAVE_SIGACTION
/* Define if you have the `sigaltstack' function */
#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. */
#cmakedefine HAVE_SYSCALL_H
/* Define to 1 if you have the <syslog.h> header file. */
#cmakedefine HAVE_SYSLOG_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#cmakedefine HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/syscall.h> header file. */
#cmakedefine HAVE_SYS_SYSCALL_H
/* Define to 1 if you have the <sys/time.h> header file. */
#cmakedefine HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H}
/* Define to 1 if you have the <sys/ucontext.h> header file. */
#cmakedefine HAVE_SYS_UCONTEXT_H
/* Define to 1 if you have the <sys/utsname.h> header file. */
#cmakedefine HAVE_SYS_UTSNAME_H
/* Define to 1 if you have the <sys/wait.h> header file. */
#cmakedefine HAVE_SYS_WAIT_H
/* Define to 1 if you have the <ucontext.h> header file. */
#cmakedefine HAVE_UCONTEXT_H
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H}
/* Define if you have the <unwind.h> header file. */
#cmakedefine HAVE_UNWIND_H
/* Define if you linking to _Unwind_Backtrace is possible. */
#cmakedefine HAVE__UNWIND_BACKTRACE
/* 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 */
#cmakedefine HAVE_SYMBOLIZE
/* define if localtime_r is available in time.h */
#cmakedefine HAVE_LOCALTIME_R
/* define if gmtime_r is available in time.h */
#cmakedefine HAVE_GMTIME_R
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#cmakedefine LT_OBJDIR
/* Name of package */
#cmakedefine PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#cmakedefine PACKAGE_BUGREPORT
/* 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 */
#cmakedefine PC_FROM_UCONTEXT
/* define if we should print file offsets in traces instead of symbolizing. */
#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. */
#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 */
#cmakedefine TEST_SRC_DIR ${TEST_SRC_DIR}
/* Define to necessary thread-local storage attribute. */
#cmakedefine GLOG_THREAD_LOCAL_STORAGE ${GLOG_THREAD_LOCAL_STORAGE}
/* Check whether aligned_storage and alignof present */
#cmakedefine HAVE_ALIGNED_STORAGE ${HAVE_ALIGNED_STORAGE}
/* Check whether C++11 atomic is available */
#cmakedefine HAVE_CXX11_ATOMIC ${HAVE_CXX11_ATOMIC}
/* Check whether C++11 chrono is available */
#cmakedefine HAVE_CXX11_CHRONO ${HAVE_CXX11_CHRONO}
/* Check whether C++11 nullptr_t is available */
#cmakedefine HAVE_CXX11_NULLPTR_T ${HAVE_CXX11_NULLPTR_T}
/* Version number of package */
#cmakedefine VERSION
#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

File diff suppressed because it is too large Load Diff

View File

@ -1,85 +0,0 @@
// Copyright (c) 2006, 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: Satoru Takabayashi
//
// An async-signal-safe and thread-safe demangler for Itanium C++ ABI
// (aka G++ V3 ABI).
// The demangler is implemented to be used in async signal handlers to
// symbolize stack traces. We cannot use libstdc++'s
// abi::__cxa_demangle() in such signal handlers since it's not async
// signal safe (it uses malloc() internally).
//
// Note that this demangler doesn't support full demangling. More
// specifically, it doesn't print types of function parameters and
// types of template arguments. It just skips them. However, it's
// still very useful to extract basic information such as class,
// function, constructor, destructor, and operator names.
//
// See the implementation note in demangle.cc if you are interested.
//
// Example:
//
// | Mangled Name | The Demangler | abi::__cxa_demangle()
// |---------------|---------------|-----------------------
// | _Z1fv | f() | f()
// | _Z1fi | f() | f(int)
// | _Z3foo3bar | foo() | foo(bar)
// | _Z1fIiEvi | f<>() | void f<int>(int)
// | _ZN1N1fE | N::f | N::f
// | _ZN3Foo3BarEv | Foo::Bar() | Foo::Bar()
// | _Zrm1XS_" | operator%() | operator%(X, X)
// | _ZN3FooC1Ev | Foo::Foo() | Foo::Foo()
// | _Z1fSs | f() | f(std::basic_string<char,
// | | | std::char_traits<char>,
// | | | std::allocator<char> >)
//
// See the unit test for more examples.
//
// Note: we might want to write demanglers for ABIs other than Itanium
// C++ ABI in the future.
//
#ifndef BASE_DEMANGLE_H_
#define BASE_DEMANGLE_H_
#include "config.h"
#include <glog/logging.h>
_START_GOOGLE_NAMESPACE_
// Demangle "mangled". On success, return true and write the
// demangled symbol name to "out". Otherwise, return false.
// "out" is modified even if demangling is unsuccessful.
bool GLOG_EXPORT Demangle(const char *mangled, char *out, size_t out_size);
_END_GOOGLE_NAMESPACE_
#endif // BASE_DEMANGLE_H_

View File

@ -1,170 +0,0 @@
// Copyright (c) 2006, 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: Satoru Takabayashi
//
// Unit tests for functions in demangle.c.
#include "utilities.h"
#include <iostream>
#include <fstream>
#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;
#endif
GLOG_DEFINE_bool(demangle_filter, false,
"Run demangle_unittest in filter mode");
using namespace std;
using namespace GOOGLE_NAMESPACE;
// A wrapper function for Demangle() to make the unit test simple.
static const char *DemangleIt(const char * const mangled) {
static char demangled[4096];
if (Demangle(mangled, demangled, sizeof(demangled))) {
return demangled;
} else {
return mangled;
}
}
#if defined(GLOG_OS_WINDOWS)
#if defined(HAVE_DBGHELP) && !defined(NDEBUG)
TEST(Demangle, Windows) {
EXPECT_STREQ(
"public: static void __cdecl Foo::func(int)",
DemangleIt("?func@Foo@@SAXH@Z"));
EXPECT_STREQ(
"public: static void __cdecl Foo::func(int)",
DemangleIt("@ILT+1105(?func@Foo@@SAXH@Z)"));
EXPECT_STREQ(
"int __cdecl foobarArray(int * const)",
DemangleIt("?foobarArray@@YAHQAH@Z"));
}
#endif
#else
// Test corner cases of bounary conditions.
TEST(Demangle, CornerCases) {
const size_t size = 10;
char tmp[size] = { 0 };
const char *demangled = "foobar()";
const char *mangled = "_Z6foobarv";
EXPECT_TRUE(Demangle(mangled, tmp, sizeof(tmp)));
// sizeof("foobar()") == size - 1
EXPECT_STREQ(demangled, tmp);
EXPECT_TRUE(Demangle(mangled, tmp, size - 1));
EXPECT_STREQ(demangled, tmp);
EXPECT_FALSE(Demangle(mangled, tmp, size - 2)); // Not enough.
EXPECT_FALSE(Demangle(mangled, tmp, 1));
EXPECT_FALSE(Demangle(mangled, tmp, 0));
EXPECT_FALSE(Demangle(mangled, NULL, 0)); // Should not cause SEGV.
}
// Test handling of functions suffixed with .clone.N, which is used by GCC
// 4.5.x, and .constprop.N and .isra.N, which are used by GCC 4.6.x. These
// suffixes are used to indicate functions which have been cloned during
// optimization. We ignore these suffixes.
TEST(Demangle, Clones) {
char tmp[20];
EXPECT_TRUE(Demangle("_ZL3Foov", tmp, sizeof(tmp)));
EXPECT_STREQ("Foo()", tmp);
EXPECT_TRUE(Demangle("_ZL3Foov.clone.3", tmp, sizeof(tmp)));
EXPECT_STREQ("Foo()", tmp);
EXPECT_TRUE(Demangle("_ZL3Foov.constprop.80", tmp, sizeof(tmp)));
EXPECT_STREQ("Foo()", tmp);
EXPECT_TRUE(Demangle("_ZL3Foov.isra.18", tmp, sizeof(tmp)));
EXPECT_STREQ("Foo()", tmp);
EXPECT_TRUE(Demangle("_ZL3Foov.isra.2.constprop.18", tmp, sizeof(tmp)));
EXPECT_STREQ("Foo()", tmp);
// Invalid (truncated), should not demangle.
EXPECT_FALSE(Demangle("_ZL3Foov.clo", tmp, sizeof(tmp)));
// Invalid (.clone. not followed by number), should not demangle.
EXPECT_FALSE(Demangle("_ZL3Foov.clone.", tmp, sizeof(tmp)));
// Invalid (.clone. followed by non-number), should not demangle.
EXPECT_FALSE(Demangle("_ZL3Foov.clone.foo", tmp, sizeof(tmp)));
// Invalid (.constprop. not followed by number), should not demangle.
EXPECT_FALSE(Demangle("_ZL3Foov.isra.2.constprop.", tmp, sizeof(tmp)));
}
TEST(Demangle, FromFile) {
string test_file = FLAGS_test_srcdir + "/src/demangle_unittest.txt";
ifstream f(test_file.c_str()); // The file should exist.
EXPECT_FALSE(f.fail());
string line;
while (getline(f, line)) {
// Lines start with '#' are considered as comments.
if (line.empty() || line[0] == '#') {
continue;
}
// Each line should contain a mangled name and a demangled name
// separated by '\t'. Example: "_Z3foo\tfoo"
string::size_type tab_pos = line.find('\t');
EXPECT_NE(string::npos, tab_pos);
string mangled = line.substr(0, tab_pos);
string demangled = line.substr(tab_pos + 1);
EXPECT_EQ(demangled, DemangleIt(mangled.c_str()));
}
}
#endif
int main(int argc, char **argv) {
#ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true);
#endif
InitGoogleTest(&argc, argv);
FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]);
if (FLAGS_demangle_filter) {
// Read from cin and write to cout.
string line;
while (getline(cin, line, '\n')) {
cout << DemangleIt(line.c_str()) << endl;
}
return 0;
} else if (argc > 1) {
cout << DemangleIt(argv[1]) << endl;
return 0;
} else {
return RUN_ALL_TESTS();
}
}

View File

@ -1,95 +0,0 @@
#! /bin/sh
#
# Copyright (c) 2006, 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: Satoru Takabayashi
#
# Unit tests for demangle.c with a real binary.
set -e
die () {
echo $1
exit 1
}
BINDIR=".libs"
LIBGLOG="$BINDIR/libglog.so"
DEMANGLER="$BINDIR/demangle_unittest"
if test -e "$DEMANGLER"; then
# We need shared object.
export LD_LIBRARY_PATH=$BINDIR
export DYLD_LIBRARY_PATH=$BINDIR
else
# For windows
DEMANGLER="./demangle_unittest.exe"
if ! test -e "$DEMANGLER"; then
echo "We coundn't find demangle_unittest binary."
exit 1
fi
fi
# Extract C++ mangled symbols from libbase.so.
NM_OUTPUT="demangle.nm"
nm "$LIBGLOG" | perl -nle 'print $1 if /\s(_Z\S+$)/' > "$NM_OUTPUT"
# Check if mangled symbols exist. If there are none, we quit.
# The binary is more likely compiled with GCC 2.95 or something old.
if ! grep --quiet '^_Z' "$NM_OUTPUT"; then
echo "PASS"
exit 0
fi
# Demangle the symbols using our demangler.
DM_OUTPUT="demangle.dm"
GLOG_demangle_filter=1 "$DEMANGLER" --demangle_filter < "$NM_OUTPUT" > "$DM_OUTPUT"
# Calculate the numbers of lines.
NM_LINES=`wc -l "$NM_OUTPUT" | awk '{ print $1 }'`
DM_LINES=`wc -l "$DM_OUTPUT" | awk '{ print $1 }'`
# Compare the numbers of lines. They must be the same.
if test "$NM_LINES" != "$DM_LINES"; then
die "$NM_OUTPUT and $DM_OUTPUT don't have the same numbers of lines"
fi
# Check if mangled symbols exist. They must not exist.
if grep --quiet '^_Z' "$DM_OUTPUT"; then
MANGLED=`grep '^_Z' "$DM_OUTPUT" | wc -l | awk '{ print \$1 }'`
echo "Mangled symbols ($MANGLED out of $NM_LINES) found in $DM_OUTPUT:"
grep '^_Z' "$DM_OUTPUT"
die "Mangled symbols ($MANGLED out of $NM_LINES) found in $DM_OUTPUT"
fi
# All C++ symbols are demangled successfully.
echo "PASS"
exit 0

View File

@ -1,145 +0,0 @@
# Test caces for demangle_unittest. Each line consists of a
# tab-separated pair of mangled and demangled symbol names.
# Constructors and destructors.
_ZN3FooC1Ev Foo::Foo()
_ZN3FooD1Ev Foo::~Foo()
_ZNSoD0Ev std::ostream::~ostream()
# G++ extensions.
_ZTCN10LogMessage9LogStreamE0_So LogMessage::LogStream
_ZTv0_n12_N10LogMessage9LogStreamD0Ev LogMessage::LogStream::~LogStream()
_ZThn4_N7icu_3_410UnicodeSetD0Ev icu_3_4::UnicodeSet::~UnicodeSet()
# A bug in g++'s C++ ABI version 2 (-fabi-version=2).
_ZN7NSSInfoI5groupjjXadL_Z10getgrgid_rEELZ19nss_getgrgid_r_nameEEC1Ei NSSInfo<>::NSSInfo()
# C linkage symbol names. Should keep them untouched.
main main
Demangle Demangle
_ZERO _ZERO
# Cast operator.
_Zcviv operator int()
_ZN3foocviEv foo::operator int()
# Versioned symbols.
_Z3Foo@GLIBCXX_3.4 Foo@GLIBCXX_3.4
_Z3Foo@@GLIBCXX_3.4 Foo@@GLIBCXX_3.4
# Abbreviations.
_ZNSaE std::allocator
_ZNSbE std::basic_string
_ZNSdE std::iostream
_ZNSiE std::istream
_ZNSoE std::ostream
_ZNSsE std::string
# Substitutions. We just replace them with ?.
_ZN3fooS_E foo::?
_ZN3foo3barS0_E foo::bar::?
_ZNcvT_IiEEv operator ?<>()
# "<< <" case.
_ZlsI3fooE operator<< <>
# ABI tags.
_Z1AB3barB3foo A
_ZN3fooL3barB5cxx11E foo::bar
# Random things we found interesting.
_ZN3FooISt6vectorISsSaISsEEEclEv Foo<>::operator()()
_ZTI9Callback1IiE Callback1<>
_ZN7icu_3_47UMemorynwEj icu_3_4::UMemory::operator new()
_ZNSt6vectorIbE9push_backE std::vector<>::push_back
_ZNSt6vectorIbSaIbEE9push_backEb std::vector<>::push_back()
_ZlsRSoRK15PRIVATE_Counter operator<<()
_ZSt6fill_nIPPN9__gnu_cxx15_Hashtable_nodeISt4pairIKPKcjEEEjS8_ET_SA_T0_RKT1_ std::fill_n<>()
_ZZ3FoovE3Bar Foo()::Bar
_ZGVZ7UpTimervE8up_timer UpTimer()::up_timer
# Test cases from gcc-4.1.0/libstdc++-v3/testsuite/demangle.
# Collected by:
# % grep verify_demangle **/*.cc | perl -nle 'print $1 if /"(_Z.*?)"/' |
# sort | uniq
#
# Note that the following symbols are invalid.
# That's why they are not demangled.
# - _ZNZN1N1fEiE1X1gE
# - _ZNZN1N1fEiE1X1gEv
# - _Z1xINiEE
_Z1fA37_iPS_ f()
_Z1fAszL_ZZNK1N1A1fEvE3foo_0E_i f()
_Z1fI1APS0_PKS0_EvT_T0_T1_PA4_S3_M1CS8_ f<>()
_Z1fI1XENT_1tES2_ f<>()
_Z1fI1XEvPVN1AIT_E1TE f<>()
_Z1fILi1ELc120EEv1AIXplT_cviLd4028ae147ae147aeEEE f<>()
_Z1fILi1ELc120EEv1AIXplT_cviLf3f800000EEE f<>()
_Z1fILi5E1AEvN1CIXqugtT_Li0ELi1ELi2EEE1qE f<>()
_Z1fILi5E1AEvN1CIXstN1T1tEEXszsrS2_1tEE1qE f<>()
_Z1fILi5EEvN1AIXcvimlT_Li22EEE1qE f<>()
_Z1fIiEvi f<>()
_Z1fKPFiiE f()
_Z1fM1AFivEPS0_ f()
_Z1fM1AKFivE f()
_Z1fM1AKFvvE f()
_Z1fPFPA1_ivE f()
_Z1fPFYPFiiEiE f()
_Z1fPFvvEM1SFvvE f()
_Z1fPKM1AFivE f()
_Z1fi f()
_Z1fv f()
_Z1jM1AFivEPS1_ j()
_Z1rM1GFivEMS_KFivES_M1HFivES1_4whatIKS_E5what2IS8_ES3_ r()
_Z1sPA37_iPS0_ s()
_Z1xINiEE _Z1xINiEE
_Z3absILi11EEvv abs<>()
_Z3foo3bar foo()
_Z3foo5Hello5WorldS0_S_ foo()
_Z3fooA30_A_i foo()
_Z3fooIA6_KiEvA9_KT_rVPrS4_ foo<>()
_Z3fooILi2EEvRAplT_Li1E_i foo<>()
_Z3fooIiFvdEiEvv foo<>()
_Z3fooPM2ABi foo()
_Z3fooc foo()
_Z3fooiPiPS_PS0_PS1_PS2_PS3_PS4_PS5_PS6_PS7_PS8_PS9_PSA_PSB_PSC_ foo()
_Z3kooPA28_A30_i koo()
_Z4makeI7FactoryiET_IT0_Ev make<>()
_Z5firstI3DuoEvS0_ first<>()
_Z5firstI3DuoEvT_ first<>()
_Z9hairyfuncM1YKFPVPFrPA2_PM1XKFKPA3_ilEPcEiE hairyfunc()
_ZGVN5libcw24_GLOBAL__N_cbll.cc0ZhUKa23compiler_bug_workaroundISt6vectorINS_13omanip_id_tctINS_5debug32memblk_types_manipulator_data_ctEEESaIS6_EEE3idsE libcw::(anonymous namespace)::compiler_bug_workaround<>::ids
_ZN12libcw_app_ct10add_optionIS_EEvMT_FvPKcES3_cS3_S3_ libcw_app_ct::add_option<>()
_ZN1AIfEcvT_IiEEv A<>::operator ?<>()
_ZN1N1TIiiE2mfES0_IddE N::T<>::mf()
_ZN1N1fE N::f
_ZN1f1fE f::f
_ZN3FooIA4_iE3barE Foo<>::bar
_ZN5Arena5levelE Arena::level
_ZN5StackIiiE5levelE Stack<>::level
_ZN5libcw5debug13cwprint_usingINS_9_private_12GlobalObjectEEENS0_17cwprint_using_tctIT_EERKS5_MS5_KFvRSt7ostreamE libcw::debug::cwprint_using<>()
_ZN6System5Sound4beepEv System::Sound::beep()
_ZNKSt14priority_queueIP27timer_event_request_base_ctSt5dequeIS1_SaIS1_EE13timer_greaterE3topEv std::priority_queue<>::top()
_ZNKSt15_Deque_iteratorIP15memory_block_stRKS1_PS2_EeqERKS5_ std::_Deque_iterator<>::operator==()
_ZNKSt17__normal_iteratorIPK6optionSt6vectorIS0_SaIS0_EEEmiERKS6_ std::__normal_iterator<>::operator-()
_ZNSbIcSt11char_traitsIcEN5libcw5debug27no_alloc_checking_allocatorEE12_S_constructIPcEES6_T_S7_RKS3_ std::basic_string<>::_S_construct<>()
_ZNSt13_Alloc_traitsISbIcSt18string_char_traitsIcEN5libcw5debug9_private_17allocator_adaptorIcSt24__default_alloc_templateILb0ELi327664EELb1EEEENS5_IS9_S7_Lb1EEEE15_S_instancelessE std::_Alloc_traits<>::_S_instanceless
_ZNSt3_In4wardE std::_In::ward
_ZNZN1N1fEiE1X1gE _ZNZN1N1fEiE1X1gE
_ZNZN1N1fEiE1X1gEv _ZNZN1N1fEiE1X1gEv
_ZSt1BISt1DIP1ARKS2_PS3_ES0_IS2_RS2_PS2_ES2_ET0_T_SB_SA_PT1_ std::B<>()
_ZSt5state std::state
_ZTI7a_class a_class
_ZZN1N1fEiE1p N::f()::p
_ZZN1N1fEiEs N::f()
_ZlsRK1XS1_ operator<<()
_ZlsRKU3fooU4bart1XS0_ operator<<()
_ZlsRKU3fooU4bart1XS2_ operator<<()
_ZlsRSoRKSs operator<<()
_ZngILi42EEvN1AIXplT_Li2EEE1TE operator-<>()
_ZplR1XS0_ operator+()
_Zrm1XS_ operator%()
# Template argument packs can start with I or J.
_Z3addIIiEEvDpT_ add<>()
_Z3addIJiEEvDpT_ add<>()

View File

@ -1,98 +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.
#ifndef BASE_LOG_SEVERITY_H__
#define BASE_LOG_SEVERITY_H__
// The recommended semantics of the log levels are as follows:
//
// INFO:
// Use for state changes or other major events, or to aid debugging.
// WARNING:
// Use for undesired but relatively expected events, which may indicate a
// problem
// ERROR:
// Use for undesired and unexpected events that the program can recover from.
// All ERRORs should be actionable - it should be appropriate to file a bug
// whenever an ERROR occurs in production.
// FATAL:
// Use for undesired and unexpected events that the program cannot recover
// from.
// Variables of type LogSeverity are widely taken to lie in the range
// [0, NUM_SEVERITIES-1]. Be careful to preserve this assumption if
// 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,
NUM_SEVERITIES = 4;
#ifndef GLOG_NO_ABBREVIATED_SEVERITIES
# ifdef ERROR
# error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail.
# endif
const int INFO = GLOG_INFO, WARNING = GLOG_WARNING,
ERROR = GLOG_ERROR, FATAL = GLOG_FATAL;
#endif
// DFATAL is FATAL in debug mode, ERROR in normal mode
#ifdef NDEBUG
#define DFATAL_LEVEL ERROR
#else
#define DFATAL_LEVEL FATAL
#endif
extern GLOG_EXPORT const char* const LogSeverityNames[NUM_SEVERITIES];
// NDEBUG usage helpers related to (RAW_)DCHECK:
//
// DEBUG_MODE is for small !NDEBUG uses like
// if (DEBUG_MODE) foo.CheckThatFoo();
// instead of substantially more verbose
// #ifndef NDEBUG
// foo.CheckThatFoo();
// #endif
//
// IF_DEBUG_MODE is for small !NDEBUG uses like
// IF_DEBUG_MODE( string error; )
// DCHECK(Foo(&error)) << error;
// instead of substantially more verbose
// #ifndef NDEBUG
// string error;
// DCHECK(Foo(&error)) << error;
// #endif
//
#ifdef NDEBUG
enum { DEBUG_MODE = 0 };
#define IF_DEBUG_MODE(x)
#else
enum { DEBUG_MODE = 1 };
#define IF_DEBUG_MODE(x) x
#endif
#endif // BASE_LOG_SEVERITY_H__

File diff suppressed because it is too large Load Diff

View File

@ -1,58 +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.
//
// Author: Shinichiro Hamaji
//
// Detect supported platforms.
#ifndef GLOG_PLATFORM_H
#define GLOG_PLATFORM_H
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
#define GLOG_OS_WINDOWS
#elif defined(__CYGWIN__) || defined(__CYGWIN32__)
#define GLOG_OS_CYGWIN
#elif defined(linux) || defined(__linux) || defined(__linux__)
#ifndef GLOG_OS_LINUX
#define GLOG_OS_LINUX
#endif
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
#define GLOG_OS_MACOSX
#elif defined(__FreeBSD__)
#define GLOG_OS_FREEBSD
#elif defined(__NetBSD__)
#define GLOG_OS_NETBSD
#elif defined(__OpenBSD__)
#define GLOG_OS_OPENBSD
#else
// TODO(hamaji): Add other platforms.
#error Platform not supported by glog. Please consider to contribute platform information by submitting a pull request on Github.
#endif
#endif // GLOG_PLATFORM_H

View File

@ -1,179 +0,0 @@
// Copyright (c) 2006, 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: Maxim Lifantsev
//
// Thread-safe logging routines that do not allocate any memory or
// acquire any locks, and can therefore be used by low-level memory
// allocation and synchronization code.
#ifndef GLOG_RAW_LOGGING_H
#define GLOG_RAW_LOGGING_H
#include <ctime>
@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
// This is similar to LOG(severity) << format... and VLOG(level) << format..,
// but
// * it is to be used ONLY by low-level modules that can't use normal LOG()
// * it is desiged to be a low-level logger that does not allocate any
// memory and does not need any locks, hence:
// * it logs straight and ONLY to STDERR w/o buffering
// * it uses an explicit format and arguments list
// * it will silently chop off really long message strings
// Usage example:
// RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
// RAW_VLOG(3, "status is %i", status);
// 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
// I20200821 211317 file.cc:142] RAW: status is 20
#define RAW_LOG(severity, ...) \
do { \
switch (@ac_google_namespace@::GLOG_ ## severity) { \
case 0: \
RAW_LOG_INFO(__VA_ARGS__); \
break; \
case 1: \
RAW_LOG_WARNING(__VA_ARGS__); \
break; \
case 2: \
RAW_LOG_ERROR(__VA_ARGS__); \
break; \
case 3: \
RAW_LOG_FATAL(__VA_ARGS__); \
break; \
default: \
break; \
} \
} while (0)
// 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.
#if !defined(STRIP_LOG) || STRIP_LOG == 0
#define RAW_VLOG(verboselevel, ...) \
do { \
if (VLOG_IS_ON(verboselevel)) { \
RAW_LOG_INFO(__VA_ARGS__); \
} \
} while (0)
#else
#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG == 0
#if !defined(STRIP_LOG) || STRIP_LOG == 0
#define RAW_LOG_INFO(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_INFO, \
__FILE__, __LINE__, __VA_ARGS__)
#else
#define RAW_LOG_INFO(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG == 0
#if !defined(STRIP_LOG) || STRIP_LOG <= 1
#define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_WARNING, \
__FILE__, __LINE__, __VA_ARGS__)
#else
#define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG <= 1
#if !defined(STRIP_LOG) || STRIP_LOG <= 2
#define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_ERROR, \
__FILE__, __LINE__, __VA_ARGS__)
#else
#define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG <= 2
#if !defined(STRIP_LOG) || STRIP_LOG <= 3
#define RAW_LOG_FATAL(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_FATAL, \
__FILE__, __LINE__, __VA_ARGS__)
#else
#define RAW_LOG_FATAL(...) \
do { \
@ac_google_namespace@::RawLogStub__(0, __VA_ARGS__); \
exit(EXIT_FAILURE); \
} while (0)
#endif // STRIP_LOG <= 3
// Similar to CHECK(condition) << message,
// 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:
// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
// so that the args are not computed when not needed.
#define RAW_CHECK(condition, message) \
do { \
if (!(condition)) { \
RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
} \
} while (0)
// Debug versions of RAW_LOG and RAW_CHECK
#ifndef NDEBUG
#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__)
#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)
#else // NDEBUG
#define RAW_DLOG(severity, ...) \
while (false) \
RAW_LOG(severity, __VA_ARGS__)
#define RAW_DCHECK(condition, message) \
while (false) \
RAW_CHECK(condition, message)
#endif // NDEBUG
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
// Stub log function used to work around for unused variable warnings when
// building with STRIP_LOG > 0.
static inline void RawLogStub__(int /* ignored */, ...) {
}
// Helper function to implement RAW_LOG and RAW_VLOG
// Logs format... at "severity" level, reporting it
// as called from file:line.
// This does not allocate memory or acquire locks.
GLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line,
const char* format, ...)
@ac_cv___attribute___printf_4_5@;
@ac_google_end_namespace@
#endif // GLOG_RAW_LOGGING_H

View File

@ -1,220 +0,0 @@
// Copyright (c) 2003, 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.
//
// Stream output operators for STL containers; to be used for logging *only*.
// Inclusion of this file lets you do:
//
// list<string> x;
// LOG(INFO) << "data: " << x;
// vector<int> 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_
#define UTIL_GTL_STL_LOGGING_INL_H_
#if !@ac_cv_cxx_using_operator@
# error We do not support stl_logging for this compiler
#endif
#include <deque>
#include <list>
#include <map>
#include <ostream>
#include <set>
#include <utility>
#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
// operators so that we can recurse from pair -> container -> container -> pair
// properly.
template<class First, class Second>
std::ostream& operator<<(std::ostream& out, const std::pair<First, Second>& p);
@ac_google_start_namespace@
template<class Iter>
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; \
}
OUTPUT_TWO_ARG_CONTAINER(std::vector)
OUTPUT_TWO_ARG_CONTAINER(std::deque)
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
#define OUTPUT_THREE_ARG_CONTAINER(Sequence) \
template<class T1, class T2, class T3> \
inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3>& seq) { \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \
}
OUTPUT_THREE_ARG_CONTAINER(std::set)
OUTPUT_THREE_ARG_CONTAINER(std::multiset)
#undef OUTPUT_THREE_ARG_CONTAINER
#define OUTPUT_FOUR_ARG_CONTAINER(Sequence) \
template<class T1, class T2, class T3, class T4> \
inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3, T4>& seq) { \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \
}
OUTPUT_FOUR_ARG_CONTAINER(std::map)
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_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
#define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \
template<class T1, class T2, class T3, class T4, class T5> \
inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3, T4, T5>& seq) { \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \
}
#if defined(GLOG_STL_LOGGING_FOR_UNORDERED) && __cplusplus >= 201103L
OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map)
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
template<class First, class Second>
inline std::ostream& operator<<(std::ostream& out,
const std::pair<First, Second>& p) {
out << '(' << p.first << ", " << p.second << ')';
return out;
}
@ac_google_start_namespace@
template<class Iter>
inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
// Output at most 100 elements -- appropriate if used for logging.
for (int i = 0; begin != end && i < 100; ++i, ++begin) {
if (i > 0) out << ' ';
out << *begin;
}
if (begin != end) {
out << " ...";
}
}
@ac_google_end_namespace@
// 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
// types which are themselves defined with this namespace. Without this, these
// operator overloads cannot be found via ADL. If these definitions are not
// found via ADL, they must be #included before they're used, which requires
// this header to be included before apparently independent other headers.
//
// For example, base/logging.h defines various template functions to implement
// CHECK_EQ(x, y) and stream x and y into the log in the event the check fails.
// It does so via the function template MakeCheckOpValueString:
// template<class T>
// void MakeCheckOpValueString(strstream* ss, const T& v) {
// (*ss) << v;
// }
// Because 'glog/logging.h' is included before 'glog/stl_logging.h',
// subsequent CHECK_EQ(v1, v2) for vector<...> typed variable v1 and v2 can only
// find these operator definitions via ADL.
//
// Even this solution has problems -- it may pull unintended operators into the
// namespace as well, allowing them to also be found via ADL, and creating code
// that only works with a particular order of includes. Long term, we need to
// 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
// in both because that would create ambiguous overloads when both are found.
namespace std { using ::operator<<; }
#endif // UTIL_GTL_STL_LOGGING_INL_H_

View File

@ -1,118 +0,0 @@
// Copyright (c) 1999, 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: Ray Sidney and many others
//
// Defines the VLOG_IS_ON macro that controls the variable-verbosity
// conditional logging.
//
// It's used by VLOG and VLOG_IF in logging.h
// and by RAW_VLOG in raw_logging.h to trigger the logging.
//
// It can also be used directly e.g. like this:
// if (VLOG_IS_ON(2)) {
// // do some logging preparation and logging
// // that can't be accomplished e.g. via just VLOG(2) << ...;
// }
//
// The truth value that VLOG_IS_ON(level) returns is determined by
// the three verbosity level flags:
// --v=<n> Gives the default maximal active V-logging level;
// 0 is the default.
// Normally positive values are used for V-logging levels.
// --vmodule=<str> Gives the per-module maximal V-logging levels to override
// the value given by --v.
// E.g. "my_module=2,foo*=3" would change the logging level
// for all code in source files "my_module.*" and "foo*.*"
// ("-inl" suffixes are also disregarded for this matching).
//
// SetVLOGLevel helper function is provided to do limited dynamic control over
// V-logging by overriding the per-module settings given via --vmodule flag.
//
// CAVEAT: --vmodule functionality is not available in non gcc compilers.
//
#ifndef BASE_VLOG_IS_ON_H_
#define BASE_VLOG_IS_ON_H_
#include <glog/log_severity.h>
#if defined(__GNUC__)
// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site.
// (Normally) the first time every VLOG_IS_ON(n) site is hit,
// we determine what variable will dynamically control logging at this site:
// it's either FLAGS_v or an appropriate internal variable
// matching the current source file that represents results of
// parsing of --vmodule flag and/or SetVLOGLevel calls.
#define VLOG_IS_ON(verboselevel) \
__extension__ \
({ static @ac_google_namespace@::SiteFlag vlocal__ = {NULL, NULL, 0, NULL}; \
@ac_google_namespace@::int32 verbose_level__ = (verboselevel); \
(vlocal__.level == NULL ? @ac_google_namespace@::InitVLOG3__(&vlocal__, &FLAGS_v, \
__FILE__, verbose_level__) : *vlocal__.level >= verbose_level__); \
})
#else
// GNU extensions not available, so we do not support --vmodule.
// Dynamic value of FLAGS_v always controls the logging level.
#define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel))
#endif
// Set VLOG(_IS_ON) level for module_pattern to log_level.
// This lets us dynamically control what is normally set by the --vmodule flag.
// Returns the level that previously applied to module_pattern.
// NOTE: To change the log level for VLOG(_IS_ON) sites
// that have already executed after/during InitGoogleLogging,
// one needs to supply the exact --vmodule pattern that applied to them.
// (If no --vmodule pattern applied to them
// the value of FLAGS_v will continue to control them.)
extern GLOG_EXPORT int SetVLOGLevel(const char* module_pattern, int log_level);
// Various declarations needed for VLOG_IS_ON above: =========================
struct SiteFlag {
@ac_google_namespace@::int32* level;
const char* base_name;
size_t base_len;
SiteFlag* next;
};
// Helper routine which determines the logging info for a particalur VLOG site.
// site_flag is the address of the site-local pointer to the controlling
// verbosity level
// site_default is the default to use for *site_flag
// fname is the current source file name
// verbose_level is the argument to VLOG_IS_ON
// We will return the return value for VLOG_IS_ON
// and if possible set *site_flag appropriately.
extern GLOG_EXPORT bool InitVLOG3__(
@ac_google_namespace@::SiteFlag* site_flag,
@ac_google_namespace@::int32* site_default, const char* fname,
@ac_google_namespace@::int32 verbose_level);
#endif // BASE_VLOG_IS_ON_H_

View File

@ -1,672 +0,0 @@
// Copyright (c) 2009, 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: Shinichiro Hamaji
// (based on googletest: http://code.google.com/p/googletest/)
#ifdef GOOGLETEST_H__
#error You must not include this file twice.
#endif
#define GOOGLETEST_H__
#include "utilities.h"
#include <cctype>
#include <csetjmp>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "base/commandlineflags.h"
#if __cplusplus < 201103L && !defined(_MSC_VER)
#define GOOGLE_GLOG_THROW_BAD_ALLOC throw (std::bad_alloc)
#else
#define GOOGLE_GLOG_THROW_BAD_ALLOC
#endif
using std::map;
using std::string;
using std::vector;
_START_GOOGLE_NAMESPACE_
extern GLOG_EXPORT void (*g_logging_fail_func)();
_END_GOOGLE_NAMESPACE_
#undef GLOG_EXPORT
#define GLOG_EXPORT
static inline string GetTempDir() {
vector<string> temp_directories_list;
google::GetExistingTempDirectories(&temp_directories_list);
if (temp_directories_list.empty()) {
fprintf(stderr, "No temporary directory found\n");
exit(EXIT_FAILURE);
}
// Use first directory from list of existing temporary directories.
return temp_directories_list.front();
}
#if defined(GLOG_OS_WINDOWS) && defined(_MSC_VER) && !defined(TEST_SRC_DIR)
// The test will run in glog/vsproject/<project name>
// (e.g., glog/vsproject/logging_unittest).
static const char TEST_SRC_DIR[] = "../..";
#elif !defined(TEST_SRC_DIR)
# warning TEST_SRC_DIR should be defined in config.h
static const char TEST_SRC_DIR[] = ".";
#endif
static const uint32_t PTR_TEST_VALUE = 0x12345678;
DEFINE_string(test_tmpdir, GetTempDir(), "Dir we use for temp files");
DEFINE_string(test_srcdir, TEST_SRC_DIR,
"Source-dir root, needed to find glog_unittest_flagfile");
DEFINE_bool(run_benchmark, false, "If true, run benchmarks");
#ifdef NDEBUG
DEFINE_int32(benchmark_iters, 100000000, "Number of iterations per benchmark");
#else
DEFINE_int32(benchmark_iters, 100000, "Number of iterations per benchmark");
#endif
#ifdef HAVE_LIB_GTEST
# include <gtest/gtest.h>
// Use our ASSERT_DEATH implementation.
# undef ASSERT_DEATH
# undef ASSERT_DEBUG_DEATH
using testing::InitGoogleTest;
#else
_START_GOOGLE_NAMESPACE_
void InitGoogleTest(int*, char**);
void InitGoogleTest(int*, char**) {}
// The following is some bare-bones testing infrastructure
#define EXPECT_NEAR(val1, val2, abs_error) \
do { \
if (abs(val1 - val2) > abs_error) { \
fprintf(stderr, "Check failed: %s within %s of %s\n", #val1, #abs_error, \
#val2); \
exit(EXIT_FAILURE); \
} \
} while (0)
#define EXPECT_TRUE(cond) \
do { \
if (!(cond)) { \
fprintf(stderr, "Check failed: %s\n", #cond); \
exit(EXIT_FAILURE); \
} \
} while (0)
#define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond))
#define EXPECT_OP(op, val1, val2) \
do { \
if (!((val1) op (val2))) { \
fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
exit(EXIT_FAILURE); \
} \
} while (0)
#define EXPECT_EQ(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_LT(val1, val2) EXPECT_OP(<, val1, val2)
#define EXPECT_NAN(arg) \
do { \
if (!isnan(arg)) { \
fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \
exit(EXIT_FAILURE); \
} \
} while (0)
#define EXPECT_INF(arg) \
do { \
if (!isinf(arg)) { \
fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \
exit(EXIT_FAILURE); \
} \
} while (0)
#define EXPECT_DOUBLE_EQ(val1, val2) \
do { \
if (((val1) < (val2) - 0.001 || (val1) > (val2) + 0.001)) { \
fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \
exit(EXIT_FAILURE); \
} \
} while (0)
#define EXPECT_STREQ(val1, val2) \
do { \
if (strcmp((val1), (val2)) != 0) { \
fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \
exit(EXIT_FAILURE); \
} \
} while (0)
vector<void (*)()> g_testlist; // the tests to run
#define TEST(a, b) \
struct Test_##a##_##b { \
Test_##a##_##b() { g_testlist.push_back(&Run); } \
static void Run() { FlagSaver fs; RunTest(); } \
static void RunTest(); \
}; \
static Test_##a##_##b g_test_##a##_##b; \
void Test_##a##_##b::RunTest()
static inline int RUN_ALL_TESTS() {
vector<void (*)()>::const_iterator it;
for (it = g_testlist.begin(); it != g_testlist.end(); ++it) {
(*it)();
}
fprintf(stderr, "Passed %d tests\n\nPASS\n",
static_cast<int>(g_testlist.size()));
return 0;
}
_END_GOOGLE_NAMESPACE_
#endif // ! HAVE_LIB_GTEST
_START_GOOGLE_NAMESPACE_
static bool g_called_abort;
static jmp_buf g_jmp_buf;
static inline void CalledAbort() {
g_called_abort = true;
longjmp(g_jmp_buf, 1);
}
#ifdef GLOG_OS_WINDOWS
// TODO(hamaji): Death test somehow doesn't work in Windows.
#define ASSERT_DEATH(fn, msg)
#else
#define ASSERT_DEATH(fn, msg) \
do { \
g_called_abort = false; \
/* in logging.cc */ \
void (*original_logging_fail_func)() = g_logging_fail_func; \
g_logging_fail_func = &CalledAbort; \
if (!setjmp(g_jmp_buf)) fn; \
/* set back to their default */ \
g_logging_fail_func = original_logging_fail_func; \
if (!g_called_abort) { \
fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \
exit(EXIT_FAILURE); \
} \
} while (0)
#endif
#ifdef NDEBUG
#define ASSERT_DEBUG_DEATH(fn, msg)
#else
#define ASSERT_DEBUG_DEATH(fn, msg) ASSERT_DEATH(fn, msg)
#endif // NDEBUG
// Benchmark tools.
#define BENCHMARK(n) static BenchmarkRegisterer __benchmark_ ## n (#n, &n);
map<string, void (*)(int)> g_benchlist; // the benchmarks to run
class BenchmarkRegisterer {
public:
BenchmarkRegisterer(const char* name, void (*function)(int iters)) {
EXPECT_TRUE(g_benchlist.insert(std::make_pair(name, function)).second);
}
};
static inline void RunSpecifiedBenchmarks() {
if (!FLAGS_run_benchmark) {
return;
}
int iter_cnt = FLAGS_benchmark_iters;
puts("Benchmark\tTime(ns)\tIterations");
for (map<string, void (*)(int)>::const_iterator iter = g_benchlist.begin();
iter != g_benchlist.end();
++iter) {
clock_t start = clock();
iter->second(iter_cnt);
double elapsed_ns = (static_cast<double>(clock()) - start) /
CLOCKS_PER_SEC * 1000 * 1000 * 1000;
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat="
#endif
printf("%s\t%8.2lf\t%10d\n",
iter->first.c_str(), elapsed_ns / iter_cnt, iter_cnt);
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
}
puts("");
}
// ----------------------------------------------------------------------
// Golden file functions
// ----------------------------------------------------------------------
class CapturedStream {
public:
CapturedStream(int fd, const string & filename) :
fd_(fd),
uncaptured_fd_(-1),
filename_(filename) {
Capture();
}
~CapturedStream() {
if (uncaptured_fd_ != -1) {
CHECK(close(uncaptured_fd_) != -1);
}
}
// Start redirecting output to a file
void Capture() {
// Keep original stream for later
CHECK(uncaptured_fd_ == -1) << ", Stream " << fd_ << " already captured!";
uncaptured_fd_ = dup(fd_);
CHECK(uncaptured_fd_ != -1);
// Open file to save stream to
int cap_fd = open(filename_.c_str(),
O_CREAT | O_TRUNC | O_WRONLY,
S_IRUSR | S_IWUSR);
CHECK(cap_fd != -1);
// Send stdout/stderr to this file
fflush(NULL);
CHECK(dup2(cap_fd, fd_) != -1);
CHECK(close(cap_fd) != -1);
}
// Remove output redirection
void StopCapture() {
// Restore original stream
if (uncaptured_fd_ != -1) {
fflush(NULL);
CHECK(dup2(uncaptured_fd_, fd_) != -1);
}
}
const string & filename() const { return filename_; }
private:
int fd_; // file descriptor being captured
int uncaptured_fd_; // where the stream was originally being sent to
string filename_; // file where stream is being saved
};
static CapturedStream * s_captured_streams[STDERR_FILENO+1];
// Redirect a file descriptor to a file.
// fd - Should be STDOUT_FILENO or STDERR_FILENO
// filename - File where output should be stored
static inline void CaptureTestOutput(int fd, const string & filename) {
CHECK((fd == STDOUT_FILENO) || (fd == STDERR_FILENO));
CHECK(s_captured_streams[fd] == NULL);
s_captured_streams[fd] = new CapturedStream(fd, filename);
}
static inline void CaptureTestStdout() {
CaptureTestOutput(STDOUT_FILENO, FLAGS_test_tmpdir + "/captured.out");
}
static inline void CaptureTestStderr() {
CaptureTestOutput(STDERR_FILENO, FLAGS_test_tmpdir + "/captured.err");
}
// Return the size (in bytes) of a file
static inline size_t GetFileSize(FILE * file) {
fseek(file, 0, SEEK_END);
return static_cast<size_t>(ftell(file));
}
// Read the entire content of a file as a string
static inline string ReadEntireFile(FILE * file) {
const size_t file_size = GetFileSize(file);
char * const buffer = new char[file_size];
size_t bytes_last_read = 0; // # of bytes read in the last fread()
size_t bytes_read = 0; // # of bytes read so far
fseek(file, 0, SEEK_SET);
// Keep reading the file until we cannot read further or the
// pre-determined file size is reached.
do {
bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
bytes_read += bytes_last_read;
} while (bytes_last_read > 0 && bytes_read < file_size);
const string content = string(buffer, buffer+bytes_read);
delete[] buffer;
return content;
}
// Get the captured stdout (when fd is STDOUT_FILENO) or stderr (when
// fd is STDERR_FILENO) as a string
static inline string GetCapturedTestOutput(int fd) {
CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO);
CapturedStream * const cap = s_captured_streams[fd];
CHECK(cap)
<< ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
// Make sure everything is flushed.
cap->StopCapture();
// Read the captured file.
FILE * const file = fopen(cap->filename().c_str(), "r");
const string content = ReadEntireFile(file);
fclose(file);
delete cap;
s_captured_streams[fd] = NULL;
return content;
}
// Get the captured stderr of a test as a string.
static inline string GetCapturedTestStderr() {
return GetCapturedTestOutput(STDERR_FILENO);
}
static const std::size_t kLoggingPrefixLength = 9;
// Check if the string is [IWEF](\d{8}|YEARDATE)
static inline bool IsLoggingPrefix(const string& s) {
if (s.size() != kLoggingPrefixLength) {
return false;
}
if (!strchr("IWEF", s[0])) return false;
for (size_t i = 1; i <= 8; ++i) {
if (!isdigit(s[i]) && s[i] != "YEARDATE"[i-1]) return false;
}
return true;
}
// Convert log output into normalized form.
//
// Example:
// I20200102 030405 logging_unittest.cc:345] RAW: vlog -1
// => IYEARDATE TIME__ logging_unittest.cc:LINE] RAW: vlog -1
static inline string MungeLine(const string& line) {
string before, logcode_date, time, thread_lineinfo;
std::size_t begin_of_logging_prefix = 0;
for (; begin_of_logging_prefix + kLoggingPrefixLength < line.size();
++begin_of_logging_prefix) {
if (IsLoggingPrefix(
line.substr(begin_of_logging_prefix, kLoggingPrefixLength))) {
break;
}
}
if (begin_of_logging_prefix + kLoggingPrefixLength >= line.size()) {
return line;
} else if (begin_of_logging_prefix > 0) {
before = line.substr(0, begin_of_logging_prefix - 1);
}
std::istringstream iss(line.substr(begin_of_logging_prefix));
iss >> logcode_date;
iss >> time;
iss >> thread_lineinfo;
CHECK(!thread_lineinfo.empty());
if (thread_lineinfo[thread_lineinfo.size() - 1] != ']') {
// We found thread ID.
string tmp;
iss >> tmp;
CHECK(!tmp.empty());
CHECK_EQ(']', tmp[tmp.size() - 1]);
thread_lineinfo = "THREADID " + tmp;
}
size_t index = thread_lineinfo.find(':');
CHECK_NE(string::npos, index);
thread_lineinfo = thread_lineinfo.substr(0, index+1) + "LINE]";
string rest;
std::getline(iss, rest);
return (before + logcode_date[0] + "YEARDATE TIME__ " + thread_lineinfo +
MungeLine(rest));
}
static inline void StringReplace(string* str,
const string& oldsub,
const string& newsub) {
size_t pos = str->find(oldsub);
if (pos != string::npos) {
str->replace(pos, oldsub.size(), newsub);
}
}
static inline string Munge(const string& filename) {
FILE* fp = fopen(filename.c_str(), "rb");
CHECK(fp != NULL) << filename << ": couldn't open";
char buf[4096];
string result;
while (fgets(buf, 4095, fp)) {
string line = MungeLine(buf);
const size_t str_size = 256;
char null_str[str_size];
char ptr_str[str_size];
snprintf(null_str, str_size, "%p", static_cast<void*>(NULL));
snprintf(ptr_str, str_size, "%p", reinterpret_cast<void*>(PTR_TEST_VALUE));
StringReplace(&line, "__NULLP__", null_str);
StringReplace(&line, "__PTRTEST__", ptr_str);
StringReplace(&line, "__SUCCESS__", StrError(0));
StringReplace(&line, "__ENOENT__", StrError(ENOENT));
StringReplace(&line, "__EINTR__", StrError(EINTR));
StringReplace(&line, "__ENXIO__", StrError(ENXIO));
StringReplace(&line, "__ENOEXEC__", StrError(ENOEXEC));
result += line + "\n";
}
fclose(fp);
return result;
}
static inline void WriteToFile(const string& body, const string& file) {
FILE* fp = fopen(file.c_str(), "wb");
fwrite(body.data(), 1, body.size(), fp);
fclose(fp);
}
static inline bool MungeAndDiffTest(const string& golden_filename,
CapturedStream* cap) {
if (cap == s_captured_streams[STDOUT_FILENO]) {
CHECK(cap) << ": did you forget CaptureTestStdout()?";
} else {
CHECK(cap) << ": did you forget CaptureTestStderr()?";
}
cap->StopCapture();
// Run munge
const string captured = Munge(cap->filename());
const string golden = Munge(golden_filename);
if (captured != golden) {
fprintf(stderr,
"Test with golden file failed. We'll try to show the diff:\n");
string munged_golden = golden_filename + ".munged";
WriteToFile(golden, munged_golden);
string munged_captured = cap->filename() + ".munged";
WriteToFile(captured, munged_captured);
#ifdef GLOG_OS_WINDOWS
string diffcmd("fc " + munged_golden + " " + munged_captured);
#else
string diffcmd("diff -u " + munged_golden + " " + munged_captured);
#endif
if (system(diffcmd.c_str()) != 0) {
fprintf(stderr, "diff command was failed.\n");
}
unlink(munged_golden.c_str());
unlink(munged_captured.c_str());
return false;
}
LOG(INFO) << "Diff was successful";
return true;
}
static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
return MungeAndDiffTest(golden_filename, s_captured_streams[STDERR_FILENO]);
}
static inline bool MungeAndDiffTestStdout(const string& golden_filename) {
return MungeAndDiffTest(golden_filename, s_captured_streams[STDOUT_FILENO]);
}
// Save flags used from logging_unittest.cc.
#ifndef HAVE_LIB_GFLAGS
struct FlagSaver {
FlagSaver()
: v_(FLAGS_v),
stderrthreshold_(FLAGS_stderrthreshold),
logtostderr_(FLAGS_logtostderr),
alsologtostderr_(FLAGS_alsologtostderr) {}
~FlagSaver() {
FLAGS_v = v_;
FLAGS_stderrthreshold = stderrthreshold_;
FLAGS_logtostderr = logtostderr_;
FLAGS_alsologtostderr = alsologtostderr_;
}
int v_;
int stderrthreshold_;
bool logtostderr_;
bool alsologtostderr_;
};
#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.
void (*g_new_hook)() = NULL;
_END_GOOGLE_NAMESPACE_
void* operator new(size_t size) GOOGLE_GLOG_THROW_BAD_ALLOC {
if (GOOGLE_NAMESPACE::g_new_hook) {
GOOGLE_NAMESPACE::g_new_hook();
}
return malloc(size);
}
void* operator new[](size_t size) GOOGLE_GLOG_THROW_BAD_ALLOC {
return ::operator new(size);
}
void operator delete(void* p) throw() {
free(p);
}
void operator delete(void* p, size_t) throw() {
::operator delete(p);
}
void operator delete[](void* p) throw() {
::operator delete(p);
}
void operator delete[](void* p, size_t) throw() {
::operator delete(p);
}

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,79 +0,0 @@
#! /bin/sh
#
# 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: Sergey Ioffe
get_strings () {
if test -e ".libs/$1"; then
binary=".libs/$1"
elif test -e "$1.exe"; then
binary="$1.exe"
else
echo "We coundn't find $1 binary."
exit 1
fi
strings -n 10 $binary | sort | awk '/TESTMESSAGE/ {printf "%s ", $2}'
}
# Die if "$1" != "$2", print $3 as death reason
check_eq () {
if [ "$1" != "$2" ]; then
echo "Check failed: '$1' == '$2' ${3:+ ($3)}"
exit 1
fi
}
die () {
echo $1
exit 1
}
# Check that the string literals are appropriately stripped. This will
# not be the case in debug mode.
mode=`GLOG_check_mode=1 ./logging_striptest0 2> /dev/null`
if [ "$mode" = "opt" ];
then
echo "In OPT mode"
check_eq "`get_strings logging_striptest0`" "COND ERROR FATAL INFO USAGE WARNING "
check_eq "`get_strings logging_striptest2`" "COND ERROR FATAL USAGE "
check_eq "`get_strings logging_striptest10`" ""
else
echo "In DBG mode; not checking strings"
fi
# Check that LOG(FATAL) aborts even for large STRIP_LOG
./logging_striptest2 2>/dev/null && die "Did not abort for STRIP_LOG=2"
./logging_striptest10 2>/dev/null && die "Did not abort for STRIP_LOG=10"
echo "PASS"

View File

@ -1,35 +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: Sergey Ioffe
#define GOOGLE_STRIP_LOG 10
// Include the actual test.
#include "logging_striptest_main.cc"

View File

@ -1,35 +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: Sergey Ioffe
#define GOOGLE_STRIP_LOG 2
// Include the actual test.
#include "logging_striptest_main.cc"

View File

@ -1,73 +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: Sergey Ioffe
// The common part of the striplog tests.
#include <cstdio>
#include <string>
#include <iosfwd>
#include <glog/logging.h>
#include "base/commandlineflags.h"
#include "config.h"
DECLARE_bool(logtostderr);
GLOG_DEFINE_bool(check_mode, false, "Prints 'opt' or 'dbg'");
using std::string;
using namespace GOOGLE_NAMESPACE;
int CheckNoReturn(bool b) {
string s;
if (b) {
LOG(FATAL) << "Fatal";
} else {
return 0;
}
}
struct A { };
std::ostream &operator<<(std::ostream &str, const A&) {return str;}
int main(int, char* argv[]) {
FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]);
if (FLAGS_check_mode) {
printf("%s\n", DEBUG_MODE ? "dbg" : "opt");
return 0;
}
LOG(INFO) << "TESTMESSAGE INFO";
LOG(WARNING) << 2 << "something" << "TESTMESSAGE WARNING"
<< 1 << 'c' << A() << std::endl;
LOG(ERROR) << "TESTMESSAGE ERROR";
bool flag = true;
(flag ? LOG(INFO) : LOG(ERROR)) << "TESTMESSAGE COND";
LOG(FATAL) << "TESTMESSAGE FATAL";
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,150 +0,0 @@
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog -1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 0
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log warning
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if -1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if warning
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info expr
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if info every 1 expr
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] log_if error every 1 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] vlog_if 0 every 1 expr
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_STRING: reported info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_STRING: reported warning
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_STRING: reported error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_STRING: LOG_STRING: collected info
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_STRING: LOG_STRING: collected warning
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_STRING: LOG_STRING: collected error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected warning
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: reported info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: reported warning
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: reported error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_TO_SINK:
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected warning
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK: collected error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK_BUT_NOT_TO_LOGFILE: collected info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK_BUT_NOT_TO_LOGFILE: collected warning
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_SINK_BUT_NOT_TO_LOGFILE: collected error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: collected info
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_TO_STRING: LOG_TO_STRING: collected info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: collected warning
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_TO_STRING: LOG_TO_STRING: collected warning
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: collected error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Captured by LOG_TO_STRING: LOG_TO_STRING: collected error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: reported info
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: reported warning
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] LOG_TO_STRING: reported error
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink is sending out a message: IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Have 0 left
EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 2
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink is sending out a message: EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 2
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Have 0 left
WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 3
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink is sending out a message: WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 3
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Have 0 left
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink capture: IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 1
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink capture: EYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 2
IYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Sink capture: WYEARDATE TIME__ THREADID logging_unittest.cc:LINE] Message 3

View File

@ -1,156 +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: Zhanyong Wan
//
// Defines the ScopedMockLog class (using Google C++ Mocking
// Framework), which is convenient for testing code that uses LOG().
#ifndef GLOG_SRC_MOCK_LOG_H_
#define GLOG_SRC_MOCK_LOG_H_
// For GOOGLE_NAMESPACE. This must go first so we get _XOPEN_SOURCE.
#include "utilities.h"
#include <string>
#include <gmock/gmock.h>
#include <glog/logging.h>
_START_GOOGLE_NAMESPACE_
namespace glog_testing {
// A ScopedMockLog object intercepts LOG() messages issued during its
// lifespan. Using this together with Google C++ Mocking Framework,
// it's very easy to test how a piece of code calls LOG(). The
// typical usage:
//
// TEST(FooTest, LogsCorrectly) {
// ScopedMockLog log;
//
// // We expect the WARNING "Something bad!" exactly twice.
// EXPECT_CALL(log, Log(WARNING, _, "Something bad!"))
// .Times(2);
//
// // We allow foo.cc to call LOG(INFO) any number of times.
// EXPECT_CALL(log, Log(INFO, HasSubstr("/foo.cc"), _))
// .Times(AnyNumber());
//
// Foo(); // Exercises the code under test.
// }
class ScopedMockLog : public GOOGLE_NAMESPACE::LogSink {
public:
// When a ScopedMockLog object is constructed, it starts to
// intercept logs.
ScopedMockLog() { AddLogSink(this); }
// When the object is destructed, it stops intercepting logs.
~ScopedMockLog() { RemoveLogSink(this); }
// Implements the mock method:
//
// void Log(LogSeverity severity, const string& file_path,
// const string& message);
//
// The second argument to Send() is the full path of the source file
// in which the LOG() was issued.
//
// Note, that in a multi-threaded environment, all LOG() messages from a
// single thread will be handled in sequence, but that cannot be guaranteed
// for messages from different threads. In fact, if the same or multiple
// expectations are matched on two threads concurrently, their actions will
// be executed concurrently as well and may interleave.
MOCK_METHOD3(Log, void(GOOGLE_NAMESPACE::LogSeverity severity,
const std::string& file_path,
const std::string& message));
private:
// Implements the send() virtual function in class LogSink.
// Whenever a LOG() statement is executed, this function will be
// invoked with information presented in the LOG().
//
// The method argument list is long and carries much information a
// test usually doesn't care about, so we trim the list before
// forwarding the call to Log(), which is much easier to use in
// tests.
//
// We still cannot call Log() directly, as it may invoke other LOG()
// messages, either due to Invoke, or due to an error logged in
// Google C++ Mocking Framework code, which would trigger a deadlock
// since a lock is held during send().
//
// Hence, we save the message for WaitTillSent() which will be called after
// the lock on send() is released, and we'll call Log() inside
// WaitTillSent(). Since while a single send() call may be running at a
// time, multiple WaitTillSent() calls (along with the one send() call) may
// be running simultaneously, we ensure thread-safety of the exchange between
// send() and WaitTillSent(), and that for each message, LOG(), send(),
// WaitTillSent() and Log() are executed in the same thread.
virtual void send(GOOGLE_NAMESPACE::LogSeverity severity,
const char* full_filename,
const char* /*base_filename*/, int /*line*/,
const LogMessageTime & /*logmsgtime*/,
const char* message, size_t message_len) {
// We are only interested in the log severity, full file name, and
// log message.
message_info_.severity = severity;
message_info_.file_path = full_filename;
message_info_.message = std::string(message, message_len);
}
// Implements the WaitTillSent() virtual function in class LogSink.
// It will be executed after send() and after the global logging lock is
// released, so calls within it (or rather within the Log() method called
// within) may also issue LOG() statements.
//
// LOG(), send(), WaitTillSent() and Log() will occur in the same thread for
// a given log message.
virtual void WaitTillSent() {
// First, and very importantly, we save a copy of the message being
// processed before calling Log(), since Log() may indirectly call send()
// and WaitTillSent() in the same thread again.
MessageInfo message_info = message_info_;
Log(message_info.severity, message_info.file_path, message_info.message);
}
// All relevant information about a logged message that needs to be passed
// from send() to WaitTillSent().
struct MessageInfo {
GOOGLE_NAMESPACE::LogSeverity severity;
std::string file_path;
std::string message;
};
MessageInfo message_info_;
};
} // namespace glog_testing
_END_GOOGLE_NAMESPACE_
#endif // GLOG_SRC_MOCK_LOG_H_

View File

@ -1,108 +0,0 @@
// Copyright (c) 2022, 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: Zhanyong Wan
// Tests the ScopedMockLog class.
#include "mock-log.h"
#include <string>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace {
using GOOGLE_NAMESPACE::GLOG_ERROR;
using GOOGLE_NAMESPACE::GLOG_INFO;
using GOOGLE_NAMESPACE::GLOG_WARNING;
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
using std::string;
using testing::_;
using testing::EndsWith;
using testing::InSequence;
using testing::InvokeWithoutArgs;
// Tests that ScopedMockLog intercepts LOG()s when it's alive.
TEST(ScopedMockLogTest, InterceptsLog) {
ScopedMockLog log;
InSequence s;
EXPECT_CALL(log,
Log(GLOG_WARNING, EndsWith("mock-log_unittest.cc"), "Fishy."));
EXPECT_CALL(log, Log(GLOG_INFO, _, "Working..."))
.Times(2);
EXPECT_CALL(log, Log(GLOG_ERROR, _, "Bad!!"));
LOG(WARNING) << "Fishy.";
LOG(INFO) << "Working...";
LOG(INFO) << "Working...";
LOG(ERROR) << "Bad!!";
}
void LogBranch() {
LOG(INFO) << "Logging a branch...";
}
void LogTree() {
LOG(INFO) << "Logging the whole tree...";
}
void LogForest() {
LOG(INFO) << "Logging the entire forest.";
LOG(INFO) << "Logging the entire forest..";
LOG(INFO) << "Logging the entire forest...";
}
// The purpose of the following test is to verify that intercepting logging
// continues to work properly if a LOG statement is executed within the scope
// of a mocked call.
TEST(ScopedMockLogTest, LogDuringIntercept) {
ScopedMockLog log;
InSequence s;
EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, "Logging a branch..."))
.WillOnce(InvokeWithoutArgs(LogTree));
EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, "Logging the whole tree..."))
.WillOnce(InvokeWithoutArgs(LogForest));
EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, "Logging the entire forest."));
EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, "Logging the entire forest.."));
EXPECT_CALL(log, Log(GLOG_INFO, __FILE__, "Logging the entire forest..."));
LogBranch();
}
} // namespace
int main(int argc, char **argv) {
GOOGLE_NAMESPACE::InitGoogleLogging(argv[0]);
testing::InitGoogleTest(&argc, argv);
testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}

View File

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

View File

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

View File

@ -1,178 +0,0 @@
// Copyright (c) 2006, 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: Maxim Lifantsev
//
// logging_unittest.cc covers the functionality herein
#include "utilities.h"
#include <stdarg.h>
#include <cstdio>
#include <cerrno>
#ifdef HAVE_UNISTD_H
# 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
// Not so safe, but what can you do?
# define safe_write(fd, s, len) write(fd, s, len)
#endif
_START_GOOGLE_NAMESPACE_
#if defined(__GNUC__)
#define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck) \
__attribute__((format(archetype, stringIndex, firstToCheck)))
#define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex) \
__attribute__((format_arg(stringIndex)))
#else
#define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck)
#define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex)
#endif
// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
// that invoke malloc() and getenv() that might acquire some locks.
// If this becomes a problem we should reimplement a subset of vsnprintf
// that does not need locks and malloc.
// Helper for RawLog__ below.
// *DoRawLog writes to *buf of *size and move them past the written portion.
// It returns true iff there was no overflow or error.
GLOG_ATTRIBUTE_FORMAT(printf, 3, 4)
static bool DoRawLog(char** buf, size_t* size, const char* format, ...) {
va_list ap;
va_start(ap, format);
int n = vsnprintf(*buf, *size, format, ap);
va_end(ap);
if (n < 0 || static_cast<size_t>(n) > *size) return false;
*size -= static_cast<size_t>(n);
*buf += n;
return true;
}
// Helper for RawLog__ below.
inline static bool VADoRawLog(char** buf, size_t* size,
const char* format, va_list ap) {
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif
int n = vsnprintf(*buf, *size, format, ap);
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
if (n < 0 || static_cast<size_t>(n) > *size) return false;
*size -= static_cast<size_t>(n);
*buf += n;
return true;
}
static const int kLogBufSize = 3000;
static bool crashed = false;
static CrashReason crash_reason;
static char crash_buf[kLogBufSize + 1] = { 0 }; // Will end in '\0'
GLOG_ATTRIBUTE_FORMAT(printf, 4, 5)
void RawLog__(LogSeverity severity, const char* file, int line,
const char* format, ...) {
if (!(FLAGS_logtostdout || FLAGS_logtostderr ||
severity >= FLAGS_stderrthreshold || FLAGS_alsologtostderr ||
!IsGoogleLoggingInitialized())) {
return; // this stderr log message is suppressed
}
// can't call localtime_r here: it can allocate
char buffer[kLogBufSize];
char* buf = buffer;
size_t size = sizeof(buffer);
// NOTE: this format should match the specification in base/logging.h
DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %5u %s:%d] RAW: ",
LogSeverityNames[severity][0],
static_cast<unsigned int>(GetTID()),
const_basename(const_cast<char *>(file)), line);
// Record the position and size of the buffer after the prefix
const char* msg_start = buf;
const size_t msg_size = size;
va_list ap;
va_start(ap, format);
bool no_chop = VADoRawLog(&buf, &size, format, ap);
va_end(ap);
if (no_chop) {
DoRawLog(&buf, &size, "\n");
} else {
DoRawLog(&buf, &size, "RAW_LOG ERROR: The Message was too long!\n");
}
// We make a raw syscall to write directly to the stderr file descriptor,
// avoiding FILE buffering (to avoid invoking malloc()), and bypassing
// libc (to side-step any libc interception).
// We write just once to avoid races with other invocations of RawLog__.
safe_write(STDERR_FILENO, buffer, strlen(buffer));
if (severity == GLOG_FATAL) {
if (!sync_val_compare_and_swap(&crashed, false, true)) {
crash_reason.filename = file;
crash_reason.line_number = line;
memcpy(crash_buf, msg_start, msg_size); // Don't include prefix
crash_reason.message = crash_buf;
#ifdef HAVE_STACKTRACE
crash_reason.depth =
GetStackTrace(crash_reason.stack, ARRAYSIZE(crash_reason.stack), 1);
#else
crash_reason.depth = 0;
#endif
SetCrashReason(&crash_reason);
}
LogMessage::Fail(); // abort()
}
}
_END_GOOGLE_NAMESPACE_

View File

@ -1,409 +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.
//
// Author: Satoru Takabayashi
//
// Implementation of InstallFailureSignalHandler().
#include "utilities.h"
#include "stacktrace.h"
#include "symbolize.h"
#include <glog/logging.h>
#include <csignal>
#include <ctime>
#ifdef HAVE_UCONTEXT_H
# include <ucontext.h>
#endif
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
#include <algorithm>
_START_GOOGLE_NAMESPACE_
namespace {
// We'll install the failure signal handler for these signals. We could
// use strsignal() to get signal names, but we don't use it to avoid
// introducing yet another #ifdef complication.
//
// The list should be synced with the comment in signalhandler.h.
const struct {
int number;
const char *name;
} kFailureSignals[] = {
{ SIGSEGV, "SIGSEGV" },
{ SIGILL, "SIGILL" },
{ SIGFPE, "SIGFPE" },
{ SIGABRT, "SIGABRT" },
#if !defined(GLOG_OS_WINDOWS)
{ SIGBUS, "SIGBUS" },
#endif
{ SIGTERM, "SIGTERM" },
};
static bool kFailureSignalHandlerInstalled = false;
#if !defined(GLOG_OS_WINDOWS)
// Returns the program counter from signal context, NULL if unknown.
void* GetPC(void* ucontext_in_void) {
#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
if (ucontext_in_void != NULL) {
ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void);
return (void*)context->PC_FROM_UCONTEXT;
}
#else
(void)ucontext_in_void;
#endif
return NULL;
}
#endif
// The class is used for formatting error messages. We don't use printf()
// as it's not async signal safe.
class MinimalFormatter {
public:
MinimalFormatter(char *buffer, size_t size)
: buffer_(buffer),
cursor_(buffer),
end_(buffer + size) {
}
// Returns the number of bytes written in the 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.
void AppendString(const char* str) {
ptrdiff_t i = 0;
while (str[i] != '\0' && cursor_ + i < end_) {
cursor_[i] = str[i];
++i;
}
cursor_ += i;
}
// Formats "number" in "radix" and updates the internal cursor.
// Lowercase letters are used for 'a' - 'z'.
void AppendUint64(uint64 number, unsigned radix) {
unsigned i = 0;
while (cursor_ + i < end_) {
const uint64 tmp = number % radix;
number /= radix;
cursor_[i] = static_cast<char>(tmp < 10 ? '0' + tmp : 'a' + tmp - 10);
++i;
if (number == 0) {
break;
}
}
// Reverse the bytes written.
std::reverse(cursor_, cursor_ + i);
cursor_ += i;
}
// Formats "number" as hexadecimal number, and updates the internal
// cursor. Padding will be added in front if needed.
void AppendHexWithPadding(uint64 number, int width) {
char* start = cursor_;
AppendString("0x");
AppendUint64(number, 16);
// Move to right and add padding in front if needed.
if (cursor_ < start + width) {
const int64 delta = start + width - cursor_;
std::copy(start, cursor_, start + delta);
std::fill(start, start + delta, ' ');
cursor_ = start + width;
}
}
private:
char *buffer_;
char *cursor_;
const char * const end_;
};
// Writes the given data with the size to the standard error.
void WriteToStderr(const char* data, size_t size) {
if (write(STDERR_FILENO, data, size) < 0) {
// Ignore errors.
}
}
// The writer function can be changed by InstallFailureWriter().
void (*g_failure_writer)(const char* data, size_t size) = WriteToStderr;
// Dumps time information. We don't dump human-readable time information
// as localtime() is not guaranteed to be async signal safe.
void DumpTimeInfo() {
time_t time_in_sec = time(NULL);
char buf[256]; // Big enough for time info.
MinimalFormatter formatter(buf, sizeof(buf));
formatter.AppendString("*** Aborted at ");
formatter.AppendUint64(static_cast<uint64>(time_in_sec), 10);
formatter.AppendString(" (unix time)");
formatter.AppendString(" try \"date -d @");
formatter.AppendUint64(static_cast<uint64>(time_in_sec), 10);
formatter.AppendString("\" if you are using GNU date ***\n");
g_failure_writer(buf, formatter.num_bytes_written());
}
// TODO(hamaji): Use signal instead of sigaction?
#ifdef HAVE_SIGACTION
// Dumps information about the signal to STDERR.
void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
// Get the signal name.
const char* signal_name = NULL;
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
if (signal_number == kFailureSignals[i].number) {
signal_name = kFailureSignals[i].name;
}
}
char buf[256]; // Big enough for signal info.
MinimalFormatter formatter(buf, sizeof(buf));
formatter.AppendString("*** ");
if (signal_name) {
formatter.AppendString(signal_name);
} else {
// Use the signal number if the name is unknown. The signal name
// should be known, but just in case.
formatter.AppendString("Signal ");
formatter.AppendUint64(static_cast<uint64>(signal_number), 10);
}
formatter.AppendString(" (@0x");
formatter.AppendUint64(reinterpret_cast<uintptr_t>(siginfo->si_addr), 16);
formatter.AppendString(")");
formatter.AppendString(" received by PID ");
formatter.AppendUint64(static_cast<uint64>(getpid()), 10);
formatter.AppendString(" (TID 0x");
// We assume pthread_t is an integral number or a pointer, rather
// than a complex struct. In some environments, pthread_self()
// returns an uint64 but in some other environments pthread_self()
// returns a pointer.
pthread_t id = pthread_self();
formatter.AppendUint64(
reinterpret_cast<uint64>(reinterpret_cast<const char*>(id)), 16);
formatter.AppendString(") ");
// Only linux has the PID of the signal sender in si_pid.
#ifdef GLOG_OS_LINUX
formatter.AppendString("from PID ");
formatter.AppendUint64(static_cast<uint64>(siginfo->si_pid), 10);
formatter.AppendString("; ");
#endif
formatter.AppendString("stack trace: ***\n");
g_failure_writer(buf, formatter.num_bytes_written());
}
#endif // HAVE_SIGACTION
// Dumps information about the stack frame to STDERR.
void DumpStackFrameInfo(const char* prefix, void* pc) {
// Get the symbol name.
const char *symbol = "(unknown)";
char symbolized[1024]; // Big enough for a sane symbol.
// Symbolizes the previous address of pc because pc may be in the
// next function.
if (Symbolize(reinterpret_cast<char *>(pc) - 1,
symbolized, sizeof(symbolized))) {
symbol = symbolized;
}
char buf[1024]; // Big enough for stack frame info.
MinimalFormatter formatter(buf, sizeof(buf));
formatter.AppendString(prefix);
formatter.AppendString("@ ");
const int width = 2 * sizeof(void*) + 2; // + 2 for "0x".
formatter.AppendHexWithPadding(reinterpret_cast<uintptr_t>(pc), width);
formatter.AppendString(" ");
formatter.AppendString(symbol);
formatter.AppendString("\n");
g_failure_writer(buf, formatter.num_bytes_written());
}
// Invoke the default signal handler.
void InvokeDefaultSignalHandler(int signal_number) {
#ifdef HAVE_SIGACTION
struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask);
sig_action.sa_handler = SIG_DFL;
sigaction(signal_number, &sig_action, NULL);
kill(getpid(), signal_number);
#elif defined(GLOG_OS_WINDOWS)
signal(signal_number, SIG_DFL);
raise(signal_number);
#endif
}
// This variable is used for protecting FailureSignalHandler() from
// dumping stuff while another thread is doing it. Our policy is to let
// the first thread dump stuff and let other threads wait.
// See also comments in FailureSignalHandler().
static pthread_t* g_entered_thread_id_pointer = NULL;
// 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
{
// 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
// do some interesting stuff from here.
// TODO(satorux): We might want to set timeout here using alarm(), but
// mixing alarm() and sleep() can be a bad idea.
// First dump time info.
DumpTimeInfo();
#if !defined(GLOG_OS_WINDOWS)
// Get the program counter from ucontext.
void *pc = GetPC(ucontext);
DumpStackFrameInfo("PC: ", pc);
#endif
#ifdef HAVE_STACKTRACE
// Get the stack traces.
void *stack[32];
// +1 to exclude this function.
const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
# ifdef HAVE_SIGACTION
DumpSignalInfo(signal_number, signal_info);
# endif
// Dump the stack traces.
for (int i = 0; i < depth; ++i) {
DumpStackFrameInfo(" ", stack[i]);
}
#endif
// *** TRANSITION ***
//
// BEFORE this point, all code must be async-termination-safe!
// (See WARNING above.)
//
// AFTER this point, we do unsafe things, like using LOG()!
// The process could be terminated or hung at any time. We try to
// do more useful things first and riskier things later.
// Flush the logs before we do anything in case 'anything'
// causes problems.
FlushLogFilesUnsafe(0);
// Kill ourself by the default signal handler.
InvokeDefaultSignalHandler(signal_number);
}
} // namespace
namespace glog_internal_namespace_ {
bool IsFailureSignalHandlerInstalled() {
#ifdef HAVE_SIGACTION
// TODO(andschwa): Return kFailureSignalHandlerInstalled?
struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask);
sigaction(SIGABRT, NULL, &sig_action);
if (sig_action.sa_sigaction == &FailureSignalHandler) {
return true;
}
#elif defined(GLOG_OS_WINDOWS)
return kFailureSignalHandlerInstalled;
#endif // HAVE_SIGACTION
return false;
}
} // namespace glog_internal_namespace_
void InstallFailureSignalHandler() {
#ifdef HAVE_SIGACTION
// Build the sigaction struct.
struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask);
sig_action.sa_flags |= SA_SIGINFO;
sig_action.sa_sigaction = &FailureSignalHandler;
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL));
}
kFailureSignalHandlerInstalled = true;
#elif defined(GLOG_OS_WINDOWS)
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler),
SIG_ERR);
}
kFailureSignalHandlerInstalled = true;
#endif // HAVE_SIGACTION
}
void InstallFailureWriter(void (*writer)(const char* data, size_t size)) {
#if defined(HAVE_SIGACTION) || defined(GLOG_OS_WINDOWS)
g_failure_writer = writer;
#endif // HAVE_SIGACTION
}
_END_GOOGLE_NAMESPACE_

View File

@ -1,113 +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.
//
// Author: Satoru Takabayashi
//
// This is a helper binary for testing signalhandler.cc. The actual test
// is done in signalhandler_unittest.sh.
#include "utilities.h"
#if defined(HAVE_PTHREAD)
# include <pthread.h>
#endif
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <glog/logging.h>
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE;
#endif
using namespace GOOGLE_NAMESPACE;
static void* DieInThread(void*) {
// We assume pthread_t is an integral number or a pointer, rather
// than a complex struct. In some environments, pthread_self()
// returns an uint64 but in some other environments pthread_self()
// returns a pointer.
fprintf(
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);
return NULL;
}
static void WriteToStdout(const char* data, size_t size) {
if (write(STDOUT_FILENO, data, size) < 0) {
// Ignore errors.
}
}
int main(int argc, char **argv) {
#if defined(HAVE_STACKTRACE) && defined(HAVE_SYMBOLIZE)
InitGoogleLogging(argv[0]);
#ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true);
#endif
InstallFailureSignalHandler();
const std::string command = argc > 1 ? argv[1] : "none";
if (command == "segv") {
// We'll check if this is outputted.
LOG(INFO) << "create the log file";
LOG(INFO) << "a message before segv";
// We assume 0xDEAD is not writable.
int *a = (int*)0xDEAD;
*a = 0;
} else if (command == "loop") {
fprintf(stderr, "looping\n");
while (true);
} else if (command == "die_in_thread") {
#if defined(HAVE_PTHREAD)
pthread_t thread;
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") {
InstallFailureWriter(WriteToStdout);
abort();
} else if (command == "installed") {
fprintf(stderr, "signal handler installed: %s\n",
IsFailureSignalHandlerInstalled() ? "true" : "false");
} else {
// Tell the shell script
puts("OK");
}
#endif
return 0;
}

View File

@ -1,131 +0,0 @@
#! /bin/sh
#
# 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.
#
# Author: Satoru Takabayashi
#
# Unit tests for signalhandler.cc.
die () {
echo $1
exit 1
}
BINDIR=".libs"
LIBGLOG="$BINDIR/libglog.so"
BINARY="$BINDIR/signalhandler_unittest"
LOG_INFO="./signalhandler_unittest.INFO"
# Remove temporary files.
rm -f signalhandler.out*
if test -e "$BINARY"; then
# We need shared object.
export LD_LIBRARY_PATH=$BINDIR
export DYLD_LIBRARY_PATH=$BINDIR
else
# For windows
BINARY="./signalhandler_unittest.exe"
if ! test -e "$BINARY"; then
echo "We coundn't find demangle_unittest binary."
exit 1
fi
fi
if [ x`$BINARY` != 'xOK' ]; then
echo "PASS (No stacktrace support. We don't run this test.)"
exit 0
fi
# The PC cannot be obtained in signal handlers on PowerPC correctly.
# We just skip the test for PowerPC.
if [ x`uname -p` = x"powerpc" ]; then
echo "PASS (We don't test the signal handler on PowerPC.)"
exit 0
fi
# Test for a case the program kills itself by SIGSEGV.
GOOGLE_LOG_DIR=. $BINARY segv 2> signalhandler.out1
for pattern in SIGSEGV 0xdead main "Aborted at [0-9]"; do
if ! grep --quiet "$pattern" signalhandler.out1; then
die "'$pattern' should appear in the output"
fi
done
if ! grep --quiet "a message before segv" $LOG_INFO; then
die "'a message before segv' should appear in the INFO log"
fi
rm -f $LOG_INFO
# Test for a case the program is killed by this shell script.
# $! = the process id of the last command run in the background.
# $$ = the process id of this shell.
$BINARY loop 2> signalhandler.out2 &
# Wait until "looping" is written in the file. This indicates the program
# is ready to accept signals.
while true; do
if grep --quiet looping signalhandler.out2; then
break
fi
done
kill -TERM $!
wait $!
from_pid=''
# Only linux has the process ID of the signal sender.
if [ x`uname` = "xLinux" ]; then
from_pid="from PID $$"
fi
for pattern in SIGTERM "by PID $!" "$from_pid" main "Aborted at [0-9]"; do
if ! grep --quiet "$pattern" signalhandler.out2; then
die "'$pattern' should appear in the output"
fi
done
# Test for a case the program dies in a non-main thread.
$BINARY die_in_thread 2> signalhandler.out3
EXPECTED_TID="`sed 's/ .*//; q' signalhandler.out3`"
for pattern in SIGFPE DieInThread "TID $EXPECTED_TID" "Aborted at [0-9]"; do
if ! grep --quiet "$pattern" signalhandler.out3; then
die "'$pattern' should appear in the output"
fi
done
# Test for a case the program installs a custom failure writer that writes
# stuff to stdout instead of stderr.
$BINARY dump_to_stdout 1> signalhandler.out4
for pattern in SIGABRT main "Aborted at [0-9]"; do
if ! grep --quiet "$pattern" signalhandler.out4; then
die "'$pattern' should appear in the output"
fi
done
echo PASS

View File

@ -1,61 +0,0 @@
// Copyright (c) 2000 - 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.
//
// Routines to extract the current stack trace. These functions are
// thread-safe.
#ifndef BASE_STACKTRACE_H_
#define BASE_STACKTRACE_H_
#include "config.h"
#include <glog/logging.h>
_START_GOOGLE_NAMESPACE_
// This is similar to the GetStackFrames routine, except that it returns
// the stack trace only, and not the stack frame sizes as well.
// Example:
// main() { foo(); }
// foo() { bar(); }
// bar() {
// void* result[10];
// int depth = GetStackFrames(result, 10, 1);
// }
//
// This produces:
// result[0] foo
// result[1] main
// .... ...
//
// "result" must not be NULL.
GLOG_EXPORT int GetStackTrace(void** result, int max_depth, int skip_count);
_END_GOOGLE_NAMESPACE_
#endif // BASE_STACKTRACE_H_

View File

@ -1,62 +0,0 @@
// Copyright (c) 2000 - 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.
//
// Portable implementation - just use glibc
//
// Note: The glibc implementation may cause a call to malloc.
// This can cause a deadlock in HeapProfiler.
#include <execinfo.h>
#include <string.h>
#include "stacktrace.h"
_START_GOOGLE_NAMESPACE_
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
static const int kStackLength = 64;
void * stack[kStackLength];
int size;
size = backtrace(stack, kStackLength);
skip_count++; // we want to skip the current frame as well
int result_count = size - skip_count;
if (result_count < 0) {
result_count = 0;
}
if (result_count > max_depth) {
result_count = max_depth;
}
for (int i = 0; i < result_count; i++) {
result[i] = stack[i + skip_count];
}
return result_count;
}
_END_GOOGLE_NAMESPACE_

View File

@ -1,93 +0,0 @@
// Copyright (c) 2005 - 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: Arun Sharma
//
// Produce stack trace using libunwind
#include "utilities.h"
extern "C" {
#define UNW_LOCAL_ONLY
#include <libunwind.h>
}
#include <glog/raw_logging.h>
#include "stacktrace.h"
_START_GOOGLE_NAMESPACE_
// Sometimes, we can try to get a stack trace from within a stack
// trace, because libunwind can call mmap (maybe indirectly via an
// internal mmap based memory allocator), and that mmap gets trapped
// and causes a stack-trace request. If were to try to honor that
// recursive request, we'd end up with infinite recursion or deadlock.
// Luckily, it's safe to ignore those subsequent traces. In such
// cases, we return 0 to indicate the situation.
// We can use the GCC __thread syntax here since libunwind is not supported on
// Windows.
static __thread bool g_tl_entered; // Initialized to false.
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
void *ip;
int n = 0;
unw_cursor_t cursor;
unw_context_t uc;
if (g_tl_entered) {
return 0;
}
g_tl_entered = true;
unw_getcontext(&uc);
RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, "unw_init_local failed");
skip_count++; // Do not include the "GetStackTrace" frame
while (n < max_depth) {
int ret =
unw_get_reg(&cursor, UNW_REG_IP, reinterpret_cast<unw_word_t *>(&ip));
if (ret < 0) {
break;
}
if (skip_count > 0) {
skip_count--;
} else {
result[n++] = ip;
}
ret = unw_step(&cursor);
if (ret <= 0) {
break;
}
}
g_tl_entered = false;
return n;
}
_END_GOOGLE_NAMESPACE_

View File

@ -1,130 +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
//
// Produce stack trace. I'm guessing (hoping!) the code is much like
// for x86. For apple machines, at least, it seems to be; see
// http://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html
// 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
#include <cstdio>
#include <stdint.h> // for uintptr_t
#include "stacktrace.h"
_START_GOOGLE_NAMESPACE_
// Given a pointer to a stack frame, locate and return the calling
// stackframe, or return NULL if no stackframe can be found. Perform sanity
// checks (the strictness of which is controlled by the boolean parameter
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
template<bool STRICT_UNWINDING>
static void **NextStackFrame(void **old_sp) {
void **new_sp = static_cast<void **>(*old_sp);
// Check that the transition from frame pointer old_sp to frame
// pointer new_sp isn't clearly bogus
if (STRICT_UNWINDING) {
// With the stack growing downwards, older stack frame must be
// at a greater address that the current one.
if (new_sp <= old_sp) return NULL;
// Assume stack frames larger than 100,000 bytes are bogus.
if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL;
} else {
// In the non-strict mode, allow discontiguous stack frames.
// (alternate-signal-stacks for example).
if (new_sp == old_sp) return NULL;
// And allow frames upto about 1MB.
if ((new_sp > old_sp)
&& ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return NULL;
}
if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL;
return new_sp;
}
// This ensures that GetStackTrace stes up the Link Register properly.
void StacktracePowerPCDummyFunction() __attribute__((noinline));
void StacktracePowerPCDummyFunction() { __asm__ volatile(""); }
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
void **sp;
// 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
// 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__.
#ifdef __APPLE__
__asm__ volatile ("mr %0,r1" : "=r" (sp));
#else
__asm__ volatile ("mr %0,1" : "=r" (sp));
#endif
// On PowerPC, the "Link Register" or "Link Record" (LR), is a stack
// entry that holds the return address of the subroutine call (what
// instruction we run after our function finishes). This is the
// same as the stack-pointer of our parent routine, which is what we
// want here. While the compiler will always(?) set up LR for
// subroutine calls, it may not for leaf functions (such as this one).
// This routine forces the compiler (at least gcc) to push it anyway.
StacktracePowerPCDummyFunction();
// The LR save area is used by the callee, so the top entry is bogus.
skip_count++;
int n = 0;
while (sp && n < max_depth) {
if (skip_count > 0) {
skip_count--;
} else {
// PowerPC has 3 main ABIs, which say where in the stack the
// Link Register is. For DARWIN and AIX (used by apple and
// linux ppc64), it's in sp[2]. For SYSV (used by linux ppc),
// it's in sp[1].
#if defined(_CALL_AIX) || defined(_CALL_DARWIN)
result[n++] = *(sp+2);
#elif defined(_CALL_SYSV)
result[n++] = *(sp+1);
#elif defined(__APPLE__) || ((defined(__linux) || defined(__linux__)) && defined(__PPC64__))
// This check is in case the compiler doesn't define _CALL_AIX/etc.
result[n++] = *(sp+2);
#elif defined(__linux) || defined(__OpenBSD__)
// This check is in case the compiler doesn't define _CALL_SYSV.
result[n++] = *(sp+1);
#else
#error Need to specify the PPC ABI for your archiecture.
#endif
}
// Use strict unwinding rules.
sp = NextStackFrame<true>(sp);
}
return n;
}
_END_GOOGLE_NAMESPACE_

View File

@ -1,239 +0,0 @@
// Copyright (c) 2004, 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 "utilities.h"
#include <cstdio>
#include <cstdlib>
#include "config.h"
#include "base/commandlineflags.h"
#include <glog/logging.h>
#include "stacktrace.h"
#ifdef HAVE_EXECINFO_H
# include <execinfo.h>
#endif
using namespace GOOGLE_NAMESPACE;
#ifdef HAVE_STACKTRACE
// Obtain a backtrace, verify that the expected callers are present in the
// backtrace, and maybe print the backtrace to stdout.
// The sequence of functions whose return addresses we expect to see in the
// backtrace.
const int BACKTRACE_STEPS = 6;
struct AddressRange {
const void *start, *end;
};
// Expected function [start,end] range.
AddressRange expected_range[BACKTRACE_STEPS];
#if __GNUC__
// Using GCC extension: address of a label can be taken with '&&label'.
// Start should be a label somewhere before recursive call, end somewhere
// after it.
#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
do { \
(prange)->start = &&start_label; \
(prange)->end = &&end_label; \
CHECK_LT((prange)->start, (prange)->end); \
} while (0)
// This macro expands into "unmovable" code (opaque to GCC), and that
// prevents GCC from moving a_label up or down in the code.
// 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
// the recursive call.
#define DECLARE_ADDRESS_LABEL(a_label) \
a_label: do { __asm__ __volatile__(""); } while (0)
// 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
// instruction (this actually happens with FDO).
// Adjust function range from __builtin_return_address.
#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
do { \
void *ra = __builtin_return_address(0); \
CHECK_LT((prange)->start, ra); \
if (ra > (prange)->end) { \
printf("Adjusting range from %p..%p to %p..%p\n", \
(prange)->start, (prange)->end, \
(prange)->start, ra); \
(prange)->end = ra; \
} \
} while (0)
#else
// Assume the Check* functions below are not longer than 256 bytes.
#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
do { \
(prange)->start = reinterpret_cast<const void *>(&fn); \
(prange)->end = reinterpret_cast<const char *>(&fn) + 256; \
} while (0)
#define DECLARE_ADDRESS_LABEL(a_label) do { } while (0)
#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) do { } while (0)
#endif // __GNUC__
//-----------------------------------------------------------------------//
static void CheckRetAddrIsInFunction(void *ret_addr, const AddressRange &range)
{
CHECK_GE(ret_addr, range.start);
CHECK_LE(ret_addr, range.end);
}
//-----------------------------------------------------------------------//
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-label-as-value"
#endif
void ATTRIBUTE_NOINLINE CheckStackTrace(int);
static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf(void) {
const int STACK_LEN = 10;
void *stack[STACK_LEN];
int size;
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);
INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
DECLARE_ADDRESS_LABEL(start);
size = GetStackTrace(stack, STACK_LEN, 0);
printf("Obtained %d stack frames.\n", size);
CHECK_GE(size, 1);
CHECK_LE(size, STACK_LEN);
if (1) {
#ifdef HAVE_EXECINFO_H
char **strings = backtrace_symbols(stack, size);
printf("Obtained %d stack frames.\n", size);
for (int i = 0; i < size; i++) {
printf("%s %p\n", strings[i], stack[i]);
}
union {
void (*p1)(int);
void* p2;
} p = {&CheckStackTrace};
printf("CheckStackTrace() addr: %p\n", p.p2);
free(strings);
#endif
}
for (int i = 0; i < BACKTRACE_STEPS; i++) {
printf("Backtrace %d: expected: %p..%p actual: %p ... ",
i, expected_range[i].start, expected_range[i].end, stack[i]);
fflush(stdout);
CheckRetAddrIsInFunction(stack[i], expected_range[i]);
printf("OK\n");
}
DECLARE_ADDRESS_LABEL(end);
}
//-----------------------------------------------------------------------//
/* Dummy functions to make the backtrace more interesting. */
static void ATTRIBUTE_NOINLINE CheckStackTrace4(int i) {
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[2]);
INIT_ADDRESS_RANGE(CheckStackTrace4, start, end, &expected_range[1]);
DECLARE_ADDRESS_LABEL(start);
for (int j = i; j >= 0; j--) {
CheckStackTraceLeaf();
}
DECLARE_ADDRESS_LABEL(end);
}
static void ATTRIBUTE_NOINLINE CheckStackTrace3(int i) {
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[3]);
INIT_ADDRESS_RANGE(CheckStackTrace3, start, end, &expected_range[2]);
DECLARE_ADDRESS_LABEL(start);
for (int j = i; j >= 0; j--) {
CheckStackTrace4(j);
}
DECLARE_ADDRESS_LABEL(end);
}
static void ATTRIBUTE_NOINLINE CheckStackTrace2(int i) {
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[4]);
INIT_ADDRESS_RANGE(CheckStackTrace2, start, end, &expected_range[3]);
DECLARE_ADDRESS_LABEL(start);
for (int j = i; j >= 0; j--) {
CheckStackTrace3(j);
}
DECLARE_ADDRESS_LABEL(end);
}
static void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[5]);
INIT_ADDRESS_RANGE(CheckStackTrace1, start, end, &expected_range[4]);
DECLARE_ADDRESS_LABEL(start);
for (int j = i; j >= 0; j--) {
CheckStackTrace2(j);
}
DECLARE_ADDRESS_LABEL(end);
}
#ifndef __GNUC__
// On non-GNU environment, we use the address of `CheckStackTrace` to
// guess the address range of this function. This guess is wrong for
// non-static function on Windows. This is probably because
// `&CheckStackTrace` returns the address of a trampoline like PLT,
// not the actual address of `CheckStackTrace`.
// See https://github.com/google/glog/issues/421 for the detail.
static
#endif
void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
DECLARE_ADDRESS_LABEL(start);
for (int j = i; j >= 0; j--) {
CheckStackTrace1(j);
}
DECLARE_ADDRESS_LABEL(end);
}
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
//-----------------------------------------------------------------------//
int main(int, char ** argv) {
FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]);
CheckStackTrace(0);
printf("PASS\n");
return 0;
}
#else
int main() {
printf("PASS (no stacktrace support)\n");
return 0;
}
#endif // HAVE_STACKTRACE

View File

@ -1,106 +0,0 @@
// Copyright (c) 2005 - 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: Arun Sharma
//
// Produce stack trace using libgcc
#include <cstdlib> // for NULL
#include <unwind.h> // ABI defined unwinder
#include "stacktrace.h"
_START_GOOGLE_NAMESPACE_
typedef struct {
void **result;
int max_depth;
int skip_count;
int count;
} trace_arg_t;
// Workaround for the malloc() in _Unwind_Backtrace() issue.
static _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context */*uc*/, void */*opq*/) {
return _URC_NO_REASON;
}
// This code is not considered ready to run until
// static initializers run so that we are guaranteed
// that any malloc-related initialization is done.
static bool ready_to_run = false;
class StackTraceInit {
public:
StackTraceInit() {
// Extra call to force initialization
_Unwind_Backtrace(nop_backtrace, NULL);
ready_to_run = true;
}
};
static StackTraceInit module_initializer; // Force initialization
static _Unwind_Reason_Code GetOneFrame(struct _Unwind_Context *uc, void *opq) {
trace_arg_t *targ = static_cast<trace_arg_t *>(opq);
if (targ->skip_count > 0) {
targ->skip_count--;
} else {
targ->result[targ->count++] = (void *) _Unwind_GetIP(uc);
}
if (targ->count == targ->max_depth) {
return _URC_END_OF_STACK;
}
return _URC_NO_REASON;
}
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
if (!ready_to_run) {
return 0;
}
trace_arg_t targ;
skip_count += 1; // Do not include the "GetStackTrace" frame
targ.result = result;
targ.max_depth = max_depth;
targ.skip_count = skip_count;
targ.count = 0;
_Unwind_Backtrace(GetOneFrame, &targ);
return targ.count;
}
_END_GOOGLE_NAMESPACE_

View File

@ -1,50 +0,0 @@
// Copyright (c) 2000 - 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: Andrew Schwartzmeyer
//
// Windows implementation - just use CaptureStackBackTrace
#include "config.h"
#include "port.h"
#include "stacktrace.h"
#include <dbghelp.h>
_START_GOOGLE_NAMESPACE_
int GetStackTrace(void** result, int max_depth, int skip_count) {
if (max_depth > 64) {
max_depth = 64;
}
skip_count++; // we want to skip the current frame as well
// This API is thread-safe (moreover it walks only the current thread).
return CaptureStackBackTrace(static_cast<DWORD>(skip_count), static_cast<DWORD>(max_depth), result, NULL);
}
_END_GOOGLE_NAMESPACE_

View File

@ -1,147 +0,0 @@
// Copyright (c) 2000 - 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.
//
// Produce stack trace
#include <stdint.h> // for uintptr_t
#include "utilities.h" // for OS_* macros
#if !defined(GLOG_OS_WINDOWS)
#include <unistd.h>
#include <sys/mman.h>
#endif
#include <cstdio> // for NULL
#include "stacktrace.h"
_START_GOOGLE_NAMESPACE_
// Given a pointer to a stack frame, locate and return the calling
// stackframe, or return NULL if no stackframe can be found. Perform sanity
// checks (the strictness of which is controlled by the boolean parameter
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
template<bool STRICT_UNWINDING>
static void **NextStackFrame(void **old_sp) {
void **new_sp = static_cast<void **>(*old_sp);
// Check that the transition from frame pointer old_sp to frame
// pointer new_sp isn't clearly bogus
if (STRICT_UNWINDING) {
// With the stack growing downwards, older stack frame must be
// at a greater address that the current one.
if (new_sp <= old_sp) return NULL;
// Assume stack frames larger than 100,000 bytes are bogus.
if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return NULL;
} else {
// In the non-strict mode, allow discontiguous stack frames.
// (alternate-signal-stacks for example).
if (new_sp == old_sp) return NULL;
// And allow frames upto about 1MB.
if ((new_sp > old_sp)
&& ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return NULL;
}
if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return NULL;
#ifdef __i386__
// On 64-bit machines, the stack pointer can be very close to
// 0xffffffff, so we explicitly check for a pointer into the
// last two pages in the address space
if ((uintptr_t)new_sp >= 0xffffe000) return NULL;
#endif
#if !defined(GLOG_OS_WINDOWS)
if (!STRICT_UNWINDING) {
// Lax sanity checks cause a crash in 32-bit tcmalloc/crash_reason_test
// on AMD-based machines with VDSO-enabled kernels.
// Make an extra sanity check to insure new_sp is readable.
// Note: NextStackFrame<false>() is only called while the program
// is already on its last leg, so it's ok to be slow here.
static int page_size = getpagesize();
void *new_sp_aligned = (void *)((uintptr_t)new_sp & ~(page_size - 1));
if (msync(new_sp_aligned, page_size, MS_ASYNC) == -1) {
return NULL;
}
}
#endif
return new_sp;
}
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
void **sp;
#ifdef __GNUC__
#if __GNUC__ * 100 + __GNUC_MINOR__ >= 402
#define USE_BUILTIN_FRAME_ADDRESS
#endif
#endif
#ifdef USE_BUILTIN_FRAME_ADDRESS
sp = reinterpret_cast<void**>(__builtin_frame_address(0));
#elif defined(__i386__)
// Stack frame format:
// sp[0] pointer to previous frame
// sp[1] caller address
// sp[2] first argument
// ...
sp = (void **)&result - 2;
#elif defined(__x86_64__)
// __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8
unsigned long rbp;
// Move the value of the register %rbp into the local variable rbp.
// We need 'volatile' to prevent this instruction from getting moved
// around during optimization to before function prologue is done.
// An alternative way to achieve this
// would be (before this __asm__ instruction) to call Noop() defined as
// static void Noop() __attribute__ ((noinline)); // prevent inlining
// static void Noop() { asm(""); } // prevent optimizing-away
__asm__ volatile ("mov %%rbp, %0" : "=r" (rbp));
// Arguments are passed in registers on x86-64, so we can't just
// offset from &result
sp = (void **) rbp;
#endif
int n = 0;
while (sp && n < max_depth) {
if (*(sp+1) == (void *)0) {
// In 64-bit code, we often see a frame that
// points to itself and has a return address of 0.
break;
}
if (skip_count > 0) {
skip_count--;
} else {
result[n++] = *(sp+1);
}
// Use strict unwinding rules.
sp = NextStackFrame<true>(sp);
}
return n;
}
_END_GOOGLE_NAMESPACE_

View File

@ -1,207 +0,0 @@
// Copyright (c) 2003, 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 "config.h"
#ifdef HAVE_USING_OPERATOR
#include <functional>
#include <iostream>
#include <map>
#include <ostream>
#include <string>
#include <vector>
#ifdef __GNUC__
// C++0x isn't enabled by default in GCC and libc++ does not have
// non-standard ext/* and tr1/unordered_*.
# if defined(_LIBCPP_VERSION)
# ifndef GLOG_STL_LOGGING_FOR_UNORDERED
# define GLOG_STL_LOGGING_FOR_UNORDERED
# endif
# else
# ifndef GLOG_STL_LOGGING_FOR_EXT_HASH
# define GLOG_STL_LOGGING_FOR_EXT_HASH
# endif
# ifndef GLOG_STL_LOGGING_FOR_EXT_SLIST
# define GLOG_STL_LOGGING_FOR_EXT_SLIST
# endif
# ifndef GLOG_STL_LOGGING_FOR_TR1_UNORDERED
# define GLOG_STL_LOGGING_FOR_TR1_UNORDERED
# endif
# endif
#endif
#include <glog/logging.h>
#include <glog/stl_logging.h>
#include "googletest.h"
using namespace std;
#ifdef GLOG_STL_LOGGING_FOR_EXT_HASH
using namespace __gnu_cxx;
#endif
struct user_hash {
size_t operator()(int x) const { return static_cast<size_t>(x); }
};
static void TestSTLLogging() {
{
// Test a sequence.
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
ostringstream ss;
ss << v;
EXPECT_EQ(ss.str(), "10 20 30");
vector<int> copied_v(v);
CHECK_EQ(v, copied_v); // This must compile.
}
{
// Test a sorted pair associative container.
map< int, string > m;
m[20] = "twenty";
m[10] = "ten";
m[30] = "thirty";
ostringstream ss;
ss << m;
EXPECT_EQ(ss.str(), "(10, ten) (20, twenty) (30, thirty)");
map< int, string > copied_m(m);
CHECK_EQ(m, copied_m); // This must compile.
}
#ifdef GLOG_STL_LOGGING_FOR_EXT_HASH
{
// Test a hashed simple associative container.
hash_set<int> hs;
hs.insert(10);
hs.insert(20);
hs.insert(30);
ostringstream ss;
ss << hs;
EXPECT_EQ(ss.str().size(), 8);
EXPECT_TRUE(ss.str().find("10") != string::npos);
EXPECT_TRUE(ss.str().find("20") != string::npos);
EXPECT_TRUE(ss.str().find("30") != string::npos);
hash_set<int> copied_hs(hs);
CHECK_EQ(hs, copied_hs); // This must compile.
}
#endif
#ifdef GLOG_STL_LOGGING_FOR_EXT_HASH
{
// Test a hashed pair associative container.
hash_map<int, string> hm;
hm[10] = "ten";
hm[20] = "twenty";
hm[30] = "thirty";
ostringstream ss;
ss << hm;
EXPECT_EQ(ss.str().size(), 35);
EXPECT_TRUE(ss.str().find("(10, ten)") != string::npos);
EXPECT_TRUE(ss.str().find("(20, twenty)") != string::npos);
EXPECT_TRUE(ss.str().find("(30, thirty)") != string::npos);
hash_map<int, string> copied_hm(hm);
CHECK_EQ(hm, copied_hm); // this must compile
}
#endif
{
// Test a long sequence.
vector<int> v;
string expected;
for (int i = 0; i < 100; i++) {
v.push_back(i);
if (i > 0) expected += ' ';
const size_t buf_size = 256;
char buf[buf_size];
snprintf(buf, buf_size, "%d", i);
expected += buf;
}
v.push_back(100);
expected += " ...";
ostringstream ss;
ss << v;
CHECK_EQ(ss.str(), expected.c_str());
}
{
// Test a sorted pair associative container.
// Use a non-default comparison functor.
map< int, string, greater<int> > m;
m[20] = "twenty";
m[10] = "ten";
m[30] = "thirty";
ostringstream ss;
ss << m;
EXPECT_EQ(ss.str(), "(30, thirty) (20, twenty) (10, ten)");
map< int, string, greater<int> > copied_m(m);
CHECK_EQ(m, copied_m); // This must compile.
}
#ifdef GLOG_STL_LOGGING_FOR_EXT_HASH
{
// Test a hashed simple associative container.
// Use a user defined hash function.
hash_set<int, user_hash> hs;
hs.insert(10);
hs.insert(20);
hs.insert(30);
ostringstream ss;
ss << hs;
EXPECT_EQ(ss.str().size(), 8);
EXPECT_TRUE(ss.str().find("10") != string::npos);
EXPECT_TRUE(ss.str().find("20") != string::npos);
EXPECT_TRUE(ss.str().find("30") != string::npos);
hash_set<int, user_hash> copied_hs(hs);
CHECK_EQ(hs, copied_hs); // This must compile.
}
#endif
}
int main(int, char**) {
TestSTLLogging();
std::cout << "PASS\n";
return 0;
}
#else
#include <iostream>
int main(int, char**) {
std::cout << "We don't support stl_logging for this compiler.\n"
<< "(we need compiler support of 'using ::operator<<' "
<< "for this feature.)\n";
return 0;
}
#endif // HAVE_USING_OPERATOR

View File

@ -1,955 +0,0 @@
// Copyright (c) 2006, 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: Satoru Takabayashi
// Stack-footprint reduction work done by Raksit Ashok
//
// Implementation note:
//
// We don't use heaps but only use stacks. We want to reduce the
// stack consumption so that the symbolizer can run on small stacks.
//
// Here are some numbers collected with GCC 4.1.0 on x86:
// - sizeof(Elf32_Sym) = 16
// - sizeof(Elf32_Shdr) = 40
// - sizeof(Elf64_Sym) = 24
// - sizeof(Elf64_Shdr) = 64
//
// This implementation is intended to be async-signal-safe but uses
// some functions which are not guaranteed to be so, such as memchr()
// and memmove(). We assume they are async-signal-safe.
//
// Additional header can be specified by the GLOG_BUILD_CONFIG_INCLUDE
// macro to add platform specific defines (e.g. GLOG_OS_OPENBSD).
#ifdef GLOG_BUILD_CONFIG_INCLUDE
#include GLOG_BUILD_CONFIG_INCLUDE
#endif // GLOG_BUILD_CONFIG_INCLUDE
#include "utilities.h"
#if defined(HAVE_SYMBOLIZE)
#include <cstring>
#include <algorithm>
#include <limits>
#include "symbolize.h"
#include "demangle.h"
_START_GOOGLE_NAMESPACE_
// We don't use assert() since it's not guaranteed to be
// async-signal-safe. Instead we define a minimal assertion
// macro. So far, we don't need pretty printing for __FILE__, etc.
// A wrapper for abort() to make it callable in ? :.
static int AssertFail() {
abort();
return 0; // Should not reach.
}
#define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
static SymbolizeCallback g_symbolize_callback = NULL;
void InstallSymbolizeCallback(SymbolizeCallback callback) {
g_symbolize_callback = callback;
}
static SymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback =
NULL;
void InstallSymbolizeOpenObjectFileCallback(
SymbolizeOpenObjectFileCallback callback) {
g_symbolize_open_object_file_callback = callback;
}
// This function wraps the Demangle function to provide an interface
// where the input symbol is demangled in-place.
// To keep stack consumption low, we would like this function to not
// get inlined.
static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size) {
char demangled[256]; // Big enough for sane demangled symbols.
if (Demangle(out, demangled, sizeof(demangled))) {
// Demangling succeeded. Copy to out if the space allows.
size_t len = strlen(demangled);
if (len + 1 <= static_cast<size_t>(out_size)) { // +1 for '\0'.
SAFE_ASSERT(len < sizeof(demangled));
memmove(out, demangled, len + 1);
}
}
}
_END_GOOGLE_NAMESPACE_
#if defined(__ELF__)
#if defined(HAVE_DLFCN_H)
#include <dlfcn.h>
#endif
#if defined(GLOG_OS_OPENBSD)
#include <sys/exec_elf.h>
#else
#include <elf.h>
#endif
#include <cerrno>
#include <climits>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "symbolize.h"
#include "config.h"
#include <glog/raw_logging.h>
// Re-runs fn until it doesn't cause EINTR.
#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
_START_GOOGLE_NAMESPACE_
// Read up to "count" bytes from "offset" in the file pointed by file
// descriptor "fd" into the buffer starting at "buf" while handling short reads
// and EINTR. On success, return the number of bytes read. Otherwise, return
// -1.
static ssize_t ReadFromOffset(const int fd, void *buf, const size_t count,
const size_t offset) {
SAFE_ASSERT(fd >= 0);
SAFE_ASSERT(count <= static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
char *buf0 = reinterpret_cast<char *>(buf);
size_t num_bytes = 0;
while (num_bytes < count) {
ssize_t len;
NO_INTR(len = pread(fd, buf0 + num_bytes, count - num_bytes,
static_cast<off_t>(offset + num_bytes)));
if (len < 0) { // There was an error other than EINTR.
return -1;
}
if (len == 0) { // Reached EOF.
break;
}
num_bytes += static_cast<size_t>(len);
}
SAFE_ASSERT(num_bytes <= count);
return static_cast<ssize_t>(num_bytes);
}
// Try reading exactly "count" bytes from "offset" bytes in a file
// pointed by "fd" into the buffer starting at "buf" while handling
// short reads and EINTR. On success, return true. Otherwise, return
// false.
static bool ReadFromOffsetExact(const int fd, void *buf,
const size_t count, const size_t offset) {
ssize_t len = ReadFromOffset(fd, buf, count, offset);
return static_cast<size_t>(len) == count;
}
// Returns elf_header.e_type if the file pointed by fd is an ELF binary.
static int FileGetElfType(const int fd) {
ElfW(Ehdr) elf_header;
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
return -1;
}
if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {
return -1;
}
return elf_header.e_type;
}
// Read the section headers in the given ELF binary, and if a section
// of the specified type is found, set the output to this section header
// and return true. Otherwise, return false.
// To keep stack consumption low, we would like this function to not get
// inlined.
static ATTRIBUTE_NOINLINE bool
GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const size_t sh_offset,
ElfW(Word) type, ElfW(Shdr) *out) {
// Read at most 16 section headers at a time to save read calls.
ElfW(Shdr) buf[16];
for (size_t i = 0; i < sh_num;) {
const size_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);
const size_t num_bytes_to_read =
(sizeof(buf) > num_bytes_left) ? num_bytes_left : sizeof(buf);
const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read,
sh_offset + i * sizeof(buf[0]));
if (len == -1) {
return false;
}
SAFE_ASSERT(static_cast<size_t>(len) % sizeof(buf[0]) == 0);
const size_t num_headers_in_buf = static_cast<size_t>(len) / sizeof(buf[0]);
SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
for (size_t j = 0; j < num_headers_in_buf; ++j) {
if (buf[j].sh_type == type) {
*out = buf[j];
return true;
}
}
i += num_headers_in_buf;
}
return false;
}
// There is no particular reason to limit section name to 63 characters,
// but there has (as yet) been no need for anything longer either.
const int kMaxSectionNameLen = 64;
// name_len should include terminating '\0'.
bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
ElfW(Shdr) *out) {
ElfW(Ehdr) elf_header;
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
return false;
}
ElfW(Shdr) shstrtab;
size_t shstrtab_offset =
(elf_header.e_shoff + static_cast<size_t>(elf_header.e_shentsize) *
static_cast<size_t>(elf_header.e_shstrndx));
if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
return false;
}
for (size_t i = 0; i < elf_header.e_shnum; ++i) {
size_t section_header_offset = (elf_header.e_shoff +
elf_header.e_shentsize * i);
if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
return false;
}
char header_name[kMaxSectionNameLen];
if (sizeof(header_name) < name_len) {
RAW_LOG(WARNING, "Section name '%s' is too long (%" PRIuS "); "
"section will not be found (even if present).", name, name_len);
// No point in even trying.
return false;
}
size_t name_offset = shstrtab.sh_offset + out->sh_name;
ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset);
if (n_read == -1) {
return false;
} else if (static_cast<size_t>(n_read) != name_len) {
// Short read -- name could be at end of file.
continue;
}
if (memcmp(header_name, name, name_len) == 0) {
return true;
}
}
return false;
}
// Read a symbol table and look for the symbol containing the
// pc. Iterate over symbols in a symbol table and look for the symbol
// containing "pc". On success, return true and write the symbol name
// to out. Otherwise, return false.
// To keep stack consumption low, we would like this function to not get
// inlined.
static ATTRIBUTE_NOINLINE bool
FindSymbol(uint64_t pc, const int fd, char *out, size_t out_size,
uint64_t symbol_offset, const ElfW(Shdr) *strtab,
const ElfW(Shdr) *symtab) {
if (symtab == NULL) {
return false;
}
const size_t num_symbols = symtab->sh_size / symtab->sh_entsize;
for (unsigned i = 0; i < num_symbols;) {
size_t offset = symtab->sh_offset + i * symtab->sh_entsize;
// If we are reading Elf64_Sym's, we want to limit this array to
// 32 elements (to keep stack consumption low), otherwise we can
// have a 64 element Elf32_Sym array.
#if defined(__WORDSIZE) && __WORDSIZE == 64
const size_t NUM_SYMBOLS = 32U;
#else
const size_t NUM_SYMBOLS = 64U;
#endif
// Read at most NUM_SYMBOLS symbols at once to save read() calls.
ElfW(Sym) buf[NUM_SYMBOLS];
size_t num_symbols_to_read = std::min(NUM_SYMBOLS, num_symbols - i);
const ssize_t len =
ReadFromOffset(fd, &buf, sizeof(buf[0]) * num_symbols_to_read, offset);
SAFE_ASSERT(static_cast<size_t>(len) % sizeof(buf[0]) == 0);
const size_t num_symbols_in_buf = static_cast<size_t>(len) / sizeof(buf[0]);
SAFE_ASSERT(num_symbols_in_buf <= num_symbols_to_read);
for (unsigned j = 0; j < num_symbols_in_buf; ++j) {
const ElfW(Sym)& symbol = buf[j];
uint64_t start_address = symbol.st_value;
start_address += symbol_offset;
uint64_t end_address = start_address + symbol.st_size;
if (symbol.st_value != 0 && // Skip null value symbols.
symbol.st_shndx != 0 && // Skip undefined symbols.
start_address <= pc && pc < end_address) {
ssize_t len1 = ReadFromOffset(fd, out, out_size,
strtab->sh_offset + symbol.st_name);
if (len1 <= 0 || memchr(out, '\0', out_size) == NULL) {
memset(out, 0, out_size);
return false;
}
return true; // Obtained the symbol name.
}
}
i += num_symbols_in_buf;
}
return false;
}
// Get the symbol name of "pc" from the file pointed by "fd". Process
// both regular and dynamic symbol tables if necessary. On success,
// write the symbol name to "out" and return true. Otherwise, return
// false.
static bool GetSymbolFromObjectFile(const int fd,
uint64_t pc,
char* out,
size_t out_size,
uint64_t base_address) {
// Read the ELF header.
ElfW(Ehdr) elf_header;
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
return false;
}
ElfW(Shdr) symtab, strtab;
// Consult a regular symbol table first.
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
SHT_SYMTAB, &symtab)) {
if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
symtab.sh_link * sizeof(symtab))) {
return false;
}
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
return true; // Found the symbol in a regular symbol table.
}
}
// If the symbol is not found, then consult a dynamic symbol table.
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
SHT_DYNSYM, &symtab)) {
if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
symtab.sh_link * sizeof(symtab))) {
return false;
}
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
return true; // Found the symbol in a dynamic symbol table.
}
}
return false;
}
namespace {
// Thin wrapper around a file descriptor so that the file descriptor
// gets closed for sure.
struct FileDescriptor {
const int fd_;
explicit FileDescriptor(int fd) : fd_(fd) {}
~FileDescriptor() {
if (fd_ >= 0) {
close(fd_);
}
}
int get() { return fd_; }
private:
FileDescriptor(const FileDescriptor &);
void operator=(const FileDescriptor&);
};
// Helper class for reading lines from file.
//
// Note: we don't use ProcMapsIterator since the object is big (it has
// a 5k array member) and uses async-unsafe functions such as sscanf()
// and snprintf().
class LineReader {
public:
explicit LineReader(int fd, char *buf, size_t buf_len, size_t offset)
: fd_(fd),
buf_(buf),
buf_len_(buf_len),
offset_(offset),
bol_(buf),
eol_(buf),
eod_(buf) {}
// Read '\n'-terminated line from file. On success, modify "bol"
// and "eol", then return true. Otherwise, return false.
//
// Note: if the last line doesn't end with '\n', the line will be
// dropped. It's an intentional behavior to make the code simple.
bool ReadLine(const char **bol, const char **eol) {
if (BufferIsEmpty()) { // First time.
const ssize_t num_bytes = ReadFromOffset(fd_, buf_, buf_len_, offset_);
if (num_bytes <= 0) { // EOF or error.
return false;
}
offset_ += static_cast<size_t>(num_bytes);
eod_ = buf_ + num_bytes;
bol_ = buf_;
} else {
bol_ = eol_ + 1; // Advance to the next line in the buffer.
SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_".
if (!HasCompleteLine()) {
const size_t incomplete_line_length = static_cast<size_t>(eod_ - bol_);
// Move the trailing incomplete line to the beginning.
memmove(buf_, bol_, incomplete_line_length);
// Read text from file and append it.
char * const append_pos = buf_ + incomplete_line_length;
const size_t capacity_left = buf_len_ - incomplete_line_length;
const ssize_t num_bytes =
ReadFromOffset(fd_, append_pos, capacity_left, offset_);
if (num_bytes <= 0) { // EOF or error.
return false;
}
offset_ += static_cast<size_t>(num_bytes);
eod_ = append_pos + num_bytes;
bol_ = buf_;
}
}
eol_ = FindLineFeed();
if (eol_ == NULL) { // '\n' not found. Malformed line.
return false;
}
*eol_ = '\0'; // Replace '\n' with '\0'.
*bol = bol_;
*eol = eol_;
return true;
}
// Beginning of line.
const char *bol() {
return bol_;
}
// End of line.
const char *eol() {
return eol_;
}
private:
LineReader(const LineReader &);
void operator=(const LineReader&);
char *FindLineFeed() {
return reinterpret_cast<char *>(memchr(bol_, '\n', static_cast<size_t>(eod_ - bol_)));
}
bool BufferIsEmpty() {
return buf_ == eod_;
}
bool HasCompleteLine() {
return !BufferIsEmpty() && FindLineFeed() != NULL;
}
const int fd_;
char * const buf_;
const size_t buf_len_;
size_t offset_;
char *bol_;
char *eol_;
const char *eod_; // End of data in "buf_".
};
} // namespace
// Place the hex number read from "start" into "*hex". The pointer to
// the first non-hex character or "end" is returned.
static char *GetHex(const char *start, const char *end, uint64_t *hex) {
*hex = 0;
const char *p;
for (p = start; p < end; ++p) {
int ch = *p;
if ((ch >= '0' && ch <= '9') ||
(ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
*hex = (*hex << 4U) | (ch < 'A' ? static_cast<uint64_t>(ch - '0') : (ch & 0xF) + 9U);
} else { // Encountered the first non-hex character.
break;
}
}
SAFE_ASSERT(p <= end);
return const_cast<char *>(p);
}
// Searches for the object file (from /proc/self/maps) that contains
// the specified pc. If found, sets |start_address| to the start address
// of where this object file is mapped in memory, sets the module base
// address into |base_address|, copies the object file name into
// |out_file_name|, and attempts to open the object file. If the object
// file is opened successfully, returns the file descriptor. Otherwise,
// returns -1. |out_file_name_size| is the size of the file name buffer
// (including the null-terminator).
static ATTRIBUTE_NOINLINE int
OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
uint64_t &start_address,
uint64_t &base_address,
char *out_file_name,
size_t out_file_name_size) {
int object_fd;
int maps_fd;
NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
FileDescriptor wrapped_maps_fd(maps_fd);
if (wrapped_maps_fd.get() < 0) {
return -1;
}
int mem_fd;
NO_INTR(mem_fd = open("/proc/self/mem", O_RDONLY));
FileDescriptor wrapped_mem_fd(mem_fd);
if (wrapped_mem_fd.get() < 0) {
return -1;
}
// Iterate over maps and look for the map containing the pc. Then
// look into the symbol tables inside.
char buf[1024]; // Big enough for line of sane /proc/self/maps
unsigned num_maps = 0;
LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf), 0);
while (true) {
num_maps++;
const char *cursor;
const char *eol;
if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
return -1;
}
// Start parsing line in /proc/self/maps. Here is an example:
//
// 08048000-0804c000 r-xp 00000000 08:01 2142121 /bin/cat
//
// We want start address (08048000), end address (0804c000), flags
// (r-xp) and file name (/bin/cat).
// Read start address.
cursor = GetHex(cursor, eol, &start_address);
if (cursor == eol || *cursor != '-') {
return -1; // Malformed line.
}
++cursor; // Skip '-'.
// Read end address.
uint64_t end_address;
cursor = GetHex(cursor, eol, &end_address);
if (cursor == eol || *cursor != ' ') {
return -1; // Malformed line.
}
++cursor; // Skip ' '.
// Read flags. Skip flags until we encounter a space or eol.
const char * const flags_start = cursor;
while (cursor < eol && *cursor != ' ') {
++cursor;
}
// We expect at least four letters for flags (ex. "r-xp").
if (cursor == eol || cursor < flags_start + 4) {
return -1; // Malformed line.
}
// Determine the base address by reading ELF headers in process memory.
ElfW(Ehdr) ehdr;
// Skip non-readable maps.
if (flags_start[0] == 'r' &&
ReadFromOffsetExact(mem_fd, &ehdr, sizeof(ElfW(Ehdr)), start_address) &&
memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) {
switch (ehdr.e_type) {
case ET_EXEC:
base_address = 0;
break;
case ET_DYN:
// Find the segment containing file offset 0. This will correspond
// to the ELF header that we just read. Normally this will have
// virtual address 0, but this is not guaranteed. We must subtract
// the virtual address from the address where the ELF header was
// mapped to get the base address.
//
// If we fail to find a segment for file offset 0, use the address
// of the ELF header as the base address.
base_address = start_address;
for (unsigned i = 0; i != ehdr.e_phnum; ++i) {
ElfW(Phdr) phdr;
if (ReadFromOffsetExact(
mem_fd, &phdr, sizeof(phdr),
start_address + ehdr.e_phoff + i * sizeof(phdr)) &&
phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
base_address = start_address - phdr.p_vaddr;
break;
}
}
break;
default:
// ET_REL or ET_CORE. These aren't directly executable, so they don't
// affect the base address.
break;
}
}
// Check start and end addresses.
if (!(start_address <= pc && pc < end_address)) {
continue; // We skip this map. PC isn't in this map.
}
// Check flags. We are only interested in "r*x" maps.
if (flags_start[0] != 'r' || flags_start[2] != 'x') {
continue; // We skip this map.
}
++cursor; // Skip ' '.
// Read file offset.
uint64_t file_offset;
cursor = GetHex(cursor, eol, &file_offset);
if (cursor == eol || *cursor != ' ') {
return -1; // Malformed line.
}
++cursor; // Skip ' '.
// Skip to file name. "cursor" now points to dev. We need to
// skip at least two spaces for dev and inode.
int num_spaces = 0;
while (cursor < eol) {
if (*cursor == ' ') {
++num_spaces;
} else if (num_spaces >= 2) {
// The first non-space character after skipping two spaces
// is the beginning of the file name.
break;
}
++cursor;
}
if (cursor == eol) {
return -1; // Malformed line.
}
// Finally, "cursor" now points to file name of our interest.
NO_INTR(object_fd = open(cursor, O_RDONLY));
if (object_fd < 0) {
// Failed to open object file. Copy the object file name to
// |out_file_name|.
strncpy(out_file_name, cursor, out_file_name_size);
// Making sure |out_file_name| is always null-terminated.
out_file_name[out_file_name_size - 1] = '\0';
return -1;
}
return object_fd;
}
}
// POSIX doesn't define any async-signal safe function for converting
// an integer to ASCII. We'll have to define our own version.
// itoa_r() converts an (unsigned) integer to ASCII. It returns "buf", if the
// conversion was successful or NULL otherwise. It never writes more than "sz"
// bytes. Output will be truncated as needed, and a NUL character is always
// appended.
// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
static char *itoa_r(uintptr_t i, char *buf, size_t sz, unsigned base, size_t padding) {
// Make sure we can write at least one NUL byte.
size_t n = 1;
if (n > sz) {
return NULL;
}
if (base < 2 || base > 16) {
buf[0] = '\000';
return NULL;
}
char *start = buf;
// Loop until we have converted the entire number. Output at least one
// character (i.e. '0').
char *ptr = start;
do {
// Make sure there is still enough space left in our output buffer.
if (++n > sz) {
buf[0] = '\000';
return NULL;
}
// Output the next digit.
*ptr++ = "0123456789abcdef"[i % base];
i /= base;
if (padding > 0) {
padding--;
}
} while (i > 0 || padding > 0);
// Terminate the output with a NUL character.
*ptr = '\000';
// Conversion to ASCII actually resulted in the digits being in reverse
// order. We can't easily generate them in forward order, as we can't tell
// the number of characters needed until we are done converting.
// So, now, we reverse the string (except for the possible "-" sign).
while (--ptr > start) {
char ch = *ptr;
*ptr = *start;
*start++ = ch;
}
return buf;
}
// Safely appends string |source| to string |dest|. Never writes past the
// buffer size |dest_size| and guarantees that |dest| is null-terminated.
static void SafeAppendString(const char* source, char* dest, size_t dest_size) {
size_t dest_string_length = strlen(dest);
SAFE_ASSERT(dest_string_length < dest_size);
dest += dest_string_length;
dest_size -= dest_string_length;
strncpy(dest, source, dest_size);
// Making sure |dest| is always null-terminated.
dest[dest_size - 1] = '\0';
}
// Converts a 64-bit value into a hex string, and safely appends it to |dest|.
// Never writes past the buffer size |dest_size| and guarantees that |dest| is
// null-terminated.
static void SafeAppendHexNumber(uint64_t value, char* dest, size_t dest_size) {
// 64-bit numbers in hex can have up to 16 digits.
char buf[17] = {'\0'};
SafeAppendString(itoa_r(value, buf, sizeof(buf), 16, 0), dest, dest_size);
}
// The implementation of our symbolization routine. If it
// successfully finds the symbol containing "pc" and obtains the
// symbol name, returns true and write the symbol name to "out".
// Otherwise, returns false. If Callback function is installed via
// InstallSymbolizeCallback(), the function is also called in this function,
// and "out" is used as its output.
// To keep stack consumption low, we would like this function to not
// get inlined.
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
size_t out_size) {
uint64_t pc0 = reinterpret_cast<uintptr_t>(pc);
uint64_t start_address = 0;
uint64_t base_address = 0;
int object_fd = -1;
if (out_size < 1) {
return false;
}
out[0] = '\0';
SafeAppendString("(", out, out_size);
if (g_symbolize_open_object_file_callback) {
object_fd = g_symbolize_open_object_file_callback(pc0, start_address,
base_address, out + 1,
out_size - 1);
} else {
object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0, start_address,
base_address,
out + 1,
out_size - 1);
}
FileDescriptor wrapped_object_fd(object_fd);
#if defined(PRINT_UNSYMBOLIZED_STACK_TRACES)
{
#else
// Check whether a file name was returned.
if (object_fd < 0) {
#endif
if (out[1]) {
// The object file containing PC was determined successfully however the
// object file was not opened successfully. This is still considered
// success because the object file name and offset are known and tools
// like asan_symbolize.py can be used for the symbolization.
out[out_size - 1] = '\0'; // Making sure |out| is always null-terminated.
SafeAppendString("+0x", out, out_size);
SafeAppendHexNumber(pc0 - base_address, out, out_size);
SafeAppendString(")", out, out_size);
return true;
}
// Failed to determine the object file containing PC. Bail out.
return false;
}
int elf_type = FileGetElfType(wrapped_object_fd.get());
if (elf_type == -1) {
return false;
}
if (g_symbolize_callback) {
// Run the call back if it's installed.
// Note: relocation (and much of the rest of this code) will be
// wrong for prelinked shared libraries and PIE executables.
uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0;
int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
pc, out, out_size,
relocation);
if (num_bytes_written > 0) {
out += static_cast<size_t>(num_bytes_written);
out_size -= static_cast<size_t>(num_bytes_written);
}
}
if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
out, out_size, base_address)) {
if (out[1] && !g_symbolize_callback) {
// The object file containing PC was opened successfully however the
// symbol was not found. The object may have been stripped. This is still
// considered success because the object file name and offset are known
// and tools like asan_symbolize.py can be used for the symbolization.
out[out_size - 1] = '\0'; // Making sure |out| is always null-terminated.
SafeAppendString("+0x", out, out_size);
SafeAppendHexNumber(pc0 - base_address, out, out_size);
SafeAppendString(")", out, out_size);
return true;
}
return false;
}
// Symbolization succeeded. Now we try to demangle the symbol.
DemangleInplace(out, out_size);
return true;
}
_END_GOOGLE_NAMESPACE_
#elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)
#include <dlfcn.h>
#include <cstring>
_START_GOOGLE_NAMESPACE_
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
size_t out_size) {
Dl_info info;
if (dladdr(pc, &info)) {
if (info.dli_sname) {
if (strlen(info.dli_sname) < out_size) {
strcpy(out, info.dli_sname);
// Symbolization succeeded. Now we try to demangle the symbol.
DemangleInplace(out, out_size);
return true;
}
}
}
return false;
}
_END_GOOGLE_NAMESPACE_
#elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
#include <windows.h>
#include <dbghelp.h>
#ifdef _MSC_VER
#pragma comment(lib, "dbghelp")
#endif
_START_GOOGLE_NAMESPACE_
class SymInitializer {
public:
HANDLE process;
bool ready;
SymInitializer() : process(NULL), ready(false) {
// Initialize the symbol handler.
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680344(v=vs.85).aspx
process = GetCurrentProcess();
// Defer symbol loading.
// We do not request undecorated symbols with SYMOPT_UNDNAME
// because the mangling library calls UnDecorateSymbolName.
SymSetOptions(SYMOPT_DEFERRED_LOADS);
if (SymInitialize(process, NULL, true)) {
ready = true;
}
}
~SymInitializer() {
SymCleanup(process);
// We do not need to close `HANDLE process` because it's a "pseudo handle."
}
private:
SymInitializer(const SymInitializer&);
SymInitializer& operator=(const SymInitializer&);
};
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
int out_size) {
const static SymInitializer symInitializer;
if (!symInitializer.ready) {
return false;
}
// Resolve symbol information from address.
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO *>(buf);
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
// We use the ANSI version to ensure the string type is always `char *`.
// This could break if a symbol has Unicode in it.
BOOL ret = SymFromAddr(symInitializer.process,
reinterpret_cast<DWORD64>(pc), 0, symbol);
if (ret == 1 && static_cast<int>(symbol->NameLen) < out_size) {
// `NameLen` does not include the null terminating character.
strncpy(out, symbol->Name, static_cast<size_t>(symbol->NameLen) + 1);
out[static_cast<size_t>(symbol->NameLen)] = '\0';
// Symbolization succeeded. Now we try to demangle the symbol.
DemangleInplace(out, out_size);
return true;
}
return false;
}
_END_GOOGLE_NAMESPACE_
#else
# error BUG: HAVE_SYMBOLIZE was wrongly set
#endif
_START_GOOGLE_NAMESPACE_
bool Symbolize(void *pc, char *out, size_t out_size) {
return SymbolizeAndDemangle(pc, out, out_size);
}
_END_GOOGLE_NAMESPACE_
#else /* HAVE_SYMBOLIZE */
#include <cassert>
#include "config.h"
_START_GOOGLE_NAMESPACE_
// TODO: Support other environments.
bool Symbolize(void* /*pc*/, char* /*out*/, size_t /*out_size*/) {
assert(0);
return false;
}
_END_GOOGLE_NAMESPACE_
#endif

View File

@ -1,159 +0,0 @@
// Copyright (c) 2006, 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: Satoru Takabayashi
//
// This library provides Symbolize() function that symbolizes program
// counters to their corresponding symbol names on linux platforms.
// This library has a minimal implementation of an ELF symbol table
// reader (i.e. it doesn't depend on libelf, etc.).
//
// The algorithm used in Symbolize() is as follows.
//
// 1. Go through a list of maps in /proc/self/maps and find the map
// containing the program counter.
//
// 2. Open the mapped file and find a regular symbol table inside.
// Iterate over symbols in the symbol table and look for the symbol
// containing the program counter. If such a symbol is found,
// obtain the symbol name, and demangle the symbol if possible.
// If the symbol isn't found in the regular symbol table (binary is
// stripped), try the same thing with a dynamic symbol table.
//
// Note that Symbolize() is originally implemented to be used in
// FailureSignalHandler() in base/google.cc. Hence it doesn't use
// malloc() and other unsafe operations. It should be both
// thread-safe and async-signal-safe.
#ifndef BASE_SYMBOLIZE_H_
#define BASE_SYMBOLIZE_H_
#include "utilities.h"
#include "config.h"
#include <glog/logging.h>
#ifdef HAVE_SYMBOLIZE
#if defined(__ELF__) // defined by gcc
#if defined(__OpenBSD__)
#include <sys/exec_elf.h>
#else
#include <elf.h>
#endif
#if !defined(ANDROID)
#include <link.h> // For ElfW() macro.
#endif
// For systems where SIZEOF_VOID_P is not defined, determine it
// based on __LP64__ (defined by gcc on 64-bit systems)
#if !defined(SIZEOF_VOID_P)
# if defined(__LP64__)
# define SIZEOF_VOID_P 8
# else
# define SIZEOF_VOID_P 4
# endif
#endif
// If there is no ElfW macro, let's define it by ourself.
#ifndef ElfW
# if SIZEOF_VOID_P == 4
# define ElfW(type) Elf32_##type
# elif SIZEOF_VOID_P == 8
# define ElfW(type) Elf64_##type
# else
# error "Unknown sizeof(void *)"
# endif
#endif
_START_GOOGLE_NAMESPACE_
// Gets the section header for the given name, if it exists. Returns true on
// success. Otherwise, returns false.
bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
ElfW(Shdr) *out);
_END_GOOGLE_NAMESPACE_
#endif /* __ELF__ */
_START_GOOGLE_NAMESPACE_
// Restrictions on the callbacks that follow:
// - The callbacks must not use heaps but only use stacks.
// - The callbacks must be async-signal-safe.
// Installs a callback function, which will be called right before a symbol name
// is printed. The callback is intended to be used for showing a file name and a
// line number preceding a symbol name.
// "fd" is a file descriptor of the object file containing the program
// counter "pc". The callback function should write output to "out"
// and return the size of the output written. On error, the callback
// function should return -1.
typedef int (*SymbolizeCallback)(int fd,
void* pc,
char* out,
size_t out_size,
uint64_t relocation);
GLOG_EXPORT
void InstallSymbolizeCallback(SymbolizeCallback callback);
// Installs a callback function, which will be called instead of
// OpenObjectFileContainingPcAndGetStartAddress. The callback is expected
// to searches for the object file (from /proc/self/maps) that contains
// the specified pc. If found, sets |start_address| to the start address
// of where this object file is mapped in memory, sets the module base
// address into |base_address|, copies the object file name into
// |out_file_name|, and attempts to open the object file. If the object
// file is opened successfully, returns the file descriptor. Otherwise,
// returns -1. |out_file_name_size| is the size of the file name buffer
// (including the null-terminator).
typedef int (*SymbolizeOpenObjectFileCallback)(uint64_t pc,
uint64_t& start_address,
uint64_t& base_address,
char* out_file_name,
size_t out_file_name_size);
void InstallSymbolizeOpenObjectFileCallback(
SymbolizeOpenObjectFileCallback callback);
_END_GOOGLE_NAMESPACE_
#endif
_START_GOOGLE_NAMESPACE_
// Symbolizes a program counter. On success, returns true and write the
// symbol name to "out". The symbol name is demangled if possible
// (supports symbols generated by GCC 3.x or newer). Otherwise,
// returns false.
GLOG_EXPORT bool Symbolize(void* pc, char* out, size_t out_size);
_END_GOOGLE_NAMESPACE_
#endif // BASE_SYMBOLIZE_H_

View File

@ -1,447 +0,0 @@
// Copyright (c) 2006, 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: Satoru Takabayashi
//
// Unit tests for functions in symbolize.cc.
#include <csignal>
#include <iostream>
#include "config.h"
#include <glog/logging.h>
#include "googletest.h"
#include "symbolize.h"
#include "utilities.h"
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE;
#endif
using namespace std;
using namespace GOOGLE_NAMESPACE;
#if defined(HAVE_STACKTRACE)
#define always_inline
#if defined(__ELF__) || defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
// A wrapper function for Symbolize() to make the unit test simple.
static const char *TrySymbolize(void *pc) {
static char symbol[4096];
if (Symbolize(pc, symbol, sizeof(symbol))) {
return symbol;
} else {
return NULL;
}
}
#endif
# if defined(__ELF__)
// This unit tests make sense only with GCC.
// Uses lots of GCC specific features.
#if defined(__GNUC__) && !defined(__OPENCC__)
# if __GNUC__ >= 4
# define TEST_WITH_MODERN_GCC
# if defined(__i386__) && __i386__ // always_inline isn't supported for x86_64 with GCC 4.1.0.
# undef always_inline
# define always_inline __attribute__((always_inline))
# define HAVE_ALWAYS_INLINE
# endif // __i386__
# else
# endif // __GNUC__ >= 4
# if defined(__i386__) || defined(__x86_64__)
# define TEST_X86_32_AND_64 1
# endif // defined(__i386__) || defined(__x86_64__)
#endif
// Make them C linkage to avoid mangled names.
extern "C" {
void nonstatic_func();
void nonstatic_func() {
volatile int a = 0;
++a;
}
static void static_func() {
volatile int a = 0;
++a;
}
}
TEST(Symbolize, Symbolize) {
// We do C-style cast since GCC 2.95.3 doesn't allow
// reinterpret_cast<void *>(&func).
// Compilers should give us pointers to them.
EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
// The name of an internal linkage symbol is not specified; allow either a
// mangled or an unmangled name here.
const char *static_func_symbol =
TrySymbolize(reinterpret_cast<void *>(&static_func));
#if !defined(_MSC_VER) || !defined(NDEBUG)
CHECK(NULL != static_func_symbol);
EXPECT_TRUE(strcmp("static_func", static_func_symbol) == 0 ||
strcmp("static_func()", static_func_symbol) == 0);
#endif
EXPECT_TRUE(NULL == TrySymbolize(NULL));
}
struct Foo {
static void func(int x);
};
void ATTRIBUTE_NOINLINE Foo::func(int x) {
volatile int a = x;
++a;
}
// With a modern GCC, Symbolize() should return demangled symbol
// names. Function parameters should be omitted.
#ifdef TEST_WITH_MODERN_GCC
TEST(Symbolize, SymbolizeWithDemangling) {
Foo::func(100);
#if !defined(_MSC_VER) || !defined(NDEBUG)
EXPECT_STREQ("Foo::func()", TrySymbolize((void *)(&Foo::func)));
#endif
}
#endif
// Tests that verify that Symbolize footprint is within some limit.
// To measure the stack footprint of the Symbolize function, we create
// a signal handler (for SIGUSR1 say) that calls the Symbolize function
// on an alternate stack. This alternate stack is initialized to some
// known pattern (0x55, 0x55, 0x55, ...). We then self-send this signal,
// and after the signal handler returns, look at the alternate stack
// buffer to see what portion has been touched.
//
// This trick gives us the the stack footprint of the signal handler.
// But the signal handler, even before the call to Symbolize, consumes
// some stack already. We however only want the stack usage of the
// Symbolize function. To measure this accurately, we install two signal
// handlers: one that does nothing and just returns, and another that
// calls Symbolize. The difference between the stack consumption of these
// two signals handlers should give us the Symbolize stack foorprint.
static void *g_pc_to_symbolize;
static char g_symbolize_buffer[4096];
static char *g_symbolize_result;
static void EmptySignalHandler(int /*signo*/) {}
static void SymbolizeSignalHandler(int /*signo*/) {
if (Symbolize(g_pc_to_symbolize, g_symbolize_buffer,
sizeof(g_symbolize_buffer))) {
g_symbolize_result = g_symbolize_buffer;
} else {
g_symbolize_result = NULL;
}
}
const int kAlternateStackSize = 8096;
const char kAlternateStackFillValue = 0x55;
// These helper functions look at the alternate stack buffer, and figure
// out what portion of this buffer has been touched - this is the stack
// consumption of the signal handler running on this alternate stack.
static ATTRIBUTE_NOINLINE bool StackGrowsDown(int *x) {
int y;
return &y < x;
}
static int GetStackConsumption(const char* alt_stack) {
int x;
if (StackGrowsDown(&x)) {
for (int i = 0; i < kAlternateStackSize; i++) {
if (alt_stack[i] != kAlternateStackFillValue) {
return (kAlternateStackSize - i);
}
}
} else {
for (int i = (kAlternateStackSize - 1); i >= 0; i--) {
if (alt_stack[i] != kAlternateStackFillValue) {
return i;
}
}
}
return -1;
}
#ifdef HAVE_SIGALTSTACK
// Call Symbolize and figure out the stack footprint of this call.
static const char *SymbolizeStackConsumption(void *pc, int *stack_consumed) {
g_pc_to_symbolize = pc;
// The alt-signal-stack cannot be heap allocated because there is a
// bug in glibc-2.2 where some signal handler setup code looks at the
// current stack pointer to figure out what thread is currently running.
// Therefore, the alternate stack must be allocated from the main stack
// itself.
char altstack[kAlternateStackSize];
memset(altstack, kAlternateStackFillValue, kAlternateStackSize);
// Set up the alt-signal-stack (and save the older one).
stack_t sigstk;
memset(&sigstk, 0, sizeof(stack_t));
stack_t old_sigstk;
sigstk.ss_sp = altstack;
sigstk.ss_size = kAlternateStackSize;
sigstk.ss_flags = 0;
CHECK_ERR(sigaltstack(&sigstk, &old_sigstk));
// Set up SIGUSR1 and SIGUSR2 signal handlers (and save the older ones).
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
struct sigaction old_sa1, old_sa2;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_ONSTACK;
// SIGUSR1 maps to EmptySignalHandler.
sa.sa_handler = EmptySignalHandler;
CHECK_ERR(sigaction(SIGUSR1, &sa, &old_sa1));
// SIGUSR2 maps to SymbolizeSignalHanlder.
sa.sa_handler = SymbolizeSignalHandler;
CHECK_ERR(sigaction(SIGUSR2, &sa, &old_sa2));
// Send SIGUSR1 signal and measure the stack consumption of the empty
// signal handler.
CHECK_ERR(kill(getpid(), SIGUSR1));
int stack_consumption1 = GetStackConsumption(altstack);
// Send SIGUSR2 signal and measure the stack consumption of the symbolize
// signal handler.
CHECK_ERR(kill(getpid(), SIGUSR2));
int stack_consumption2 = GetStackConsumption(altstack);
// The difference between the two stack consumption values is the
// stack footprint of the Symbolize function.
if (stack_consumption1 != -1 && stack_consumption2 != -1) {
*stack_consumed = stack_consumption2 - stack_consumption1;
} else {
*stack_consumed = -1;
}
// Log the stack consumption values.
LOG(INFO) << "Stack consumption of empty signal handler: "
<< stack_consumption1;
LOG(INFO) << "Stack consumption of symbolize signal handler: "
<< stack_consumption2;
LOG(INFO) << "Stack consumption of Symbolize: " << *stack_consumed;
// Now restore the old alt-signal-stack and signal handlers.
CHECK_ERR(sigaltstack(&old_sigstk, NULL));
CHECK_ERR(sigaction(SIGUSR1, &old_sa1, NULL));
CHECK_ERR(sigaction(SIGUSR2, &old_sa2, NULL));
return g_symbolize_result;
}
#ifdef __ppc64__
// Symbolize stack consumption should be within 4kB.
const int kStackConsumptionUpperLimit = 4096;
#else
// Symbolize stack consumption should be within 2kB.
const int kStackConsumptionUpperLimit = 2048;
#endif
TEST(Symbolize, SymbolizeStackConsumption) {
int stack_consumed;
const char* symbol;
symbol = SymbolizeStackConsumption(reinterpret_cast<void *>(&nonstatic_func),
&stack_consumed);
EXPECT_STREQ("nonstatic_func", symbol);
EXPECT_GT(stack_consumed, 0);
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
// The name of an internal linkage symbol is not specified; allow either a
// mangled or an unmangled name here.
symbol = SymbolizeStackConsumption(reinterpret_cast<void *>(&static_func),
&stack_consumed);
CHECK(NULL != symbol);
EXPECT_TRUE(strcmp("static_func", symbol) == 0 ||
strcmp("static_func()", symbol) == 0);
EXPECT_GT(stack_consumed, 0);
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
}
#ifdef TEST_WITH_MODERN_GCC
TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
Foo::func(100);
int stack_consumed;
const char* symbol;
symbol = SymbolizeStackConsumption(reinterpret_cast<void *>(&Foo::func),
&stack_consumed);
EXPECT_STREQ("Foo::func()", symbol);
EXPECT_GT(stack_consumed, 0);
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
}
#endif
#endif // HAVE_SIGALTSTACK
// x86 specific tests. Uses some inline assembler.
extern "C" {
inline void* always_inline inline_func() {
void *pc = NULL;
#ifdef TEST_X86_32_AND_64
__asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
#endif
return pc;
}
void* ATTRIBUTE_NOINLINE non_inline_func();
void* ATTRIBUTE_NOINLINE non_inline_func() {
void *pc = NULL;
#ifdef TEST_X86_32_AND_64
__asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
#endif
return pc;
}
static void ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() {
#if defined(TEST_X86_32_AND_64) && defined(HAVE_ATTRIBUTE_NOINLINE)
void *pc = non_inline_func();
const char *symbol = TrySymbolize(pc);
#if !defined(_MSC_VER) || !defined(NDEBUG)
CHECK(symbol != NULL);
CHECK_STREQ(symbol, "non_inline_func");
#endif
cout << "Test case TestWithPCInsideNonInlineFunction passed." << endl;
#endif
}
static void ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() {
#if defined(TEST_X86_32_AND_64) && defined(HAVE_ALWAYS_INLINE)
void *pc = inline_func(); // Must be inlined.
const char *symbol = TrySymbolize(pc);
#if !defined(_MSC_VER) || !defined(NDEBUG)
CHECK(symbol != NULL);
CHECK_STREQ(symbol, __FUNCTION__);
#endif
cout << "Test case TestWithPCInsideInlineFunction passed." << endl;
#endif
}
}
// Test with a return address.
static void ATTRIBUTE_NOINLINE TestWithReturnAddress() {
#if defined(HAVE_ATTRIBUTE_NOINLINE)
void *return_address = __builtin_return_address(0);
const char *symbol = TrySymbolize(return_address);
#if !defined(_MSC_VER) || !defined(NDEBUG)
CHECK(symbol != NULL);
CHECK_STREQ(symbol, "main");
#endif
cout << "Test case TestWithReturnAddress passed." << endl;
#endif
}
# elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
#ifdef _MSC_VER
#include <intrin.h>
#pragma intrinsic(_ReturnAddress)
#endif
struct Foo {
static void func(int x);
};
__declspec(noinline) void Foo::func(int x) {
volatile int a = x;
++a;
}
TEST(Symbolize, SymbolizeWithDemangling) {
Foo::func(100);
const char* ret = TrySymbolize((void *)(&Foo::func));
#if defined(HAVE_DBGHELP) && !defined(NDEBUG)
EXPECT_STREQ("public: static void __cdecl Foo::func(int)", ret);
#endif
}
__declspec(noinline) void TestWithReturnAddress() {
void *return_address =
#ifdef __GNUC__ // Cygwin and MinGW support
__builtin_return_address(0)
#else
_ReturnAddress()
#endif
;
const char *symbol = TrySymbolize(return_address);
#if !defined(_MSC_VER) || !defined(NDEBUG)
CHECK(symbol != NULL);
CHECK_STREQ(symbol, "main");
#endif
cout << "Test case TestWithReturnAddress passed." << endl;
}
# endif // __ELF__
#endif // HAVE_STACKTRACE
int main(int argc, char **argv) {
FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]);
InitGoogleTest(&argc, argv);
#if defined(HAVE_SYMBOLIZE) && defined(HAVE_STACKTRACE)
# if defined(__ELF__)
// We don't want to get affected by the callback interface, that may be
// used to install some callback function at InitGoogle() time.
InstallSymbolizeCallback(NULL);
TestWithPCInsideInlineFunction();
TestWithPCInsideNonInlineFunction();
TestWithReturnAddress();
return RUN_ALL_TESTS();
# elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
TestWithReturnAddress();
return RUN_ALL_TESTS();
# else // GLOG_OS_WINDOWS
printf("PASS (no symbolize_unittest support)\n");
return 0;
# endif // __ELF__
#else
printf("PASS (no symbolize support)\n");
return 0;
#endif // HAVE_SYMBOLIZE
}

View File

@ -1,402 +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.
//
// Author: Shinichiro Hamaji
#include "config.h"
#include "utilities.h"
#include <cstdio>
#include <cstdlib>
#include <csignal>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <ctime>
#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_SYSLOG_H
# include <syslog.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h> // For geteuid.
#endif
#ifdef HAVE_PWD_H
# include <pwd.h>
#endif
#ifdef __ANDROID__
#include <android/log.h>
#endif
#include "base/googleinit.h"
using std::string;
_START_GOOGLE_NAMESPACE_
static const char* g_program_invocation_short_name = NULL;
bool IsGoogleLoggingInitialized() {
return g_program_invocation_short_name != NULL;
}
_END_GOOGLE_NAMESPACE_
// The following APIs are all internal.
#ifdef HAVE_STACKTRACE
#include "stacktrace.h"
#include "symbolize.h"
#include "base/commandlineflags.h"
GLOG_DEFINE_bool(symbolize_stacktrace, true,
"Symbolize the stack trace in the tombstone");
_START_GOOGLE_NAMESPACE_
typedef void DebugWriter(const char*, void*);
// The %p field width for printf() functions is two characters per byte.
// For some environments, add two extra bytes for the leading "0x".
static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
static void DebugWriteToStderr(const char* data, void *) {
// This one is signal-safe.
if (write(STDERR_FILENO, data, strlen(data)) < 0) {
// Ignore errors.
}
#if defined(__ANDROID__)
// ANDROID_LOG_FATAL as fatal error occurred and now is dumping call stack.
__android_log_write(ANDROID_LOG_FATAL,
glog_internal_namespace_::ProgramInvocationShortName(),
data);
#endif
}
static void DebugWriteToString(const char* data, void *arg) {
reinterpret_cast<string*>(arg)->append(data);
}
#ifdef HAVE_SYMBOLIZE
// Print a program counter and its symbol name.
static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc,
const char * const prefix) {
char tmp[1024];
const char *symbol = "(unknown)";
// Symbolizes the previous address of pc because pc may be in the
// next function. The overrun happens when the function ends with
// a call to a function annotated noreturn (e.g. CHECK).
if (Symbolize(reinterpret_cast<char *>(pc) - 1, tmp, sizeof(tmp))) {
symbol = tmp;
}
char buf[1024];
snprintf(buf, sizeof(buf), "%s@ %*p %s\n",
prefix, kPrintfPointerFieldWidth, pc, symbol);
writerfn(buf, arg);
}
#endif
static void DumpPC(DebugWriter *writerfn, void *arg, void *pc,
const char * const prefix) {
char buf[100];
snprintf(buf, sizeof(buf), "%s@ %*p\n",
prefix, kPrintfPointerFieldWidth, pc);
writerfn(buf, arg);
}
// Dump current stack trace as directed by writerfn
static void DumpStackTrace(int skip_count, DebugWriter *writerfn, void *arg) {
// Print stack trace
void* stack[32];
int depth = GetStackTrace(stack, ARRAYSIZE(stack), skip_count+1);
for (int i = 0; i < depth; i++) {
#if defined(HAVE_SYMBOLIZE)
if (FLAGS_symbolize_stacktrace) {
DumpPCAndSymbol(writerfn, arg, stack[i], " ");
} else {
DumpPC(writerfn, arg, stack[i], " ");
}
#else
DumpPC(writerfn, arg, stack[i], " ");
#endif
}
}
#if defined(__GNUC__)
__attribute__((noreturn))
#elif defined(_MSC_VER)
__declspec(noreturn)
#endif
static void DumpStackTraceAndExit() {
DumpStackTrace(1, DebugWriteToStderr, NULL);
// TODO(hamaji): Use signal instead of sigaction?
if (IsFailureSignalHandlerInstalled()) {
// Set the default signal handler for SIGABRT, to avoid invoking our
// own signal handler installed by InstallFailureSignalHandler().
#ifdef HAVE_SIGACTION
struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask);
sig_action.sa_handler = SIG_DFL;
sigaction(SIGABRT, &sig_action, NULL);
#elif defined(GLOG_OS_WINDOWS)
signal(SIGABRT, SIG_DFL);
#endif // HAVE_SIGACTION
}
abort();
}
_END_GOOGLE_NAMESPACE_
#endif // HAVE_STACKTRACE
_START_GOOGLE_NAMESPACE_
namespace glog_internal_namespace_ {
const char* ProgramInvocationShortName() {
if (g_program_invocation_short_name != NULL) {
return g_program_invocation_short_name;
} else {
// TODO(hamaji): Use /proc/self/cmdline and so?
return "UNKNOWN";
}
}
#ifdef GLOG_OS_WINDOWS
struct timeval {
long tv_sec, tv_usec;
};
// Based on: http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/os_win32.c&q=GetSystemTimeAsFileTime%20license:bsd
// See COPYING for copyright information.
static int gettimeofday(struct timeval *tv, void* /*tz*/) {
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlong-long"
#endif
#define EPOCHFILETIME (116444736000000000ULL)
FILETIME ft;
ULARGE_INTEGER li;
uint64 tt;
GetSystemTimeAsFileTime(&ft);
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
tt = (li.QuadPart - EPOCHFILETIME) / 10;
tv->tv_sec = tt / 1000000;
tv->tv_usec = tt % 1000000;
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
return 0;
}
#endif
int64 CycleClock_Now() {
// TODO(hamaji): temporary impementation - it might be too slow.
struct timeval tv;
gettimeofday(&tv, NULL);
return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
}
int64 UsecToCycles(int64 usec) {
return usec;
}
WallTime WallTime_Now() {
// Now, cycle clock is retuning microseconds since the epoch.
return CycleClock_Now() * 0.000001;
}
static int32 g_main_thread_pid = getpid();
int32 GetMainThreadPid() {
return g_main_thread_pid;
}
bool PidHasChanged() {
int32 pid = getpid();
if (g_main_thread_pid == pid) {
return false;
}
g_main_thread_pid = pid;
return true;
}
pid_t GetTID() {
// On Linux and MacOSX, we try to use gettid().
#if defined GLOG_OS_LINUX || defined GLOG_OS_MACOSX
#ifndef __NR_gettid
#ifdef GLOG_OS_MACOSX
#define __NR_gettid SYS_gettid
#elif ! defined __i386__
#error "Must define __NR_gettid for non-x86 platforms"
#else
#define __NR_gettid 224
#endif
#endif
static bool lacks_gettid = false;
if (!lacks_gettid) {
#if (defined(GLOG_OS_MACOSX) && defined(HAVE_PTHREAD_THREADID_NP))
uint64_t tid64;
const int error = pthread_threadid_np(NULL, &tid64);
pid_t tid = error ? -1 : static_cast<pid_t>(tid64);
#else
pid_t tid = static_cast<pid_t>(syscall(__NR_gettid));
#endif
if (tid != -1) {
return tid;
}
// Technically, this variable has to be volatile, but there is a small
// performance penalty in accessing volatile variables and there should
// not be any serious adverse effect if a thread does not immediately see
// the value change to "true".
lacks_gettid = true;
}
#endif // GLOG_OS_LINUX || GLOG_OS_MACOSX
// If gettid() could not be used, we use one of the following.
#if defined GLOG_OS_LINUX
return getpid(); // Linux: getpid returns thread ID when gettid is absent
#elif defined GLOG_OS_WINDOWS && !defined GLOG_OS_CYGWIN
return static_cast<pid_t>(GetCurrentThreadId());
#elif defined(HAVE_PTHREAD)
// If none of the techniques above worked, we use pthread_self().
return (pid_t)(uintptr_t)pthread_self();
#else
return -1;
#endif
}
const char* const_basename(const char* filepath) {
const char* base = strrchr(filepath, '/');
#ifdef GLOG_OS_WINDOWS // Look for either path separator in Windows
if (!base)
base = strrchr(filepath, '\\');
#endif
return base ? (base+1) : filepath;
}
static string g_my_user_name;
const string& MyUserName() {
return g_my_user_name;
}
static void MyUserNameInitializer() {
// TODO(hamaji): Probably this is not portable.
#if defined(GLOG_OS_WINDOWS)
const char* user = getenv("USERNAME");
#else
const char* user = getenv("USER");
#endif
if (user != NULL) {
g_my_user_name = user;
} else {
#if defined(HAVE_PWD_H) && defined(HAVE_UNISTD_H)
struct passwd pwd;
struct passwd* result = NULL;
char buffer[1024] = {'\0'};
uid_t uid = geteuid();
int pwuid_res = getpwuid_r(uid, &pwd, buffer, sizeof(buffer), &result);
if (pwuid_res == 0 && result) {
g_my_user_name = pwd.pw_name;
} else {
snprintf(buffer, sizeof(buffer), "uid%d", uid);
g_my_user_name = buffer;
}
#endif
if (g_my_user_name.empty()) {
g_my_user_name = "invalid-user";
}
}
}
REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer())
#ifdef HAVE_STACKTRACE
void DumpStackTraceToString(string* stacktrace) {
DumpStackTrace(1, DebugWriteToString, stacktrace);
}
#endif
// We use an atomic operation to prevent problems with calling CrashReason
// from inside the Mutex implementation (potentially through RAW_CHECK).
static const CrashReason* g_reason = 0;
void SetCrashReason(const CrashReason* r) {
sync_val_compare_and_swap(&g_reason,
reinterpret_cast<const CrashReason*>(0),
r);
}
void InitGoogleLoggingUtilities(const char* argv0) {
CHECK(!IsGoogleLoggingInitialized())
<< "You called InitGoogleLogging() twice!";
const char* slash = strrchr(argv0, '/');
#ifdef GLOG_OS_WINDOWS
if (!slash) slash = strrchr(argv0, '\\');
#endif
g_program_invocation_short_name = slash ? slash + 1 : argv0;
#ifdef HAVE_STACKTRACE
InstallFailureFunction(&DumpStackTraceAndExit);
#endif
}
void ShutdownGoogleLoggingUtilities() {
CHECK(IsGoogleLoggingInitialized())
<< "You called ShutdownGoogleLogging() without calling InitGoogleLogging() first!";
g_program_invocation_short_name = NULL;
#ifdef HAVE_SYSLOG_H
closelog();
#endif
}
} // namespace glog_internal_namespace_
_END_GOOGLE_NAMESPACE_
// Make an implementation of stacktrace compiled.
#ifdef STACKTRACE_H
# include STACKTRACE_H
# if 0
// For include scanners which can't handle macro expansions.
# include "stacktrace_libunwind-inl.h"
# include "stacktrace_x86-inl.h"
# include "stacktrace_x86_64-inl.h"
# include "stacktrace_powerpc-inl.h"
# include "stacktrace_generic-inl.h"
# endif
#endif

View File

@ -1,217 +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.
//
// Author: Shinichiro Hamaji
//
// Define utilties for glog internal usage.
#ifndef UTILITIES_H__
#define UTILITIES_H__
// printf macros for size_t, in the style of inttypes.h
#ifdef _LP64
#define __PRIS_PREFIX "z"
#else
#define __PRIS_PREFIX
#endif
// Use these macros after a % in a printf format string
// to get correct 32/64 bit behavior, like this:
// size_t size = records.size();
// printf("%"PRIuS"\n", size);
#define PRIdS __PRIS_PREFIX "d"
#define PRIxS __PRIS_PREFIX "x"
#define PRIuS __PRIS_PREFIX "u"
#define PRIXS __PRIS_PREFIX "X"
#define PRIoS __PRIS_PREFIX "o"
#include "base/mutex.h" // This must go first so we get _XOPEN_SOURCE
#include <string>
#include <glog/logging.h>
#if defined(GLOG_OS_WINDOWS)
# include "port.h"
#endif
#include "config.h"
// There are three different ways we can try to get the stack trace:
//
// 1) The libunwind library. This is still in development, and as a
// separate library adds a new dependency, but doesn't need a frame
// pointer. It also doesn't call malloc.
//
// 2) Our hand-coded stack-unwinder. This depends on a certain stack
// layout, which is used by gcc (and those systems using a
// gcc-compatible ABI) on x86 systems, at least since gcc 2.95.
// It uses the frame pointer to do its work.
//
// 3) The gdb unwinder -- also the one used by the c++ exception code.
// It's obviously well-tested, but has a fatal flaw: it can call
// malloc() from the unwinder. This is a problem because we're
// trying to use the unwinder to instrument malloc().
//
// 4) The Windows API CaptureStackTrace.
//
// Note: if you add a new implementation here, make sure it works
// correctly when GetStackTrace() is called with max_depth == 0.
// Some code may do that.
#if defined(HAVE_LIB_UNWIND)
# define STACKTRACE_H "stacktrace_libunwind-inl.h"
#elif defined(HAVE__UNWIND_BACKTRACE)
# 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
#if !defined(STACKTRACE_H) && defined(HAVE_EXECINFO_H)
# define STACKTRACE_H "stacktrace_generic-inl.h"
#endif
#if defined(STACKTRACE_H)
# define HAVE_STACKTRACE
#endif
#ifndef GLOG_NO_SYMBOLIZE_DETECTION
#ifndef HAVE_SYMBOLIZE
// defined by gcc
#if defined(__ELF__) && defined(GLOG_OS_LINUX)
# define HAVE_SYMBOLIZE
#elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)
// Use dladdr to symbolize.
# define HAVE_SYMBOLIZE
#elif defined(GLOG_OS_WINDOWS)
// Use DbgHelp to symbolize
# define HAVE_SYMBOLIZE
#endif
#endif // !defined(HAVE_SYMBOLIZE)
#endif // !defined(GLOG_NO_SYMBOLIZE_DETECTION)
#ifndef ARRAYSIZE
// There is a better way, but this is good enough for our purpose.
# define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
#endif
_START_GOOGLE_NAMESPACE_
namespace glog_internal_namespace_ {
#ifdef HAVE___ATTRIBUTE__
# define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
# define HAVE_ATTRIBUTE_NOINLINE
#elif defined(GLOG_OS_WINDOWS)
# define ATTRIBUTE_NOINLINE __declspec(noinline)
# define HAVE_ATTRIBUTE_NOINLINE
#else
# define ATTRIBUTE_NOINLINE
#endif
const char* ProgramInvocationShortName();
int64 CycleClock_Now();
int64 UsecToCycles(int64 usec);
WallTime WallTime_Now();
int32 GetMainThreadPid();
bool PidHasChanged();
pid_t GetTID();
const std::string& MyUserName();
// Get the part of filepath after the last path separator.
// (Doesn't modify filepath, contrary to basename() in libgen.h.)
const char* const_basename(const char* filepath);
// Wrapper of __sync_val_compare_and_swap. If the GCC extension isn't
// defined, we try the CPU specific logics (we only support x86 and
// x86_64 for now) first, then use a naive implementation, which has a
// race condition.
template<typename T>
inline T sync_val_compare_and_swap(T* ptr, T oldval, T newval) {
#if defined(HAVE___SYNC_VAL_COMPARE_AND_SWAP)
return __sync_val_compare_and_swap(ptr, oldval, newval);
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
T ret;
__asm__ __volatile__("lock; cmpxchg %1, (%2);"
:"=a"(ret)
// GCC may produces %sil or %dil for
// constraint "r", but some of apple's gas
// dosn't know the 8 bit registers.
// We use "q" to avoid these registers.
:"q"(newval), "q"(ptr), "a"(oldval)
:"memory", "cc");
return ret;
#else
T ret = *ptr;
if (ret == oldval) {
*ptr = newval;
}
return ret;
#endif
}
void DumpStackTraceToString(std::string* stacktrace);
struct CrashReason {
CrashReason() : filename(0), line_number(0), message(0), depth(0) {}
const char* filename;
int line_number;
const char* message;
// We'll also store a bit of stack trace context at the time of crash as
// it may not be available later on.
void* stack[32];
int depth;
};
void SetCrashReason(const CrashReason* r);
void InitGoogleLoggingUtilities(const char* argv0);
void ShutdownGoogleLoggingUtilities();
} // namespace glog_internal_namespace_
_END_GOOGLE_NAMESPACE_
using namespace GOOGLE_NAMESPACE::glog_internal_namespace_;
#endif // UTILITIES_H__

View File

@ -1,58 +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.
//
// Author: Shinichiro Hamaji
#include "utilities.h"
#include "googletest.h"
#include <glog/logging.h>
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE;
#endif
using namespace GOOGLE_NAMESPACE;
TEST(utilities, sync_val_compare_and_swap) {
bool now_entering = false;
EXPECT_FALSE(sync_val_compare_and_swap(&now_entering, false, true));
EXPECT_TRUE(sync_val_compare_and_swap(&now_entering, false, true));
EXPECT_TRUE(sync_val_compare_and_swap(&now_entering, false, true));
}
TEST(utilities, InitGoogleLoggingDeathTest) {
ASSERT_DEATH(InitGoogleLogging("foobar"), "");
}
int main(int argc, char **argv) {
InitGoogleLogging(argv[0]);
InitGoogleTest(&argc, argv);
CHECK_EQ(RUN_ALL_TESTS(), 0);
}

View File

@ -1,293 +0,0 @@
// Copyright (c) 1999, 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: Ray Sidney and many others
//
// Broken out from logging.cc by Soren Lassen
// logging_unittest.cc covers the functionality herein
#include "utilities.h"
#include <cstring>
#include <cstdlib>
#include <cerrno>
#include <cstdio>
#include <string>
#include "base/commandlineflags.h"
#include <glog/logging.h>
#include <glog/raw_logging.h>
#include "base/googleinit.h"
// glog doesn't have annotation
#define ANNOTATE_BENIGN_RACE(address, description)
using std::string;
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.");
_START_GOOGLE_NAMESPACE_
namespace glog_internal_namespace_ {
// Used by logging_unittests.cc so can't make it static here.
GLOG_EXPORT bool SafeFNMatch_(const char* pattern, size_t patt_len,
const char* str, size_t str_len);
// Implementation of fnmatch that does not need 0-termination
// of arguments and does not allocate any memory,
// but we only support "*" and "?" wildcards, not the "[...]" patterns.
// It's not a static function for the unittest.
GLOG_EXPORT bool SafeFNMatch_(const char* pattern, size_t patt_len,
const char* str, size_t str_len) {
size_t p = 0;
size_t s = 0;
while (1) {
if (p == patt_len && s == str_len) return true;
if (p == patt_len) return false;
if (s == str_len) return p+1 == patt_len && pattern[p] == '*';
if (pattern[p] == str[s] || pattern[p] == '?') {
p += 1;
s += 1;
continue;
}
if (pattern[p] == '*') {
if (p+1 == patt_len) return true;
do {
if (SafeFNMatch_(pattern+(p+1), patt_len-(p+1), str+s, str_len-s)) {
return true;
}
s += 1;
} while (s != str_len);
return false;
}
return false;
}
}
} // namespace glog_internal_namespace_
using glog_internal_namespace_::SafeFNMatch_;
// List of per-module log levels from FLAGS_vmodule.
// Once created each element is never deleted/modified
// except for the vlog_level: other threads will read VModuleInfo blobs
// w/o locks and we'll store pointers to vlog_level at VLOG locations
// that will never go away.
// We can't use an STL struct here as we wouldn't know
// when it's safe to delete/update it: other threads need to use it w/o locks.
struct VModuleInfo {
string module_pattern;
mutable int32 vlog_level; // Conceptually this is an AtomicWord, but it's
// too much work to use AtomicWord type here
// w/o much actual benefit.
const VModuleInfo* next;
};
// This protects the following global variables.
static Mutex vmodule_lock;
// Pointer to head of the VModuleInfo list.
// It's a map from module pattern to logging level for those module(s).
static VModuleInfo* vmodule_list = 0;
static SiteFlag* cached_site_list = 0;
// Boolean initialization flag.
static bool inited_vmodule = false;
// L >= vmodule_lock.
static void VLOG2Initializer() {
vmodule_lock.AssertHeld();
// Can now parse --vmodule flag and initialize mapping of module-specific
// logging levels.
inited_vmodule = false;
const char* vmodule = FLAGS_vmodule.c_str();
const char* sep;
VModuleInfo* head = NULL;
VModuleInfo* tail = NULL;
while ((sep = strchr(vmodule, '=')) != NULL) {
string pattern(vmodule, static_cast<size_t>(sep - vmodule));
int module_level;
if (sscanf(sep, "=%d", &module_level) == 1) {
VModuleInfo* info = new VModuleInfo;
info->module_pattern = pattern;
info->vlog_level = module_level;
if (head) {
tail->next = info;
} else {
head = info;
}
tail = info;
}
// Skip past this entry
vmodule = strchr(sep, ',');
if (vmodule == NULL) break;
vmodule++; // Skip past ","
}
if (head) { // Put them into the list at the head:
tail->next = vmodule_list;
vmodule_list = head;
}
inited_vmodule = true;
}
// This can be called very early, so we use SpinLock and RAW_VLOG here.
int SetVLOGLevel(const char* module_pattern, int log_level) {
int result = FLAGS_v;
size_t const pattern_len = strlen(module_pattern);
bool found = false;
{
MutexLock l(&vmodule_lock); // protect whole read-modify-write
for (const VModuleInfo* info = vmodule_list;
info != NULL; info = info->next) {
if (info->module_pattern == module_pattern) {
if (!found) {
result = info->vlog_level;
found = true;
}
info->vlog_level = log_level;
} else if (!found &&
SafeFNMatch_(info->module_pattern.c_str(),
info->module_pattern.size(),
module_pattern, pattern_len)) {
result = info->vlog_level;
found = true;
}
}
if (!found) {
VModuleInfo* info = new VModuleInfo;
info->module_pattern = module_pattern;
info->vlog_level = log_level;
info->next = vmodule_list;
vmodule_list = info;
SiteFlag** item_ptr = &cached_site_list;
SiteFlag* item = cached_site_list;
// We traverse the list fully because the pattern can match several items
// from the list.
while (item) {
if (SafeFNMatch_(module_pattern, pattern_len, item->base_name,
item->base_len)) {
// Redirect the cached value to its module override.
item->level = &info->vlog_level;
*item_ptr = item->next; // Remove the item from the list.
} else {
item_ptr = &item->next;
}
item = *item_ptr;
}
}
}
RAW_VLOG(1, "Set VLOG level for \"%s\" to %d", module_pattern, log_level);
return result;
}
// NOTE: Individual VLOG statements cache the integer log level pointers.
// NOTE: This function must not allocate memory or require any locks.
bool InitVLOG3__(SiteFlag* site_flag, int32* level_default,
const char* fname, int32 verbose_level) {
MutexLock l(&vmodule_lock);
bool read_vmodule_flag = inited_vmodule;
if (!read_vmodule_flag) {
VLOG2Initializer();
}
// protect the errno global in case someone writes:
// VLOG(..) << "The last error was " << strerror(errno)
int old_errno = errno;
// site_default normally points to FLAGS_v
int32* site_flag_value = level_default;
// Get basename for file
const char* base = strrchr(fname, '/');
#ifdef _WIN32
if (!base) {
base = strrchr(fname, '\\');
}
#endif
base = base ? (base+1) : fname;
const char* base_end = strchr(base, '.');
size_t base_length = base_end ? size_t(base_end - base) : strlen(base);
// Trim out trailing "-inl" if any
if (base_length >= 4 && (memcmp(base+base_length-4, "-inl", 4) == 0)) {
base_length -= 4;
}
// TODO: Trim out _unittest suffix? Perhaps it is better to have
// the extra control and just leave it there.
// find target in vector of modules, replace site_flag_value with
// a module-specific verbose level, if any.
for (const VModuleInfo* info = vmodule_list;
info != NULL; info = info->next) {
if (SafeFNMatch_(info->module_pattern.c_str(), info->module_pattern.size(),
base, base_length)) {
site_flag_value = &info->vlog_level;
// value at info->vlog_level is now what controls
// the VLOG at the caller site forever
break;
}
}
// Cache the vlog value pointer if --vmodule flag has been parsed.
ANNOTATE_BENIGN_RACE(site_flag,
"*site_flag may be written by several threads,"
" but the value will be the same");
if (read_vmodule_flag) {
site_flag->level = site_flag_value;
// If VLOG flag has been cached to the default site pointer,
// we want to add to the cached list in order to invalidate in case
// SetVModule is called afterwards with new modules.
// The performance penalty here is neglible, because InitVLOG3__ is called
// once per site.
if (site_flag_value == level_default && !site_flag->base_name) {
site_flag->base_name = base;
site_flag->base_len = base_length;
site_flag->next = cached_site_list;
cached_site_list = site_flag;
}
}
// restore the errno in case something recoverable went wrong during
// the initialization of the VLOG mechanism (see above note "protect the..")
errno = old_errno;
return *site_flag_value >= verbose_level;
}
_END_GOOGLE_NAMESPACE_

File diff suppressed because it is too large Load Diff

View File

@ -1,71 +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.
*
* ---
* Author: Craig Silverstein
* Copied from google-perftools and modified by Shinichiro Hamaji
*/
#ifndef _WIN32
# error You should only be including windows/port.cc in a windows environment!
#endif
#include "config.h"
#include <cstdarg> // for va_list, va_start, va_end
#include "port.h"
// These call the windows _vsnprintf, but always NUL-terminate.
int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
if (size == 0) // not even room for a \0?
return -1; // not what C99 says to do, but what windows does
str[size-1] = '\0';
return _vsnprintf(str, size-1, format, ap);
}
#ifndef HAVE_LOCALTIME_R
struct tm* localtime_r(const time_t* timep, struct tm* result) {
localtime_s(result, timep);
return result;
}
#endif // not HAVE_LOCALTIME_R
#ifndef HAVE_GMTIME_R
struct tm* gmtime_r(const time_t* timep, struct tm* result) {
gmtime_s(result, timep);
return result;
}
#endif // not HAVE_GMTIME_R
#ifndef HAVE_SNPRINTF
int snprintf(char *str, size_t size, const char *format, ...) {
va_list ap;
va_start(ap, format);
const int r = vsnprintf(str, size, format, ap);
va_end(ap);
return r;
}
#endif

View File

@ -1,181 +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.
*
* ---
* Author: Craig Silverstein
* Copied from google-perftools and modified by Shinichiro Hamaji
*
* These are some portability typedefs and defines to make it a bit
* easier to compile this code under VC++.
*
* Several of these are taken from glib:
* http://developer.gnome.org/doc/API/glib/glib-windows-compatability-functions.html
*/
#ifndef CTEMPLATE_WINDOWS_PORT_H_
#define CTEMPLATE_WINDOWS_PORT_H_
#include "config.h"
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN /* We always want minimal includes */
#endif
#include <windows.h>
#include <winsock.h> /* for gethostname */
#include <io.h> /* because we so often use open/close/etc */
#include <direct.h> /* for _getcwd() */
#include <process.h> /* for _getpid() */
#include <cstdarg> /* template_dictionary.cc uses va_copy */
#include <cstdio> /* read in vsnprintf decl. before redifining it */
#include <cstring> /* for _strnicmp(), strerror_s() */
#include <ctime> /* for localtime_s() */
/* Note: the C++ #includes are all together at the bottom. This file is
* used by both C and C++ code, so we put all the C++ together.
*/
#include <glog/logging.h>
#ifdef _MSC_VER
/* 4244: otherwise we get problems when substracting two size_t's to an int
* 4251: it's complaining about a private struct I've chosen not to dllexport
* 4355: we use this in a constructor, but we do it safely
* 4715: for some reason VC++ stopped realizing you can't return after abort()
* 4800: we know we're casting ints/char*'s to bools, and we're ok with that
* 4996: Yes, we're ok using "unsafe" functions like fopen() and strerror()
* 4312: Converting uint32_t to a pointer when testing %p
* 4267: also subtracting two size_t to int
* 4722: Destructor never returns due to abort()
*/
#pragma warning(disable:4244 4251 4355 4715 4800 4996 4267 4312 4722)
/* file I/O */
#define PATH_MAX 1024
#define access _access
#define getcwd _getcwd
#define open _open
#define read _read
#define write _write
#define lseek _lseek
#define close _close
#define popen _popen
#define pclose _pclose
#define R_OK 04 /* read-only (for access()) */
#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
#define O_WRONLY _O_WRONLY
#define O_CREAT _O_CREAT
#define O_EXCL _O_EXCL
#ifndef __MINGW32__
enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
#endif
#define S_IRUSR S_IREAD
#define S_IWUSR S_IWRITE
/* Not quite as lightweight as a hard-link, but more than good enough for us. */
#define link(oldpath, newpath) CopyFileA(oldpath, newpath, false)
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
/* In windows-land, hash<> is called hash_compare<> (from xhash.h) */
/* VC11 provides std::hash */
#if defined(_MSC_VER) && (_MSC_VER < 1700)
#define hash hash_compare
#endif
/* Sleep is in ms, on windows */
#define sleep(secs) Sleep((secs) * 1000)
/* We can't just use _vsnprintf and _snprintf as drop-in-replacements,
* because they don't always NUL-terminate. :-( We also can't use the
* name vsnprintf, since windows defines that (but not snprintf (!)).
*/
#ifndef HAVE_SNPRINTF
extern int GLOG_EXPORT snprintf(char* str, size_t size, const char* format,
...);
#endif
extern int GLOG_EXPORT safe_vsnprintf(char* str, size_t size,
const char* format, va_list ap);
#define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap)
#ifndef va_copy
#define va_copy(dst, src) (dst) = (src)
#endif
/* Windows doesn't support specifying the number of buckets as a
* hash_map constructor arg, so we leave this blank.
*/
#define CTEMPLATE_SMALL_HASHTABLE
#define DEFAULT_TEMPLATE_ROOTDIR ".."
// ----------------------------------- SYSTEM/PROCESS
typedef int pid_t;
#define getpid _getpid
#endif // _MSC_VER
// ----------------------------------- THREADS
#if defined(HAVE_PTHREAD)
# include <pthread.h>
#else // no PTHREAD
typedef DWORD pthread_t;
typedef DWORD pthread_key_t;
typedef LONG pthread_once_t;
enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock
#define pthread_self GetCurrentThreadId
#define pthread_equal(pthread_t_1, pthread_t_2) ((pthread_t_1)==(pthread_t_2))
#endif // HAVE_PTHREAD
#ifndef HAVE_LOCALTIME_R
extern GLOG_EXPORT struct tm* localtime_r(const time_t* timep,
struct tm* result);
#endif // not HAVE_LOCALTIME_R
#ifndef HAVE_GMTIME_R
extern GLOG_EXPORT struct tm* gmtime_r(const time_t* timep, struct tm* result);
#endif // not HAVE_GMTIME_R
inline char* strerror_r(int errnum, char* buf, size_t buflen) {
strerror_s(buf, buflen, errnum);
return buf;
}
#ifndef __cplusplus
/* I don't see how to get inlining for C code in MSVC. Ah well. */
#define inline
#endif
#endif /* _WIN32 */
#endif /* CTEMPLATE_WINDOWS_PORT_H_ */

View File

@ -20,7 +20,7 @@
#define TILE_SYSTEM_PROCESSOR "@CMAKE_SYSTEM_PROCESSOR@" #define TILE_SYSTEM_PROCESSOR "@CMAKE_SYSTEM_PROCESSOR@"
#define TILE_SYSTEM_NAME "@CMAKE_SYSTEM_NAME@" #define TILE_SYSTEM_NAME "@CMAKE_SYSTEM_NAME@"
#define TILE_SYSTEM_VERSION "@CMAKE_SYSTEM_VERSION@" #define TILE_SYSTEM_VERSION "@CMAKE_SYSTEM_VERSION@"
#define TILE_VERSION "@PROJECT_VERSOIN@" #define TILE_VERSION "@TILE_VERSION@"
// clang-format on // clang-format on

View File

@ -175,6 +175,8 @@ private:
}; };
for (auto &&item : m) {} for (auto &&item : m) {}
} }
return result;
}
void LinkToParent(Slice rel_path, ExposedVarGroup *parent) void LinkToParent(Slice rel_path, ExposedVarGroup *parent)
{ {

View File

@ -1,62 +1,14 @@
#include "tile/base/internal/logging.h" #include "tile/base/internal/logging.h"
#include <cassert>
#include "glog/logging.h" #include <iostream>
#include <map> #include <map>
#include <mutex> #include <mutex>
#include <set>
namespace tile {
bool
VLogIsOn(int n)
{
return true;
}
class LogMessage::Impl {
public:
Impl(const char *file, int line, int severity) : lm_(file, line, severity) {}
std::ostream &stream() { return lm_.stream(); }
private:
google::LogMessage lm_;
};
class LogMessageFatal::Impl {
public:
Impl(const char *file, int line) : lm_(file, line) {}
std::ostream &stream() { return lm_.stream(); }
private:
google::LogMessageFatal lm_;
};
LogMessage::LogMessage(const char *file, int line, int severity) : impl_(new Impl(file, line, severity)) {}
LogMessage::~LogMessage() = default;
std::ostream &
LogMessage::stream()
{
return impl_->stream();
}
LogMessageFatal::LogMessageFatal(const char *file, int line) : impl_(new Impl(file, line)) {}
LogMessageFatal::~LogMessageFatal() = default;
std::ostream &
LogMessageFatal::stream()
{
return impl_->stream();
}
}// namespace tile
namespace tile { namespace tile {
namespace internal { namespace internal {
namespace logging { namespace logging {
namespace { namespace {
std::vector<PrefixAppender *> * std::vector<PrefixAppender *> *
GetProviers() GetProviers()
@ -64,7 +16,7 @@ GetProviers()
static std::vector<PrefixAppender *> providers; static std::vector<PrefixAppender *> providers;
return &providers; return &providers;
} }
}// namespace } // namespace
namespace details { namespace details {
std::string std::string
@ -72,12 +24,9 @@ DescribeFormatArguments(const std::vector<std::string> &args)
{ {
return fmt::format("{}", fmt::join(args.begin(), args.end(), ", ")); return fmt::format("{}", fmt::join(args.begin(), args.end(), ", "));
} }
} // namespace details
}// namespace details void InstallPrefixProvider(PrefixAppender *writer) {
void
InstallPrefixProvider(PrefixAppender *writer)
{
GetProviers()->push_back(writer); GetProviers()->push_back(writer);
} }
@ -90,46 +39,233 @@ WritePrefixTo(std::string *to)
if (to->size() != was) { to->push_back(' '); } if (to->size() != was) { to->push_back(' '); }
} }
} }
}// namespace logging } // namespace logging
}// namespace internal } // namespace internal
}// namespace tile } // namespace tile
namespace tile { namespace tile {
static std::mutex g_sink_mutex;
static std::set<LogSink::Ptr> g_sinks;
static std::atomic<int> g_sink_count{0};
static uint64_t g_num_messages[TILE_MAX_LOG_SEVERITY + 1];
std::mutex g_log_mutex;
class OStreamWrapper : public std::streambuf {
public:
OStreamWrapper(std::ostream &ostream) : ostream_(ostream) {}
int_type overflow(int_type c) override { return c; }
private:
std::ostream &ostream_;
};
bool VLogIsOn(int n) { return true; }
class LogMessage::Impl {
public:
Impl(const char *file, int line)
: stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {
Init(file, line, TILE_INFO, &LogMessage::Impl::SendToLog);
}
Impl(const char *file, int line, LogSeverity severity)
: stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {
Init(file, line, severity, &LogMessage::Impl::SendToLog);
}
Impl(const char *file, int line, LogSeverity severity, LogSink *sink,
bool also_send_to_log)
: stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {
Init(file, line, severity,
also_send_to_log ? &LogMessage::Impl::SendToSinkAndLog
: &LogMessage::Impl::SendToSink);
sink_ = sink;
}
~Impl() { Flush(); }
std::ostream &stream() { return stream_; }
void Flush() {
if (has_been_flushed_) {
return;
}
num_chars_to_log_ = stream_.pcount();
const bool append_newline = message_text_[num_chars_to_log_ - 1] != '\n';
char original_final_char = '\0';
if (append_newline) {
original_final_char = message_text_[num_chars_to_log_];
message_text_[num_chars_to_log_++] = '\n';
}
message_text_[num_chars_to_log_] = '\0';
{
std::lock_guard<std::mutex> _{g_log_mutex};
(this->*(send_method_))();
++g_num_messages[severity_];
WaitForSinks();
if (sink_) {
sink_->Flush();
}
}
if (append_newline) {
message_text_[num_chars_to_log_ - 1] = original_final_char;
}
if (preserved_errno_ != 0) {
errno = preserved_errno_;
}
has_been_flushed_ = true;
if (severity_ == TILE_FATAL) {
assert(false);
}
}
LogSeverity severity() const noexcept { return severity_; }
int line() const noexcept { return line_; }
const char *fullname() const noexcept { return file_; }
const char *basename() const noexcept { return file_; }
const LogMessageTime &time() const noexcept { return time_; }
int preserved_errno() const { return preserved_errno_; }
private:
void Init(const char *file, int line, LogSeverity severity,
void (LogMessage::Impl::*send_method)()) {
has_been_flushed_ = false;
file_ = file;
line_ = line;
severity_ = severity;
send_method_ = send_method;
sink_ = nullptr;
const auto now = std::chrono::system_clock::now();
time_ = LogMessageTime(now);
thread_id_ = std::this_thread::get_id();
preserved_errno_ = errno;
}
void SendToSink() {
if (sink_) {
sink_->Send(severity_, fullname(), basename(), line(), time(),
message_text_ + num_prefix_chars_,
num_chars_to_log_ - num_prefix_chars_);
}
}
void SendToLog() {
if (g_sink_count.load(std::memory_order_relaxed) == 0) {
ColoredWriteToStdout(severity_, message_text_ + num_prefix_chars_,
num_chars_to_log_ - num_chars_to_log_);
}
LogToSinks(severity_, fullname(), basename(), line(), time(),
message_text_ + num_prefix_chars_,
num_chars_to_log_ - num_prefix_chars_);
}
void SendToSinkAndLog() {
SendToSink();
SendToLog();
}
private:
char message_text_[LogMessage::kMaxLogMessageLen + 1];
LogMessage::LogStream stream_;
bool has_been_flushed_;
const char *file_;
int line_;
LogSeverity severity_;
void (LogMessage::Impl::*send_method_)();
LogSink *sink_;
LogMessageTime time_;
std::thread::id thread_id_;
int preserved_errno_;
size_t num_prefix_chars_;
size_t num_chars_to_log_;
};
LogMessage::LogMessage(const char *file, int line)
: impl_(new Impl(file, line)) {}
LogMessage::LogMessage(const char *file, int line, LogSeverity severity)
: impl_(new Impl(file, line, severity)) {}
LogMessage::LogMessage(const char *file, int line, LogSeverity severity,
LogSink *sink, bool also_send_to_log)
: impl_(new Impl(file, line, severity, sink, also_send_to_log)) {}
LogMessage::~LogMessage() {}
std::ostream &LogMessage::stream() { return impl_->stream(); }
void LogMessage::Flush() { impl_->Flush(); }
LogSeverity LogMessage::severity() const noexcept { return impl_->severity(); }
int LogMessage::line() const noexcept { return impl_->line(); }
const char *LogMessage::fullname() const noexcept { return impl_->fullname(); }
const char *LogMessage::basename() const noexcept { return impl_->basename(); }
const LogMessageTime &LogMessage::time() const noexcept {
return impl_->time();
}
int LogMessage::preserved_errno() const { return impl_->preserved_errno(); }
LogMessageFatal::LogMessageFatal(const char *file, int line)
: LogMessage(file, line, TILE_FATAL) {}
LogMessageFatal::~LogMessageFatal() {}
std::ostream &LogMessageFatal::stream() { return LogMessage::stream(); }
LogMessageTime::LogMessageTime() : time_struct_(), timestamp_(0), usecs_(0), gmtoffset_(0) {} LogMessageTime::LogMessageTime() : time_struct_(), timestamp_(0), usecs_(0), gmtoffset_(0) {}
LogMessageTime::LogMessageTime(std::tm t) LogMessageTime::LogMessageTime(std::tm t) : use_localtime_(true) {
{
std::time_t timestamp = std::mktime(&t); std::time_t timestamp = std::mktime(&t);
init(t, timestamp, 0); init(t, timestamp, 0);
} }
LogMessageTime::LogMessageTime(std::time_t timestamp, WallTime now) LogMessageTime::LogMessageTime(std::time_t timestamp, WallTime now)
{ : use_localtime_(false) {
std::tm t; std::tm t;
if (FLAGS_log_utc_time) if (use_localtime_) {
gmtime_r(&timestamp, &t);
else
localtime_r(&timestamp, &t); localtime_r(&timestamp, &t);
} else {
gmtime_r(&timestamp, &t);
}
init(t, timestamp, now); init(t, timestamp, now);
} }
LogMessageTime::LogMessageTime(std::chrono::system_clock::time_point tp)
: use_localtime_(false) {
std::time_t timestamp = std::chrono::system_clock::to_time_t(tp);
std::tm t;
if (use_localtime_) {
localtime_r(&timestamp, &t);
} else {
gmtime_r(&timestamp, &t);
}
void init(t, timestamp, 0);
LogMessageTime::init(const std::tm &t, std::time_t timestamp, WallTime now) usecs_ = std::chrono::duration_cast<std::chrono::microseconds>(
{ tp.time_since_epoch())
.count() %
1000000;
}
void LogMessageTime::init(const std::tm &t, std::time_t timestamp,
WallTime now) {
time_struct_ = t; time_struct_ = t;
timestamp_ = timestamp; timestamp_ = timestamp;
usecs_ = static_cast<std::int32_t>((now - timestamp) * 1000000); if (now < timestamp) {
usecs_ = 0;
} else {
usecs_ = static_cast<std::int32_t>((now - timestamp) * 1000000) % 1000000;
}
CalcGmtOffset(); CalcGmtOffset();
} }
void void LogMessageTime::CalcGmtOffset() {
LogMessageTime::CalcGmtOffset()
{
std::tm gmt_struct; std::tm gmt_struct;
int isDst = 0; int isDst = 0;
if (FLAGS_log_utc_time) { if (true) {
localtime_r(&timestamp_, &gmt_struct); localtime_r(&timestamp_, &gmt_struct);
isDst = gmt_struct.tm_isdst; isDst = gmt_struct.tm_isdst;
gmt_struct = time_struct_; gmt_struct = time_struct_;
@ -146,6 +282,11 @@ LogMessageTime::CalcGmtOffset()
} }
LogSink::~LogSink() {} LogSink::~LogSink() {}
bool LogSink::ShouldLog(LogSeverity severity) { return true; }
void LogSink::Send(LogSeverity severity, const char *full_filename,
const char *base_filename, int line,
const LogMessageTime &logmsgtime, const char *message,
size_t message_len) {
void void
LogSink::send(LogSeverity severity, LogSink::send(LogSeverity severity,
@ -159,91 +300,104 @@ LogSink::send(LogSeverity severity,
// do nothing // do nothing
} }
void LogSink::Flush() {}
void std::string LogSink::ToString(LogSeverity severity, const char *file,
LogSink::WaitTillSent() const char *base_filename, int line,
{}
std::string
LogSink::ToString(LogSeverity severity,
const char *file,
int line,
const LogMessageTime &logmsgtime, const LogMessageTime &logmsgtime,
const char *message, const char *message, size_t message_len) {
size_t message_len) std::stringstream ss;
{ char date_time[64];
return google::LogSink::ToString(severity, file, line, logmsgtime.tm(), message, message_len); sprintf(date_time, "%4d-%02d-%02dT%02d:%02d:%02d.%06d",
} logmsgtime.year() + 1900, logmsgtime.month(), logmsgtime.day(),
logmsgtime.hour(), logmsgtime.min(), logmsgtime.sec(),
logmsgtime.usec());
class LogSinkWrapper : public google::LogSink { ss << date_time;
public:
LogSinkWrapper(tile::LogSink *dest) : dest_(dest) {}
~LogSinkWrapper() override {} if (logmsgtime.gmtoff() != 0) {
auto hour = logmsgtime.gmtoff() / 3600;
void send(LogSeverity severity, auto min = std::abs(logmsgtime.gmtoff() % 3600) / 60;
const char *full_filename, sprintf(date_time, "%+03ld:%02ld", hour, min);
const char *base_filename, ss << date_time;
int line, } else if (!logmsgtime.use_localtime()) {
const google::LogMessageTime &logmsgtime, ss << "Z";
const char *message,
size_t message_len) override
{
dest_->send(severity, full_filename, base_filename, line, logmsgtime.tm(), message, message_len);
} }
ss << " " << GetLogSeverityName(severity)[0] << " ";
ss << base_filename << ":" << line << " ";
void WaitTillSent() override { dest_->WaitTillSent(); } // return google::LogSink::ToString(severity, file, line, logmsgtime.tm(),
// message, message_len);
private: ss.write(message, message_len);
tile::LogSink *dest_; return ss.str();
};
struct LogSinkPair {
struct LogSinWrapper *wrapper;
LogSink *sink;
};
static std::map<LogSink *, LogSinkWrapper *> sink_registry;
static std::mutex sink_registry_mutex;
void
AddLogSink(LogSink *dest)
{
std::lock_guard<std::mutex> lock(sink_registry_mutex);
if (sink_registry.find(dest) != sink_registry.end()) { return; }
auto wrapper = new LogSinkWrapper(dest);
sink_registry[dest] = wrapper;
google::AddLogSink(wrapper);
} }
void static void ColoredWriteToStderrOrStdout(FILE *output, LogSeverity severity,
RemoveLogSink(LogSink *dest) const char *message, size_t len) {
{ fwrite(message, len, 1, output);
std::lock_guard<std::mutex> lock(sink_registry_mutex); fflush(output);
auto iter = sink_registry.find(dest); }
if (iter != sink_registry.end()) {
google::RemoveLogSink(iter->second); void ColoredWriteToStdout(LogSeverity severity, const char *message,
sink_registry.erase(iter); size_t len) {
delete iter->second; FILE *output = stdout;
if (severity >= TILE_FATAL) {
output = stderr;
}
ColoredWriteToStderrOrStdout(output, severity, message, len);
}
void ColoredWriteToStderr(LogSeverity severity, const char *message,
size_t len) {
ColoredWriteToStderrOrStdout(stderr, severity, message, len);
}
void AddLogSink(LogSink::Ptr dest) {
std::lock_guard<std::mutex> _(g_sink_mutex);
g_sinks.insert(dest);
g_sink_count.fetch_add(1);
}
void RemoveLogSink(LogSink::Ptr dest) {
std::lock_guard<std::mutex> _(g_sink_mutex);
g_sinks.erase(dest);
g_sink_count.fetch_sub(1);
}
void SetStderrLogging(LogSeverity min_severity) {}
void LogToStderr() {}
void LogToSinks(LogSeverity severity, const char *full_filename,
const char *base_filename, int line, const LogMessageTime &time,
const char *message, size_t message_len) {
std::lock_guard<std::mutex> _(g_sink_mutex);
for (auto &&sink : g_sinks) {
if (sink->ShouldLog(severity)) {
sink->Send(severity, full_filename, base_filename, line, time, message,
message_len);
}
}
}
void WaitForSinks() {
std::lock_guard<std::mutex> _(g_sink_mutex);
for (auto &&sink : g_sinks) {
sink->Flush();
} }
} }
void const char *GetLogSeverityName(LogSeverity severity) {
SetStderrLogging(LogSeverity min_severity) const static std::map<LogSeverity, const char *> severity_names = {
{ {TILE_INFO, "INFO"},
google::SetStderrLogging(min_severity); {TILE_WARNING, "WARNING"},
{TILE_ERROR, "ERROR"},
{TILE_FATAL, "FATAL"},
};
auto iter = severity_names.find(severity);
if (iter != severity_names.end()) {
return iter->second;
} else {
return "UNKNOWN";
}
} }
void } // namespace tile
LogToStderr()
{
google::LogToStderr();
}
const char *
GetLogSeverityName(LogSeverity severity)
{
return google::GetLogSeverityName(severity);
}
}// namespace tile

View File

@ -9,6 +9,7 @@
#include <cstdint> #include <cstdint>
#include <ctime> #include <ctime>
#include <set>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
@ -17,31 +18,98 @@
#include <type_traits> #include <type_traits>
namespace tile { namespace tile {
typedef int LogSeverity; // typedef int LogSeverity;
const int TILE_INFO = 0, TILE_WARNING = 1, TILE_ERROR = 2, TILE_FATAL = 3; // const int TILE_INFO = 0, TILE_WARNING = 1, TILE_ERROR = 2, TILE_FATAL = 3;
enum LogSeverity {
TILE_INFO = 0,
TILE_WARNING = 1,
TILE_ERROR = 2,
TILE_FATAL = 3,
TILE_MAX_LOG_SEVERITY = TILE_FATAL
};
bool VLogIsOn(int n); bool VLogIsOn(int n);
class LogStreamBuf : public std::streambuf {
public:
LogStreamBuf(char *buf, int len) { setp(buf, buf + len - 2); }
int_type overflow(int_type ch) { return ch; }
size_t pcount() const { return static_cast<size_t>(pptr() - pbase()); }
char *pbase() const { return std::streambuf::pbase(); }
};
class LogSink;
class LogMessageTime;
class LogMessage { class LogMessage {
public: public:
LogMessage(const char *file, int line, int severity); class LogStream : public std::ostream {
public:
LogStream(char *buf, int len, int64_t ctr)
: std::ostream(nullptr), streambuf_(buf, len), ctr_(ctr), self_(this) {
rdbuf(&streambuf_);
}
LogStream(LogStream &other) noexcept
: std::ostream(nullptr), streambuf_(std::move(other.streambuf_)),
ctr_(internal::Exchange(other.ctr_, 0)), self_(this) {
rdbuf(&streambuf_);
}
LogStream &operator=(LogStream &&other) noexcept {
streambuf_ = std::move(other.streambuf_);
ctr_ = internal::Exchange(other.ctr_, 0);
self_ = this;
rdbuf(&streambuf_);
return *this;
}
int64_t ctr() const { return ctr_; }
void set_ctr(int64_t ctr) { ctr_ = ctr; }
LogStream *self() { return self_; }
size_t pcount() const { return streambuf_.pcount(); }
char *pbase() const { return streambuf_.pbase(); }
char *str() const { return pbase(); }
LogStream(const LogStream &) = delete;
LogStream &operator=(const LogStream &) = delete;
private:
LogStreamBuf streambuf_;
int64_t ctr_;
LogStream *self_;
};
public:
static const size_t kMaxLogMessageLen = 30000;
LogMessage(const char *file, int line);
LogMessage(const char *file, int line, LogSeverity severity);
LogMessage(const char *file, int line, LogSeverity severity, LogSink *sink,
bool also_send_to_log = true);
~LogMessage(); ~LogMessage();
std::ostream &stream(); std::ostream &stream();
void Flush();
LogSeverity severity() const noexcept;
int line() const noexcept;
const char *fullname() const noexcept;
const char *basename() const noexcept;
const LogMessageTime &time() const noexcept;
int preserved_errno() const;
private: private:
class Impl; class Impl;
std::unique_ptr<Impl> impl_; std::unique_ptr<Impl> impl_;
}; };
class LogMessageFatal { class LogMessageFatal : public LogMessage {
public: public:
LogMessageFatal(const char *file, int line); LogMessageFatal(const char *file, int line);
~LogMessageFatal(); ~LogMessageFatal();
std::ostream &stream(); std::ostream &stream();
private:
class Impl;
std::unique_ptr<Impl> impl_;
}; };
class LogMessageVoidify { class LogMessageVoidify {
@ -482,76 +550,67 @@ FormatLog(const char *file, int line, Ts &&...args) noexcept
namespace tile { namespace tile {
typedef double WallTime; typedef double WallTime;
struct LogMessageTime { struct LogMessageTime {
LogMessageTime(); LogMessageTime();
LogMessageTime(std::tm t); LogMessageTime(std::tm t);
LogMessageTime(std::time_t timestamp, WallTime now); LogMessageTime(std::time_t timestamp, WallTime now);
LogMessageTime(std::chrono::system_clock::time_point tp);
const time_t &timestamp() const { return timestamp_; } const time_t &timestamp() const { return timestamp_; }
const int &sec() const { return time_struct_.tm_sec; } const int &sec() const { return time_struct_.tm_sec; }
const int32_t &usec() const { return usecs_; } const int32_t &usec() const { return usecs_; }
const int &(min)() const { return time_struct_.tm_min; }
const int &(min) () const { return time_struct_.tm_min; }
const int &hour() const { return time_struct_.tm_hour; } const int &hour() const { return time_struct_.tm_hour; }
const int &day() const { return time_struct_.tm_mday; } const int &day() const { return time_struct_.tm_mday; }
const int &month() const { return time_struct_.tm_mon; } const int &month() const { return time_struct_.tm_mon; }
const int &year() const { return time_struct_.tm_year; } const int &year() const { return time_struct_.tm_year; }
const int &dayOfWeek() const { return time_struct_.tm_wday; } const int &dayOfWeek() const { return time_struct_.tm_wday; }
const int &dayInYear() const { return time_struct_.tm_yday; } const int &dayInYear() const { return time_struct_.tm_yday; }
const int &dst() const { return time_struct_.tm_isdst; } const int &dst() const { return time_struct_.tm_isdst; }
const long int &gmtoff() const { return gmtoffset_; } const long int &gmtoff() const { return gmtoffset_; }
const std::tm &tm() const { return time_struct_; } const std::tm &tm() const { return time_struct_; }
const bool use_localtime() const { return use_localtime_; }
private: private:
void init(const std::tm &t, std::time_t timestamp, WallTime now); void init(const std::tm &t, std::time_t timestamp, WallTime now);
std::tm time_struct_;// Time of creation of LogMessage std::tm time_struct_; // Time of creation of LogMessage
time_t timestamp_; // Time of creation of LogMessage in seconds time_t timestamp_; // Time of creation of LogMessage in seconds
int32_t usecs_; // Time of creation of LogMessage - microseconds part int32_t usecs_; // Time of creation of LogMessage - microseconds part
long int gmtoffset_; long int gmtoffset_;
bool use_localtime_;
void CalcGmtOffset(); void CalcGmtOffset();
}; };
class LogSink { class LogSink {
public: public:
using Ptr = std::shared_ptr<LogSink>;
virtual ~LogSink(); virtual ~LogSink();
virtual void send(LogSeverity severity, virtual bool ShouldLog(LogSeverity severity);
const char *full_filename, virtual void Send(LogSeverity severity, const char *full_filename,
const char *base_filename, const char *base_filename, int line,
int line, const LogMessageTime &logmsgtime, const char *message,
const LogMessageTime &logmsgtime,
const char *message,
size_t message_len); size_t message_len);
virtual void WaitTillSent(); virtual void Flush();
std::string ToString(LogSeverity severity, std::string ToString(LogSeverity severity, const char *file,
const char *file, const char *base_file, int line,
int line, const LogMessageTime &logmsgtime, const char *message,
const LogMessageTime &logmsgtime,
const char *message,
size_t message_len); size_t message_len);
}; };
class FileLogSink : public LogSink { void ColoredWriteToStdout(LogSeverity severity, const char *message,
public: size_t len);
FileLogSink(const std::string &file_path_template); void ColoredWriteToStderr(LogSeverity severity, const char *message,
}; size_t len);
void AddLogSink(LogSink::Ptr dest);
void AddLogSink(LogSink *dest); void RemoveLogSink(LogSink::Ptr dest);
void RemoveLogSink(LogSink *dest);
void SetStderrLogging(LogSeverity min_severity); void SetStderrLogging(LogSeverity min_severity);
void LogToStderr(); void LogToStderr();
void LogToSinks(LogSeverity severity, const char *full_filename,
const char *base_filename, int line, const LogMessageTime &time,
const char *message, size_t message_len);
void WaitForSinks();
const char *GetLogSeverityName(LogSeverity severity); const char *GetLogSeverityName(LogSeverity severity);
}// namespace tile }// namespace tile

View File

@ -0,0 +1,187 @@
#include "tile/base/internal/logging.h"
#include "glog/logging.h"
#include <map>
#include <mutex>
namespace tile {
bool VLogIsOn(int n) { return true; }
class LogMessage::Impl {
public:
Impl(const char *file, int line, int severity) : lm_(file, line, severity) {}
std::ostream &stream() { return lm_.stream(); }
private:
google::LogMessage lm_;
};
class LogMessageFatal::Impl {
public:
Impl(const char *file, int line) : lm_(file, line) {}
std::ostream &stream() { return lm_.stream(); }
private:
google::LogMessageFatal lm_;
};
LogMessage::LogMessage(const char *file, int line, int severity)
: impl_(new Impl(file, line, severity)) {}
LogMessage::~LogMessage() = default;
std::ostream &LogMessage::stream() { return impl_->stream(); }
LogMessageFatal::LogMessageFatal(const char *file, int line)
: impl_(new Impl(file, line)) {}
LogMessageFatal::~LogMessageFatal() = default;
std::ostream &LogMessageFatal::stream() { return impl_->stream(); }
} // namespace tile
namespace tile {
namespace internal {
namespace logging {
namespace {
std::vector<PrefixAppender *> *GetProviers() {
static std::vector<PrefixAppender *> providers;
return &providers;
}
} // namespace
namespace details {
std::string DescribeFormatArguments(const std::vector<std::string> &args) {
return fmt::format("{}", fmt::join(args.begin(), args.end(), ", "));
}
} // namespace details
void InstallPrefixProvider(PrefixAppender *writer) {
GetProviers()->push_back(writer);
}
void WritePrefixTo(std::string *to) {
for (auto &&appender : *GetProviers()) {
auto was = to->size();
appender(to);
if (to->size() != was) {
to->push_back(' ');
}
}
}
} // namespace logging
} // namespace internal
} // namespace tile
namespace tile {
LogMessageTime::LogMessageTime()
: time_struct_(), timestamp_(0), usecs_(0), gmtoffset_(0) {}
LogMessageTime::LogMessageTime(std::tm t) {
std::time_t timestamp = std::mktime(&t);
init(t, timestamp, 0);
}
LogMessageTime::LogMessageTime(std::time_t timestamp, WallTime now) {
std::tm t;
if (FLAGS_log_utc_time)
gmtime_r(&timestamp, &t);
else
localtime_r(&timestamp, &t);
init(t, timestamp, now);
}
void LogMessageTime::init(const std::tm &t, std::time_t timestamp,
WallTime now) {
time_struct_ = t;
timestamp_ = timestamp;
usecs_ = static_cast<std::int32_t>((now - timestamp) * 1000000);
CalcGmtOffset();
}
void LogMessageTime::CalcGmtOffset() {
std::tm gmt_struct;
int isDst = 0;
if (FLAGS_log_utc_time) {
localtime_r(&timestamp_, &gmt_struct);
isDst = gmt_struct.tm_isdst;
gmt_struct = time_struct_;
} else {
isDst = time_struct_.tm_isdst;
gmtime_r(&timestamp_, &gmt_struct);
}
time_t gmt_sec = mktime(&gmt_struct);
const long hour_secs = 3600;
// If the Daylight Saving Time(isDst) is active subtract an hour from the
// current timestamp.
gmtoffset_ =
static_cast<long int>(timestamp_ - gmt_sec + (isDst ? hour_secs : 0));
}
LogSink::~LogSink() {}
void LogSink::send(LogSeverity severity, const char *full_filename,
const char *base_filename, int line,
const LogMessageTime &logmsgtime, const char *message,
size_t message_len) {
// do nothing
}
void LogSink::WaitTillSent() {}
std::string LogSink::ToString(LogSeverity severity, const char *file, int line,
const LogMessageTime &logmsgtime,
const char *message, size_t message_len) {
return google::LogSink::ToString(severity, file, line, logmsgtime.tm(),
message, message_len);
}
class LogSinkWrapper : public google::LogSink {
public:
LogSinkWrapper(tile::LogSink *dest) : dest_(dest) {}
~LogSinkWrapper() override {}
void send(LogSeverity severity, const char *full_filename,
const char *base_filename, int line,
const google::LogMessageTime &logmsgtime, const char *message,
size_t message_len) override {
dest_->send(severity, full_filename, base_filename, line, logmsgtime.tm(),
message, message_len);
}
void WaitTillSent() override { dest_->WaitTillSent(); }
private:
tile::LogSink *dest_;
};
struct LogSinkPair {
struct LogSinWrapper *wrapper;
LogSink *sink;
};
static std::map<LogSink *, LogSinkWrapper *> sink_registry;
static std::mutex sink_registry_mutex;
void AddLogSink(LogSink *dest) {
std::lock_guard<std::mutex> lock(sink_registry_mutex);
if (sink_registry.find(dest) != sink_registry.end()) {
return;
}
auto wrapper = new LogSinkWrapper(dest);
sink_registry[dest] = wrapper;
google::AddLogSink(wrapper);
}
void RemoveLogSink(LogSink *dest) {
std::lock_guard<std::mutex> lock(sink_registry_mutex);
auto iter = sink_registry.find(dest);
if (iter != sink_registry.end()) {
google::RemoveLogSink(iter->second);
sink_registry.erase(iter);
delete iter->second;
}
}
void SetStderrLogging(LogSeverity min_severity) {
google::SetStderrLogging(min_severity);
}
void LogToStderr() { google::LogToStderr(); }
const char *GetLogSeverityName(LogSeverity severity) {
return google::GetLogSeverityName(severity);
}
} // namespace tile

View File

@ -9,17 +9,12 @@
#include <thread> #include <thread>
struct AwesomeLogSink : public tile::LogSink { struct AwesomeLogSink : public tile::LogSink {
virtual void send(tile::LogSeverity severity, virtual void Send(tile::LogSeverity severity, const char *full_filename,
const char *full_filename, const char *base_filename, int line,
const char *base_filename, const tile::LogMessageTime &logmsgtime, const char *message,
int line, size_t message_len) override {
const tile::LogMessageTime &logmsgtime, msgs.emplace_back(std::string(message, message_len));
const char *message,
size_t message_len) override
{
msgs.emplace_back(message, message_len);
} }
std::vector<std::string> msgs; std::vector<std::string> msgs;
}; };
@ -37,11 +32,26 @@ WriteLoggingPrefix2(std::string *s)
*s += my_prefix2; *s += my_prefix2;
} }
void TEST(Logging, Prefix) {
ResetLogPrefix() auto sink = std::make_shared<AwesomeLogSink>();
{ tile::AddLogSink(sink);
my_prefix = ""; tile::ScopedDeferred defered([&] { tile::RemoveLogSink(sink); });
my_prefix2 = "";
TILE_LOG_INFO("something");
my_prefix = "[prefix]";
TILE_LOG_INFO("something");
my_prefix = "[prefix1]";
TILE_LOG_INFO("something");
my_prefix2 = "[prefix2]";
TILE_LOG_INFO("something");
ASSERT_THAT(sink->msgs,
::testing::ElementsAre("something", "[prefix] something",
"[prefix1] something",
"[prefix1] [prefix2] something"));
} }
TEST(Logging, CHECK) TEST(Logging, CHECK)
@ -61,20 +71,16 @@ TEST(Logging, Prefix)
tile::AddLogSink(&sink); tile::AddLogSink(&sink);
tile::ScopedDeferred defered([&] { tile::RemoveLogSink(&sink); }); tile::ScopedDeferred defered([&] { tile::RemoveLogSink(&sink); });
TILE_LOG_INFO("something"); auto sink = std::make_shared<AwesomeLogSink>();
tile::AddLogSink(sink);
tile::ScopedDeferred defered([&] { tile::RemoveLogSink(sink); });
for (int i = 0; i < 30; i++) {
TILE_LOG_INFO_EVERY_SECOND("something");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
my_prefix = "[prefix]"; ASSERT_THAT(sink->msgs,
TILE_LOG_INFO("something"); ::testing::ElementsAre("something", "something", "something"));
my_prefix = "[prefix1]";
TILE_LOG_INFO("something");
my_prefix2 = "[prefix2]";
TILE_LOG_INFO("something");
ASSERT_THAT(sink.msgs,
::testing::ElementsAre(
"something", "[prefix] something", "[prefix1] something", "[prefix1] [prefix2] something"));
} }
TEST(Logging, DontPanicOnFormatFailure) { TILE_LOG_INFO("Don't panic!{}{}", 1); } TEST(Logging, DontPanicOnFormatFailure) { TILE_LOG_INFO("Don't panic!{}{}", 1); }

View File

@ -4,6 +4,8 @@
#pragma once #pragma once
#include "tile/base/internal/logging.h" #include "tile/base/internal/logging.h"
#include "tile/base/logging/basic_file_sink.h"
#include "tile/base/logging/splitter_sink.h"
// #define TILE_VLOG(n, ...) // #define TILE_VLOG(n, ...)

View File

@ -0,0 +1,24 @@
#include "tile/base/logging/basic_file_sink.h"
namespace tile {
BasicFileSink::Ptr BasicFileSink::Create(const std::string &filepath) {
auto sink = std::shared_ptr<BasicFileSink>(new BasicFileSink());
sink->set_filepath(filepath);
return sink;
}
BasicFileSink::BasicFileSink() {}
BasicFileSink::~BasicFileSink() {}
void BasicFileSink::Send(LogSeverity severity, const char *full_filename,
const char *base_filename, int line,
const LogMessageTime &logmsgtime, const char *message,
size_t message_len) {
TILE_CHECK(!filepath_.empty(), "filepath is empty");
ofs_ << std::string(message, message_len) << std::endl;
}
std::string BasicFileSink::filepath() const { return filepath_; }
void BasicFileSink::set_filepath(const std::string &filepath) {
filepath_ = filepath;
ofs_.open(filepath, std::ios::out | std::ios::app);
}
void BasicFileSink::Flush() { ofs_.flush(); }
} // namespace tile

View File

@ -0,0 +1,36 @@
#ifndef TILE_BASE_LOGGING_BASIC_FILE_SINK_H
#define TILE_BASE_LOGGING_BASIC_FILE_SINK_H
#pragma once
#include "tile/base/internal/logging.h"
#include <mutex>
#include <set>
namespace tile {
class BasicFileSink : public LogSink {
public:
using Ptr = std::shared_ptr<BasicFileSink>;
static Ptr Create(const std::string &filepath);
~BasicFileSink() override;
void Send(LogSeverity severity, const char *full_filename,
const char *base_filename, int line,
const LogMessageTime &logmsgtime, const char *message,
size_t message_len) override;
void Flush() override;
std::string filepath() const;
void set_filepath(const std::string &filepath);
protected:
BasicFileSink();
private:
std::string filepath_;
std::ofstream ofs_;
};
} // namespace tile
#endif // TILE_BASE_LOGGING_BASIC_FILE_SINK_H

View File

@ -0,0 +1,32 @@
#include "tile/base/logging/console_sink.h"
#include <stdio.h>
namespace tile {
ConsoleSink::Ptr ConsoleSink::Create() {
return std::shared_ptr<ConsoleSink>(new ConsoleSink());
}
ConsoleSink::~ConsoleSink() {}
void ConsoleSink::Send(LogSeverity severity, const char *full_filename,
const char *base_filename, int line,
const LogMessageTime &logmsgtime, const char *message,
size_t message_len) {
auto msg = ToString(severity, full_filename, base_filename, line, logmsgtime,
message, message_len);
while (!msg.empty() && msg.back() == '\n') {
msg.pop_back();
}
if (severity >= TILE_FATAL) {
fprintf(stderr, "%s\n", msg.c_str());
} else {
fprintf(stdout, "%s\n", msg.c_str());
}
}
void ConsoleSink::Flush() {}
ConsoleSink::ConsoleSink() {}
} // namespace tile

View File

@ -0,0 +1,25 @@
#ifndef TILE_BASE_LOGGING_CONSOLE_SINK_H
#define TILE_BASE_LOGGING_CONSOLE_SINK_H
#pragma once
#include "tile/base/internal/logging.h"
namespace tile {
class ConsoleSink : public LogSink {
public:
using Ptr = std::shared_ptr<ConsoleSink>;
static Ptr Create();
~ConsoleSink() override;
void Send(LogSeverity severity, const char *full_filename,
const char *base_filename, int line,
const LogMessageTime &logmsgtime, const char *message,
size_t message_len) override;
void Flush() override;
protected:
ConsoleSink();
};
} // namespace tile
#endif // TILE_BASE_LOGGING_CONSOLE_SINK_H

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