From 50fb37e5fed1d56d40e3164cff864caf2ebcf51e Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Wed, 4 Mar 2026 11:03:01 +0100 Subject: [PATCH] MINOR: stream: Display the currently running filter per channel in stream dump Since the 3.1, when stream's info are dump, it is possible to print the yielding filter on each channel, if any. It was useful to detect buggy filter on spinning loop. But it is not possible to detect a filter consuming too much CPU per-execution. We can see a filter was executing in the backtrace reported by the watchdog, but we are unable to spot the specific one. Thanks to this patch, it is now possible. When a dump is emitted, the running or yield filters on each channel are now displayed with their current state (RUNNING or YIELDING). This patch could be backported as far as 3.2 because it could be useful to spot issues. But the filter API was slightly refactored in 3.4, so this patch should be adapted. --- src/filters.c | 13 ++++++++----- src/stream.c | 10 ++++++---- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/filters.c b/src/filters.c index 9775348bc..842150fff 100644 --- a/src/filters.c +++ b/src/filters.c @@ -69,15 +69,16 @@ static inline struct filter *resume_filter_list_start(struct stream *strm, struc if (chn->flt.current) { filter = chn->flt.current; - chn->flt.current = NULL; if (!(chn_prod(chn)->flags & SC_FL_ERROR) && !(chn->flags & (CF_READ_TIMEOUT|CF_WRITE_TIMEOUT))) { (strm)->waiting_entity.type = STRM_ENTITY_NONE; (strm)->waiting_entity.ptr = NULL; } } - else + else { filter = flt_list_start(strm, chn); + chn->flt.current = filter; + } return filter; } @@ -85,22 +86,24 @@ static inline struct filter *resume_filter_list_start(struct stream *strm, struc static inline struct filter *resume_filter_list_next(struct stream *strm, struct channel *chn, struct filter *filter) { - /* simply an alias to flt_list_next() */ - return flt_list_next(strm, chn, filter); + filter = flt_list_next(strm, chn, filter); + chn->flt.current = filter; + return filter; } static inline void resume_filter_list_break(struct stream *strm, struct channel *chn, struct filter *filter, int ret) { + chn->flt.current = NULL; if (ret == 0) { strm->waiting_entity.type = STRM_ENTITY_FILTER; strm->waiting_entity.ptr = filter; + chn->flt.current = filter; } else if (ret < 0) { strm->last_entity.type = STRM_ENTITY_FILTER; strm->last_entity.ptr = filter; } - chn->flt.current = filter; } /* List head of all known filter keywords */ diff --git a/src/stream.c b/src/stream.c index b72788ac0..3a0c6b806 100644 --- a/src/stream.c +++ b/src/stream.c @@ -3801,8 +3801,9 @@ static void __strm_dump_to_buffer(struct buffer *buf, const struct show_sess_ctx if (HAS_FILTERS(strm) && strm->req.flt.current) { const struct filter *flt = strm->req.flt.current; - chunk_appendf(buf, "%s current_filter=%p (id=\"%s\" flags=0x%x pre=0x%x post=0x%x) \n", pfx, - flt, flt->config->id, flt->flags, flt->pre_analyzers, flt->post_analyzers); + chunk_appendf(buf, "%s current_filter=%p (id=\"%s\" flags=0x%x pre=0x%x post=0x%x %s) \n", pfx, + flt, flt->config->id, flt->flags, flt->pre_analyzers, flt->post_analyzers, + (flt == strm->waiting_entity.ptr) ? "YIELDING" : "RUNNING"); } chunk_appendf(buf, @@ -3834,8 +3835,9 @@ static void __strm_dump_to_buffer(struct buffer *buf, const struct show_sess_ctx if (HAS_FILTERS(strm) && strm->res.flt.current) { const struct filter *flt = strm->res.flt.current; - chunk_appendf(buf, "%s current_filter=%p (id=\"%s\" flags=0x%x pre=0x%x post=0x%x) \n", pfx, - flt, flt->config->id, flt->flags, flt->pre_analyzers, flt->post_analyzers); + chunk_appendf(buf, "%s current_filter=%p (id=\"%s\" flags=0x%x pre=0x%x post=0x%x %s) \n", pfx, + flt, flt->config->id, flt->flags, flt->pre_analyzers, flt->post_analyzers, + (flt == strm->waiting_entity.ptr) ? "YIELDING" : "RUNNING"); } if (strm->current_rule_list && strm->current_rule) {