From 39ad31904a7d5b80355625794f4f6a9dfa39e81f Mon Sep 17 00:00:00 2001 From: "jie.yang" Date: Thu, 12 Mar 2026 13:21:22 +0800 Subject: [PATCH] in_tail: fix DB.compare_filename mismatch when monitoring symlinks When DB.compare_filename is enabled and the monitored path is a symbolic link (e.g. glog-style logging), the filename comparison in flb_tail_target_file_name_cmp() always fails on restart. The database stores the symlink path (file->name), but the comparison checks against file->real_name which is resolved via the file descriptor to the actual target path. For symlinks such as: app.INFO -> app.INFO.20250303-120000.12345 the basenames differ ("app.INFO" vs "app.INFO.20250303-120000.12345"), so db_file_exists() returns FLB_FALSE. The existing entry is then deleted as stale and re-inserted with offset 0, causing a full re-read of the file and duplicate log ingestion. Fix this by adding a fallback comparison against file->name (the original glob-matched path) when the real_name comparison fails. This correctly handles symlinks while still protecting against inode reuse for regular files. Signed-off-by: jie.yang --- plugins/in_tail/tail_file.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/plugins/in_tail/tail_file.h b/plugins/in_tail/tail_file.h index cee851af8b1..cb739944ba3 100644 --- a/plugins/in_tail/tail_file.h +++ b/plugins/in_tail/tail_file.h @@ -94,6 +94,20 @@ static inline int flb_tail_target_file_name_cmp(char *name, base_b = basename(name_b); ret = _stricmp(base_a, base_b); + + /* + * Fallback: when monitoring symlinks the DB stores the symlink path + * (file->name) while real_name resolves to the target. Compare + * against the original path so the entry is still recognised. + */ + if (ret != 0 && file->name) { + flb_free(name_b); + name_b = flb_strdup(file->name); + if (name_b) { + base_b = basename(name_b); + ret = _stricmp(base_a, base_b); + } + } #else name_b = flb_strdup(file->real_name); if (!name_b) { @@ -103,6 +117,20 @@ static inline int flb_tail_target_file_name_cmp(char *name, } base_b = basename(name_b); ret = strcmp(base_a, base_b); + + /* + * Fallback: when monitoring symlinks the DB stores the symlink path + * (file->name) while real_name resolves to the target. Compare + * against the original path so the entry is still recognised. + */ + if (ret != 0 && file->name) { + flb_free(name_b); + name_b = flb_strdup(file->name); + if (name_b) { + base_b = basename(name_b); + ret = strcmp(base_a, base_b); + } + } #endif out: