Comments (4)
I've traced the issue and it should be a bug of glog.
I will add the reason analysis later and submit a PR to fix it later.
from glog.
Because FLAGS_log_dir
specifies the output directory of the log, the following two methods should be completely equivalent. (Both are absolute paths and must be a directory ("dir" is explicitly used in the name of this flag))
FLAGS_log_dir=/tmp/glogs --> No '/' at the end
VS.
FLAGS_log_dir=/tmp/glogs/
But unfortunately, I found that both will indeed print logs to the "/tmp/glogs/" directory, but if there is no '/'
at the end, LogCleaner cannot clean the logs correctly, ie, LogCleaner can only work correctly if the path specified by FLAGS_log_dir
has '/'
at the end.
- To find the cause, I first created some log files (following the naming rules of glog log files) and modified their mtime to a very old time.
#touch -mt 202310010000 /tmp/glogs/*
#ll -rt /tmp/glogs/
total 32776
-rw-r--r-- 1 root root 33554535 Oct 1 00:00 test-cleaner.28f8271ff892.root.log.INFO.20231001-000000.65295
- Secondly, in order to track the code execution process, I hacked the glog code and added some output information. The output information in the two methods is as follows (only the required part is retained, we only need to care about the checking process of the
"test-cleaner.28f8271ff892.root.log.INFO.20231010-130507.58195"
file):
# ------------ FLAGS_log_dir=/tmp/glogs (No '/' at the end)----------------
lingbin-debugging[Run:1383]. Into LogCleaner::Run(). base_filename_selected=0, base_filename=/tmp/glogs/test-cleaner.28f8271ff892.root.log.INFO., filename_extension=
lingbin-debugging[Run:1389]. dirs=[/tmp/glogs]
lingbin-debugging[GetOverdueLogNames:1416]. Into GetOverdueLogNames. days=3, log_directory=/tmp/glogs, base_filename=/tmp/glogs/test-cleaner.28f8271ff892.root.log.INFO., filename_extension=
lingbin-debugging[GetOverdueLogNames:1440]. Checking filepath=test-cleaner.28f8271ff892.root.log.INFO.20231001-000000.65295, possible_dir_delim=/, log_directory[log_directory.size() - 1]=s
lingbin-debugging[IsLogFromCurrentProject:1498]. Into IsLogFromCurrentProject(). filepath=test-cleaner.28f8271ff892.root.log.INFO.20231001-000000.65295, base_filename=/tmp/glogs/test-cleaner.28f8271ff892.root.log.INFO., filename_extension=
lingbin-debugging[IsLogFromCurrentProject:1527]. cleaned_base_filename=[/tmp/glogs/test-cleaner.28f8271ff892.root.log.INFO.]
lingbin-debugging[IsLogFromCurrentProject:1533]. 'filepath' does not contain 'cleaned_base_filename', return
# ------------ FLAGS_log_dir=/tmp/glogs/ ----------------
lingbin-debugging[Run:1383]. Into LogCleaner::Run(). base_filename_selected=0, base_filename=/tmp/glogs//test-cleaner.28f8271ff892.root.log.INFO., filename_extension=
lingbin-debugging[Run:1389]. dirs=[/tmp/glogs/]
lingbin-debugging[GetOverdueLogNames:1416]. Into GetOverdueLogNames. days=3, log_directory=/tmp/glogs/, base_filename=/tmp/glogs//test-cleaner.28f8271ff892.root.log.INFO., filename_extension=
lingbin-debugging[GetOverdueLogNames:1440]. Checking filepath=test-cleaner.28f8271ff892.root.log.INFO.20231001-000000.65295, possible_dir_delim=/, log_directory[log_directory.size() - 1]=/
lingbin-debugging[GetOverdueLogNames:1462]. modified filepath=/tmp/glogs/test-cleaner.28f8271ff892.root.log.INFO.20231001-000000.65295
lingbin-debugging[IsLogFromCurrentProject:1498]. Into IsLogFromCurrentProject(). filepath=/tmp/glogs/test-cleaner.28f8271ff892.root.log.INFO.20231001-000000.65295, base_filename=/tmp/glogs//test-cleaner.28f8271ff892.root.log.INFO., filename_extension=
lingbin-debugging[IsLogFromCurrentProject:1527]. cleaned_base_filename=[/tmp/glogs/test-cleaner.28f8271ff892.root.log.INFO.]
lingbin-debugging[GetOverdueLogNames:1469]. Checking filepath=/tmp/glogs/test-cleaner.28f8271ff892.root.log.INFO.20231001-000000.65295, isFromCurrProject=1
lingbin-debugging[IsLogLastModifiedOver:1597]. filepath=/tmp/glogs/test-cleaner.28f8271ff892.root.log.INFO.20231001-000000.65295, last_modified_time=1696089600, current_time=1696915269, difftime=825669, configed_days=3
lingbin-debugging[GetOverdueLogNames:1476]. Checking filepath=/tmp/glogs/test-cleaner.28f8271ff892.root.log.INFO.20231001-000000.65295, isLogLastModifiedOver=1
lingbin-debugging[Run:1406]. Deleted /tmp/glogs/test-cleaner.28f8271ff892.root.log.INFO.20231001-000000.65295
The biggest difference between the two is the value of filePath in line 6 above, which is also the reason for this bug.
# ------------ FLAGS_log_dir=/tmp/glogs (No '/' at the end)----------------
Into IsLogFromCurrentProject(). filepath=test-cleaner.28f8271ff892.root.log.INFO.20231001-000000.65295
VS
# ------------ FLAGS_log_dir=/tmp/glogs/ ----------------
Into IsLogFromCurrentProject(). filepath=/tmp/glogs/test-cleaner.28f8271ff892.root.log.INFO.20231001-000000.65295,
Short summary: here filePath
should be a string with a path, not just the filename.
from glog.
After further exploring the code, I found that the problem came from the following places:
Lines 1430 to 1434 in b58718f
When FLAGS_log_dir=/tmp/glogs
, the last character in log_directory="/tmp/glogs"
is not '/'
, so the if condition
here is not satisfied, and finally filepath
will only contain A filename without a "path". In subsequent comparisons, it will be returned directly in the following line.
Lines 1470 to 1473 in b58718f
In order to solve this problem, we only need to modify the if
statement above: we should ensure that filepath
must eventually contain the log_directory
part. That is to say: if log_directory
is not empty, but the last character is not '/'
, then add one explicitly instead of ignoring it directly.
if (!log_directory.empty()) {
if (std::find(possible_dir_delim, dir_delim_end,
log_directory[log_directory.size() - 1]) == dir_delim_end) {
filepath = log_directory + '/' + filepath;
} else {
filepath = log_directory + filepath;
}
}
I will follow https://github.com/google/glog#how-to-contribute and submit a PR as soon as possible.
from glog.
Update:
With the fix above, my code will work correctly, but the unit test cleanup_with_absolute_prefix
will fail with some debug information as follows:
lingbin-debugging[Run:1383]. Into LogCleaner::Run(). base_filename_selected=1, base_filename=test_cleanup_, filename_extension=.barfoo
lingbin-debugging[Run:1389]. dirs=['.']
lingbin-debugging[GetOverdueLogNames:1416]. Into GetOverdueLogNames. days=0, log_directory=., base_filename=test_cleanup_, filename_extension=.barfoo
lingbin-debugging[GetOverdueLogNames:1440]. Checking filepath=test_cleanup_20231010-221021.34375.barfoo, possible_dir_delim=/, log_directory[log_directory.size() - 1]=.
lingbin-debugging[GetOverdueLogNames:1450]. modified filepath=./test_cleanup_20231010-221021.34375.barfoo
lingbin-debugging[IsLogFromCurrentProject:1498]. Into IsLogFromCurrentProject(). filepath=./test_cleanup_20231010-221021.34375.barfoo, base_filename=test_cleanup_, filename_extension=.barfoo
lingbin-debugging[IsLogFromCurrentProject:1527]. cleaned_base_filename=[test_cleanup_]
lingbin-debugging[IsLogFromCurrentProject:1533]. 'filepath' does not contain 'cleaned_base_filename', return
lingbin-debugging[GetOverdueLogNames:1469]. Checking filepath=./test_cleanup_20231010-221021.34375.barfoo, isFromCurrProject=0
What needs to be noted here is that base_filename
no longer contains "directory" information, but a value directly specified by the user. (In my reproduction code above, google::SetLogDestination()
is not used, base_filename
will contain "directory").
In this unit test, the following code is included:
google::SetLogDestination(GLOG_INFO, "test_cleanup_");
After further exploration, I found that there are some difficulties in our current processing of directories, especially the judgment of whether it ends with '/'
, such as the following code:
Lines 1388 to 1399 in b58718f
Whether FLAGS_log_dir
ends with `'/'' is not handled consistently.
- In line L1395, it is expected that
dirs
contains'/'
(becausepos+1
is used); - but in line L1397,
'.'
is used (it is not written as'./'
, that is, it will not end with'/'
); - In line L1389, whether the path added to
dirs
ends with'/'
depends entirely on the user's own command line options.
However, regardless of the processing method here, I suggest that we should normalize the input value of FLAGS_log_dir
when the user inputs. That is, in GetLoggingDirectories()
, first ensure that the directory must end with '/'
, which can greatly reduce the trivial lines and complexity of subsequent processing.
This is exactly what I modified in the final PR I submitted. The problem I encountered will also be solved, and all existing unit tests will succeed.
from glog.
Related Issues (20)
- How to encrypt logs HOT 1
- [proposal] Provide pre-defined JSON log sink in glog HOT 2
- [Emscripten][Ubuntu 22.04.3 LTS] Use of undeclared identifier 'SYS_write' HOT 3
- building phase in Ubuntu 23.10 : /usr/bin/ld: /usr/local/lib/libgflags.a(gflags.cc.o): relocation R_X86_64_PC32 against symbol `stderr@@GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPI HOT 3
- windows mingw64 compile fail HOT 4
- error in including <glog/logging.h> after installing glog according to the official tutorial HOT 2
- namespace "google" has no member "InitGoogleLogging" HOT 1
- FetchContent support HOT 4
- Customizing the Log Line Prefix HOT 2
- Can not build app integrating glog using CMake . HOT 3
- Using call_once could lead to infinite loop in fatal signal handler ? HOT 9
- bazel compilation with emscripten failed HOT 3
- HAVE_SYMBOLIZE missing on linux with bazel
- How do you solve this problem during installation? HOT 1
- Apply max_log_file constraint when timestamp_in_log_file=false
- Flag GLOG_v failed to set in Mac environment and resulting in incorrect printing of logs HOT 1
- why compile can not pass.it ocurrs the errors as follow。 HOT 3
- Cannot log to logcat on Android since 0.7.0 HOT 1
- Abseil or glog: what's the maintenance status? HOT 1
- Cmake --build build Error HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from glog.