]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: log: support optional 'profile <log_profile_name>' argument to do-log action
authorAurelien DARRAGON <adarragon@haproxy.com>
Thu, 19 Mar 2026 11:43:00 +0000 (12:43 +0100)
committerAurelien DARRAGON <adarragon@haproxy.com>
Fri, 20 Mar 2026 10:42:48 +0000 (11:42 +0100)
We anticipated that the do-log action should be expanded with optional
arguments at some point. Now that we heard of multiple use-cases
that could be achieved with do-log action, but that are limitated by the
fact that all do-log statements inherit from the implicit log-profile
defined on the logger, we need to provide a way for the user to specify
that custom log-profile that could be used per do-log actions individually

This is what we try to achieve in this commit, by leveraging the
prerequisite work performed by the last 2 commits.

doc/configuration.txt
include/haproxy/action-t.h
src/log.c

index 3e1df8acd48455fadf7931d0a6ec6f9827c00fcd..a1257973bfc83c4a5a0cc0444534f3dacf8e810e 100644 (file)
@@ -15382,15 +15382,14 @@ disable-l7-retry
   reason than a connection failure. This can be useful for example to make
   sure POST requests aren't retried on failure.
 
-do-log
+do-log [profile <log_profile>]
   Usable in:  QUIC Ini|    TCP RqCon| RqSes| RqCnt| RsCnt|    HTTP Req| Res| Aft
                     X |          X  |   X  |   X  |   X  |          X |  X |  X
 
   This action manually triggers a log emission on the proxy. This means
   log options on the proxy will be considered (including formatting options
   such as "log-format"), but it will not interfere with the logs automatically
-  generated by the proxy during transaction handling. It currently doesn't
-  support any argument, though extensions may appear in future versions.
+  generated by the proxy during transaction handling.
 
   Using "log-profile", it is possible to precisely describe how the log should
   be emitted for each of the available contexts where the action may be used.
@@ -15400,15 +15399,28 @@ do-log
 
   Also, they will be properly reported when using "%OG" logformat alias.
 
+  Optional "profile" argument may be used to specify the name of a log-profile
+  section that should be used for this do-log action specifically instead of
+  the one associated to the current logger that applies by default.
+
   Example:
-    log-profile myprof
+    log-profile my-dft-prof
       on tcp-req-conn format "Connect: %ci"
 
+    log-profile my-local-prof
+      on tcp-req-conn format "Local Connect: %ci"
+
     frontend myfront
-      log stdout format rfc5424 profile myprof local0
+      log stdout format rfc5424 profile my-dft-prof local0
       log-format "log generated using proxy logformat, from '%OG'"
-      tcp-request connection do-log             #uses special log-profile format
-      tcp-request content do-log                #uses proxy logformat
+      acl local src 127.0.0.1
+      # on connection use either log-profile from the logger (my-dft-prof) or
+      # explicit my-local-prof if source ip is localhost
+      tcp-request connection do-log if !local
+      tcp-request connection do-log profile my-local-prof if local
+      # on content use proxy logformat, since no override was specified
+      # in my-dft-prof
+      tcp-request content do-log
 
 do-resolve(<var>,<resolvers>[,ipv4|ipv6]) <expr>
   Usable in:  QUIC Ini|    TCP RqCon| RqSes| RqCnt| RsCnt|    HTTP Req| Res| Aft
index c10360e2bed36c3f4ebef2e8488a6a5456d673f4..984f55c64521cba75c300917387aba425264d636 100644 (file)
@@ -198,6 +198,11 @@ struct act_rule {
                        struct server *srv; /* target server to attach the connection */
                        struct sample_expr *name; /* used to differentiate idle connections */
                } attach_srv; /* 'attach-srv' rule */
+               struct {
+                       enum log_orig_id orig;
+                       char *profile_name;
+                       struct log_profile *profile;
+               } do_log; /* 'do-log' action */
                struct {
                        int value;
                        struct sample_expr *expr;
index 0a3d32d8d5721877824d8794329a315566ca930f..a544ea18cdbe37422df3cf5b3ec07244f9ecf1d3 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -6927,24 +6927,87 @@ static int px_parse_log_steps(char **args, int section_type, struct proxy *curpx
 static enum act_return do_log_action(struct act_rule *rule, struct proxy *px,
                                      struct session *sess, struct stream *s, int flags)
 {
+       struct process_send_log_ctx ctx;
+
        /* do_log() expects valid session pointer */
        BUG_ON(sess == NULL);
 
-       do_log(sess, s, log_orig(rule->arg.expr_int.value, LOG_ORIG_FL_NONE));
+       ctx.origin = log_orig(rule->arg.do_log.orig, LOG_ORIG_FL_NONE);
+       ctx.sess = sess;
+       ctx.stream = s;
+       ctx.profile = rule->arg.do_log.profile;
+
+       do_log_ctx(&ctx);
        return ACT_RET_CONT;
 }
 
-/* Parse a "do_log" action. It doesn't take any argument
+static int do_log_action_check(struct act_rule *rule, struct proxy *px, char **err)
+{
+       if (rule->arg.do_log.profile_name) {
+               struct log_profile *prof;
+
+               prof = log_profile_find_by_name(rule->arg.do_log.profile_name);
+               if (!prof) {
+                       memprintf(err, "do-log action: profile '%s' is invalid", rule->arg.do_log.profile_name);
+                       ha_free(&rule->arg.do_log.profile_name);
+                       return 0;
+               }
+
+               ha_free(&rule->arg.do_log.profile_name);
+
+               if (!log_profile_postcheck(px, prof, err)) {
+                       memprintf(err, "do-log action on %s %s uses incompatible log-profile '%s': %s",  proxy_type_str(px), px->id, prof->id, *err);
+                       return 0;
+               }
+               rule->arg.do_log.profile = prof;
+       }
+       return 1; // success
+}
+
+static void do_log_action_release(struct act_rule *rule)
+{
+       ha_free(&rule->arg.do_log.profile_name);
+}
+
+
+/* Parse a "do_log" action. It takes optional "log-profile" argument to
+ * specifically use a given log-profile when generating the log message
+ *
  * May be used from places where per-context actions are usually registered
  */
 enum act_parse_ret do_log_parse_act(enum log_orig_id id,
                                     const char **args, int *orig_arg, struct proxy *px,
                                     struct act_rule *rule, char **err)
 {
+       int cur_arg = *orig_arg;
+
        rule->action_ptr = do_log_action;
        rule->action = ACT_CUSTOM;
-       rule->release_ptr = NULL;
-       rule->arg.expr_int.value = id;
+       rule->check_ptr = do_log_action_check;
+       rule->release_ptr = do_log_action_release;
+       rule->arg.do_log.orig = id;
+
+       while (*args[*orig_arg]) {
+               if (!strcmp(args[*orig_arg], "profile")) {
+                       if (!*args[*orig_arg + 1]) {
+                               memprintf(err,
+                                         "action '%s': 'profile' expects argument.",
+                                         args[cur_arg-1]);
+                               return ACT_RET_PRS_ERR;
+                       }
+                       rule->arg.do_log.profile_name = strdup(args[*orig_arg + 1]);
+                       if (!rule->arg.do_log.profile_name) {
+                               memprintf(err,
+                                         "action '%s': memory error when setting 'profile'",
+                                          args[cur_arg-1]);
+                               return ACT_RET_PRS_ERR;
+                       }
+                       *orig_arg += 2;
+               }
+               else
+                       break;
+       }
+
        return ACT_RET_PRS_OK;
 }