-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
in_tail: Use inode for key of TailWatcher when follow_inodes #4185
Conversation
Thanks for your contribution! DCO check is failed: https://github.com/fluent/fluentd/pull/4185/checks?check_run_id=13780778605
Could you fix your name in the - KatuyaKawakami
+ Katuya Kawakami |
It's resolved, thanks! |
It seems that CI stalls on all platforms. |
Thank you for commenting. By the way, please let me explain why we didn't take care of To fix this unexpected file close issue, we have to modify the tail plugin to create a tail list with hash values generated by inode numbers. In our understanding, Please let me know if our understanding is wrong. |
$ bundle install
$ bundle exec rake test TEST=test/plugin/test_in_tail.rb TESTOPTS="-v"
...
TailInputTest:
test_EACCES: .: (0.513357)
...
group rules line limit resolution:
test: valid: .: (0.003195)
inode_processing:
test_should_close_watcher_after_rotate_wait: The cause is diff --git a/lib/fluent/plugin/in_tail.rb b/lib/fluent/plugin/in_tail.rb
index 71d1be9b..27ee48da 100644
--- a/lib/fluent/plugin/in_tail.rb
+++ b/lib/fluent/plugin/in_tail.rb
@@ -443,7 +443,11 @@ module Fluent::Plugin
return
end
- @tails[path] = tw
+ if @follow_inodes
+ @tails[target_info.ino] = tw
+ else
+ @tails[path] = tw
+ end
tw.on_notify
end
diff --git a/test/plugin/test_in_tail.rb b/test/plugin/test_in_tail.rb
index b1e28fc9..37fbf950 100644
--- a/test/plugin/test_in_tail.rb
+++ b/test/plugin/test_in_tail.rb
@@ -2156,13 +2156,13 @@ class TailInputTest < Test::Unit::TestCase
target_info = create_target_info("#{@tmp_dir}/tail.txt")
mock.proxy(Fluent::Plugin::TailInput::TailWatcher).new(target_info, anything, anything, true, true, anything, nil, anything, anything).once
d.run(shutdown: false)
- assert d.instance.instance_variable_get(:@tails)[target_info.path]
+ assert d.instance.instance_variable_get(:@tails)[target_info.ino]
Timecop.travel(now + 10) do
d.instance.instance_eval do
- sleep 0.1 until @tails[target_info.path] == nil
+ sleep 0.1 until @tails[target_info.ino] == nil
end
- assert_nil d.instance.instance_variable_get(:@tails)[target_info.path]
+ assert_nil d.instance.instance_variable_get(:@tails)[target_info.ino]
end
d.instance_shutdown
end Even though with above fix, some more other tests are failed. |
Thank you for your comment and analysis. |
Basically your thought is reasonable, we should make
Even though in |
Sure, I rewrite commit message and comment of this PR.
I revised and rewrite the codes. |
Thanks for this fix! I'm seeing this too. |
As I've described in #3614 (comment), I'm now positive to merge this. |
To me, this looks like a reasonable fix to address the problem of one scenario (#3614 (comment)). Though I think @ashie has a better grasp of the concerns of this fix, my concern is this code. fluentd/lib/fluent/plugin/in_tail.rb Line 525 in 84b1b49
Why do we need this |
Hmm? Perhaps I'm confusing something... |
Whey the key for |
Yes, ashie-san is correct. When using path as a key of "@tail", the key would be the same between a rotated log file and a new log file. |
Thanks. I can imagine that, but something seems inconsistent to me... The current implementation of managing For It should be symmetrical whether we use the paths or the inodes as the keys for |
If we use the inodes for the keys of Otherwise, it's not symmetrical. |
Sorry, maybe I'm saying something wrong... |
Now I understand the cause of this asymmetry. |
I have still some concerns about changing the key...
Given this, it does not seem wrong to manage watchers by using the paths as the keys, regardless of It seems to me that the problem exists in |
You are right, collecting TailWatchers is done by path by refresh_watcher (according to I think changing the key is just for comprehensibility of the code. |
Sorry, I couldn't understand what is "asymmetry". Please let me explain my idea. For example, let's consider the case of that fluentd watches "/var/log/0.log". When using a path as a key of
The old
To change the key from path to inode is the most important point of this fix. We believe that the issue is caused by using the same The path is the same even after the rotation, but the inode is changed.
Our idea is to use inode as a key of all functions of in_tail.rb when |
Thanks, everyone. I am wondering if the key of I'm still not sure, but I commented in #3614 (comment) on what I thought was the possible alternative solution. |
Ah, sorry, Because tail watchers are collected according to |
Yes, I too think so. |
Sorry, I just wanted to say that A: The current implementation:
B: This PR's implementation:
C: State that I feel is symmetrical to A. (In this case, we don't need to worry about the deletion.)
The important point is that the current B will certainly solve #3614 problem partially, but if we only consider the update process of |
Thanks to this PR and #4191, I am starting to see problems that I didn't understand before. |
Thank you for the explanations.
I couldn't find a code that fluentd passes But I feel that it's not weird even if we use inode as the key even though
To change the key of
Currently I haven't found any negative side-effect of #4191. But #4191 is a last catch fix as @garyzjq san said. In our opinion, to use path as the key of
In
In
To match the behavior of Of course I can understand that a big code change isn't preferred to avoid regressions. |
Oh, somehow, the first TailWatcher is not detached and not unwatched. We should check if there is a possibility that the results change depending on the timing... |
The following "path" should be changed to "key" or something for avoiding confusion. (We didn't notice this when posting the patch in past...) fluentd/lib/fluent/plugin/in_tail.rb Lines 491 to 492 in 719cdee
Thank you for rebasing our patch. We will recheck this and write here if we found any issue. |
Thanks! If you find any issue, feel free to fix it! |
Just FYI. |
Thanks for your check! I want to conclude by the end of this week. |
I'm also confusing why this commit can solve #4221 . Concern1: Really is it ok if
|
# When follow_inodes is true, it's not cleaned up by refresh_watcher. |
Maybe it means that stop_watchers()
isn't called by refresh_watchers()
when follow_inodes is true.
I considered why it isn't called.
expand_paths()
creates a hash list. The key will be inode when follow_inodes is true.
fluentd/lib/fluent/plugin/in_tail.rb
Line 342 in 155bdca
hash[target_info.ino] = target_info
=> If inode-1 of a deleted file(log-A) was reused with another new log file(log-B), log-B's TailWatcher will be stored in to itshash[inode-1]
.existence_path()
also creates a hash list. The key will be inode when follow_inodes is true.
fluentd/lib/fluent/plugin/in_tail.rb
Line 357 in 155bdca
hash[tw.ino] = TargetInfo.new(tw.path, tw.ino)
=> log-A's TailWatcher will be stored into itshash[inode-1]
- Compare existence_path's hash list and expand_paths's hash list to create
unwatched_hash
fluentd/lib/fluent/plugin/in_tail.rb
Line 380 in 155bdca
unwatched_hash = existence_paths_hash.reject {|key, value| target_paths_hash.key?(key)}
=> log-A's TailWatcher won't be added tounwatched_hash
since we can find the same inode-1 key from expand_paths's hash list. But the entry of expand_paths's hash list is for log-B. This is not for log-A.
==> Cannot callstop_watchers()
for log-A.
==> Cannot callstart_watchers()
for log-B due to the same reason.
So we need to detach log-A's TailWatcher in update_watcher()
instead of stop_watchers()
.
(refresh_watchers()
becomes able to call start_watchers()
for log-B after the detaching)
How can we solve the conflict between Concern1 and 2?
We can ignore Concern1 if the expected behavior of the tail plugin is that TailWatcher object should be recreated every time the log file path got changed.
However, to avoid reading the same log twice, we should tell the previous position to the new TailWatcher object.
But where is the code to do that?
Isn't the plan B of #4221 (comment) still needed even after we use inode as a key?
Thanks for your considering it!
I think It is OK.
Your assumptions seem mostly correct. This is because
This happens because the key of
These lines load the position from the pos file. fluentd/lib/fluent/plugin/in_tail.rb Line 435 in e20697e
fluentd/lib/fluent/plugin/in_tail.rb Line 509 in e20697e
|
@daipom san, Thank you for your explanation!
I was worried if
Ok. We can refer to the previous position by using inode because we set follow_inodes to true. My current concern is that the previous position might have been cleared by the following line.
The fluentd/lib/fluent/plugin/in_tail.rb Lines 504 to 521 in e20697e
Isn't the entry of the pos file cleared before test.log.1 is newly found? |
Yes! |
Instead of #4221, I would like to fix it as follows:
|
Thank you too for all your help! |
I'm thinking about the correct specifications. We need to add the fix. |
Sorry, I said I wanted to stop watching in |
I fixed the concerns. I think this is ideal behavior. |
Sorry, there was an easy mistake in the testcases. |
Sorry, one test is still failing... |
I'm sorry again 😢 fluentd/lib/fluent/plugin/in_tail.rb Line 518 in ce898dd
|
I believe the current logic is the ideal behavior for |
The following is my idea, although there might be still some overlooks...
The base ideas of this are:
|
This may improve the maintainability. Note: Regardless of `follow_inodes`, both path or inode is acceptable for the key of `tails`. It is not wrong that the current logic uses `path` for the key. Perhaps we don't need to use different keys depending on `follow_inodes`. We can always use inode for the key. (Future work) Signed-off-by: Katuya Kawakami <[email protected]> Signed-off-by: Masaki Hatada <[email protected]> Co-authored-by: Daijiro Fukuda <[email protected]>
I thought this PR could nicely solve the current problem of unwatching (#4221), but it was wrong. |
I'm very sorry for rebasing this branch again and again. After all, the only change I made is to ensure that the old TailWatcher is removed from fluentd/lib/fluent/plugin/in_tail.rb Line 518 in 45b193f
(It was done in |
@masaki-hatada @kattz-kawa I'm very sorry for troubling you all. Thanks for your suggestion to solve the problem of unwatching: #4185 (comment) Maybe that problem should be handled separately from this PR. |
For now we don't have plan changing the key from path to inode, so I close this. |
Which issue(s) this PR fixes:
Partially fixes #3614 (follow_inode true case)
What this PR does / why we need it:
Thank you for reading to the great developer's!
This PR is fixed for unexpected file close after logs rotate in fluentd v1.16.1.
I found the #3614 's reproducer.
Before applying this patch, fluentd cause unexpected file close after logs rotate every hour on my reproducer.
After applying this patch, fluentd does not cause it on my reproducer.
I have been running testing a long time.
Docs Changes:
Release Note: