Richard W.M. Jones
2020-Dec-20 12:23 UTC
[Libguestfs] [PATCH nbdkit 0/2 PROPOSAL] log: Add logscript feature.
This patch series isn't finished - at a minimum it needs tests. As you may have seen I've been fiddling around with nbdkit-log-filter, generally tidying up the code. However the big change I want to make is to allow a script to be triggered from logging events. The two patches that follow show where this is going. The first patch cleans up the log format itself so that we consistently use shell (actually _bash_) quoting for the parameters that we print in the log file. Note this introduces some minor incompatibilities. This allows the second patch which implements the logscript feature by passing the same parameters directly to an external script. Rich.
Richard W.M. Jones
2020-Dec-20 12:23 UTC
[Libguestfs] [PATCH nbdkit 1/2] log: Use strict shell quoting for every parameter displayed in the log file.
This is not fully backwards compatible, although the changes are minor: * Lists returned by ListExports and Extents use the array format that can be parsed by bash, eg: Extents id=1 extents=(0x0 0x8000 "hole,zero" 0x8000 0x8000 "") return=0 * Errors are returned as separate error= parameters, and simplified, eg: ...Read id=1 return=-1 error=EINVAL * Strings are quoted properly in all circumstances. This commit also updates the documentation and adds more tests. --- filters/log/nbdkit-log-filter.pod | 8 ++-- tests/Makefile.am | 11 ++++- filters/log/log.c | 69 +++++++++++++++++++++---------- filters/log/output.c | 30 +++++--------- tests/test-log-error.sh | 62 +++++++++++++++++++++++++++ tests/test-log-extents.sh | 59 ++++++++++++++++++++++++++ 6 files changed, 193 insertions(+), 46 deletions(-) diff --git a/filters/log/nbdkit-log-filter.pod b/filters/log/nbdkit-log-filter.pod index c36b3d35..abf52e18 100644 --- a/filters/log/nbdkit-log-filter.pod +++ b/filters/log/nbdkit-log-filter.pod @@ -62,10 +62,10 @@ An example logging session of a client that requests an export list before performing a single successful read is: 2020-08-06 02:07:23.080415 ListExports id=1 readonly=0 tls=0 ... - 2020-08-06 02:07:23.080502 ...ListExports id=1 exports=[""] return=0 - 2020-08-06 02:07:23.080712 connection=1 Connect export='' tls=0 size=0x400 write=1 flush=1 rotational=0 trim=1 zero=2 fua=2 extents=1 cache=2 fast_zero=1 + 2020-08-06 02:07:23.080502 ...ListExports id=1 exports=("") return=0 + 2020-08-06 02:07:23.080712 connection=1 Connect export="" tls=0 size=0x400 write=1 flush=1 rotational=0 trim=1 zero=2 fua=2 extents=1 cache=2 fast_zero=1 2020-08-06 02:07:23.080907 connection=1 Read id=1 offset=0x0 count=0x200 ... - 2020-08-06 02:07:23.080927 connection=1 ...Read id=1 return=0 (Success) + 2020-08-06 02:07:23.080927 connection=1 ...Read id=1 return=0 2020-08-06 02:07:23.081255 connection=1 Disconnect transactions=1 All lines start with a timestamp in C<YYYY-MM-DD HH:MM:ZZ.MS> format. @@ -82,6 +82,8 @@ value. Because nbdkit handles requests in parallel different requests may be intermingled. Use the C<id=N> field for correlation, it is unique per connection. +Strings and lists are shell-quoted. + =head1 FILES =over 4 diff --git a/tests/Makefile.am b/tests/Makefile.am index 562a6209..a6be3938 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1495,8 +1495,15 @@ TESTS += test-limit.sh EXTRA_DIST += test-limit.sh # log filter test. -TESTS += test-log.sh -EXTRA_DIST += test-log.sh +TESTS += \ + test-log.sh \ + test-log-error.sh \ + test-log-extents.sh \ + $(NULL) +EXTRA_DIST += \ + test-log.sh \ + test-log-extents.sh \ + $(NULL) # nofilter test. TESTS += test-nofilter.sh diff --git a/filters/log/log.c b/filters/log/log.c index 1c67a95e..37b36498 100644 --- a/filters/log/log.c +++ b/filters/log/log.c @@ -35,6 +35,7 @@ #include <stdio.h> #include <stdlib.h> #include <stdint.h> +#include <stdbool.h> #include <string.h> #include <stdarg.h> #include <errno.h> @@ -165,24 +166,25 @@ log_list_exports (nbdkit_next_list_exports *next, void *nxdata, } else { FILE *fp; - CLEANUP_FREE char *exports_str = NULL; + CLEANUP_FREE char *str = NULL; size_t i, n, len = 0; - fp = open_memstream (&exports_str, &len); + fp = open_memstream (&str, &len); if (fp != NULL) { + fprintf (fp, "exports=("); n = nbdkit_exports_count (exports); for (i = 0; i < n; ++i) { struct nbdkit_export e = nbdkit_get_export (exports, i); if (i > 0) - fprintf (fp, ", "); + fprintf (fp, " "); shell_quote (e.name, fp); } - + fprintf (fp, ") return=0"); fclose (fp); + leave (NULL, id, "ListExports", "%s", str); } - - leave (NULL, id, "ListExports", "exports=[%s] return=0", - exports_str ? exports_str : "(null)"); + else + leave (NULL, id, "ListExports", ""); } return r; } @@ -246,6 +248,9 @@ static int log_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, int readonly) { + FILE *fp; + CLEANUP_FREE char *str = NULL; + size_t len = 0; struct handle *h = handle; const char *exportname = h->exportname; int64_t size = next_ops->get_size (nxdata); @@ -263,9 +268,21 @@ log_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void *handle, e < 0 || c < 0 || Z < 0) return -1; - print (h, "Connect", "export='%s' tls=%d size=0x%" PRIx64 " write=%d " - "flush=%d rotational=%d trim=%d zero=%d fua=%d extents=%d cache=%d " - "fast_zero=%d", exportname, h->tls, size, w, f, r, t, z, F, e, c, Z); + fp = open_memstream (&str, &len); + if (fp) { + fprintf (fp, "export="); + shell_quote (exportname, fp); + fprintf (fp, + " tls=%d size=0x%" PRIx64 " write=%d " + "flush=%d rotational=%d trim=%d zero=%d fua=%d extents=%d " + "cache=%d fast_zero=%d", + h->tls, size, w, f, r, t, z, F, e, c, Z); + fclose (fp); + print (h, "Connect", "%s", str); + } + else + print (h, "Connect", ""); + return 0; } @@ -380,28 +397,36 @@ log_extents (struct nbdkit_next_ops *next_ops, void *nxdata, leave_simple (h, id, "Extents", r, err); else { FILE *fp; - CLEANUP_FREE char *extents_str = NULL; + CLEANUP_FREE char *str = NULL; size_t i, n, len = 0; - fp = open_memstream (&extents_str, &len); + fp = open_memstream (&str, &len); if (fp != NULL) { + fprintf (fp, "extents=("); n = nbdkit_extents_count (extents); for (i = 0; i < n; ++i) { + bool comma = false; struct nbdkit_extent e = nbdkit_get_extent (extents, i); if (i > 0) - fprintf (fp, ", "); - fprintf (fp, "{ offset=0x%" PRIx64 ", length=0x%" PRIx64 ", " - "hole=%d, zero=%d }", - e.offset, e.length, - !!(e.type & NBDKIT_EXTENT_HOLE), - !!(e.type & NBDKIT_EXTENT_ZERO)); + fprintf (fp, " "); + fprintf (fp, "0x%" PRIx64 " 0x%" PRIx64, e.offset, e.length); + fprintf (fp, " \""); + if ((e.type & NBDKIT_EXTENT_HOLE) != 0) { + fprintf (fp, "hole"); + comma = true; + } + if ((e.type & NBDKIT_EXTENT_ZERO) != 0) { + if (comma) fprintf (fp, ","); + fprintf (fp, "zero"); + } + fprintf (fp, "\""); } - + fprintf (fp, ") return=0"); fclose (fp); + leave (h, id, "Extents", "%s", str); } - - leave (h, id, "Extents", "extents=[%s] return=0", - extents_str ? extents_str : "(null)"); + else + leave (h, id, "Extents", ""); } return r; } diff --git a/filters/log/output.c b/filters/log/output.c index 63c9f70f..0bfcf7c8 100644 --- a/filters/log/output.c +++ b/filters/log/output.c @@ -140,57 +140,49 @@ leave_simple (struct handle *h, log_id_t id, const char *act, int r, int *err) { const char *s; - /* Only decode what protocol.c:nbd_errno() recognizes */ + /* Only decode what server/protocol.c:nbd_errno() recognizes */ if (r == -1) { switch (*err) { case EROFS: - s = "EROFS=>EPERM"; - break; case EPERM: - s = "EPERM"; + s = " error=EPERM"; break; case EIO: - s = "EIO"; + s = " error=EIO"; break; case ENOMEM: - s = "ENOMEM"; + s = " error=ENOMEM"; break; #ifdef EDQUOT case EDQUOT: - s = "EDQUOT=>ENOSPC"; - break; #endif case EFBIG: - s = "EFBIG=>ENOSPC"; - break; case ENOSPC: - s = "ENOSPC"; + s = " error=ENOSPC"; break; #ifdef ESHUTDOWN case ESHUTDOWN: - s = "ESHUTDOWN"; + s = " error=ESHUTDOWN"; break; #endif case ENOTSUP: #if ENOTSUP != EOPNOTSUPP case EOPNOTSUPP: #endif - s = "ENOTSUP"; + s = " error=ENOTSUP"; break; case EOVERFLOW: - s = "EOVERFLOW"; + s = " error=EOVERFLOW"; break; case EINVAL: - s = "EINVAL"; - break; default: - s = "Other=>EINVAL"; + s = " error=EINVAL"; } } else - s = "Success"; + s = ""; - leave (h, id, act, "return=%d (%s)", r, s); + leave (h, id, act, "return=%d%s", r, s); } void diff --git a/tests/test-log-error.sh b/tests/test-log-error.sh new file mode 100755 index 00000000..d8f8cc63 --- /dev/null +++ b/tests/test-log-error.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# nbdkit +# Copyright (C) 2018 Red Hat Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Red Hat nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +source ./functions.sh +set -e +set -x + +requires nbdsh +requires_filter error +requires_filter log + +cleanup_fn rm -f log-error.log +rm -f log-error.log + +nbdsh -c ' +h.connect_command(["nbdkit", "-s", + "--filter=log", "--filter=error", + "null", "size=10M", + "logfile=log-error.log", "error-rate=100%"]) +try: + h.pread(512, 0) +except: + pass +' + +# Print the full log to help with debugging. +cat log-error.log + +# The log should show the read request ... +grep 'connection=1 Read id=1 offset=0x0 count=0x200 \.\.\.' log-error.log + +# ... returning an error. +grep 'connection=1 \.\.\.Read id=1 return=-1 error=EIO' log-error.log diff --git a/tests/test-log-extents.sh b/tests/test-log-extents.sh new file mode 100755 index 00000000..13a5638c --- /dev/null +++ b/tests/test-log-extents.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# nbdkit +# Copyright (C) 2018 Red Hat Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the name of Red Hat nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +source ./functions.sh +set -e +set -x + +requires nbdsh +requires nbdsh --base-allocation +requires_filter log + +cleanup_fn rm -f log-extents.log +rm -f log-extents.log + +nbdsh --base-allocation -c ' +h.connect_command(["nbdkit", "-s", + "--filter=log", + "data", "@32768 1", "size=64K", + "logfile=log-extents.log"]) +def f(metacontext, offset, e, err): + # Throw the data away, we do not care about it here. + pass +h.block_status(65536, 0, f) +' + +# Print the full log to help with debugging. +cat log-extents.log + +# Check the extents. +grep '\.\.\.Extents .*extents=(0x0 0x8000 "hole,zero" 0x8000 0x8000 "") return=0' log-extents.log -- 2.29.0.rc2
Richard W.M. Jones
2020-Dec-20 12:23 UTC
[Libguestfs] [PATCH nbdkit 2/2] log: Add logscript feature.
This allows you to trigger an external script on log events, instead (or in addition to) logging to a file. --- filters/log/nbdkit-log-filter.pod | 113 +++++++++++++++++++++++++++--- filters/log/log.h | 1 + filters/log/log.c | 60 ++++++++-------- filters/log/output.c | 84 +++++++++++++++++++--- TODO | 4 -- 5 files changed, 207 insertions(+), 55 deletions(-) diff --git a/filters/log/nbdkit-log-filter.pod b/filters/log/nbdkit-log-filter.pod index abf52e18..dd04f1ab 100644 --- a/filters/log/nbdkit-log-filter.pod +++ b/filters/log/nbdkit-log-filter.pod @@ -4,15 +4,24 @@ nbdkit-log-filter - nbdkit log filter =head1 SYNOPSIS - nbdkit --filter=log plugin logfile=FILE [logappend=BOOL] [plugin-args...] + nbdkit --filter=log PLUGIN + [logfile=FILE | logscript=SCRIPT] [logappend=BOOL] + [PLUGIN-ARGS...] =head1 DESCRIPTION -C<nbdkit-log-filter> is a filter that logs all transactions to a file. +C<nbdkit-log-filter> is a filter that logs all transactions to a file +or external script. + When used as the first filter, it can show the original client requests. As a later filter, it can show how earlier filters have -modified the original request. The format of the log file is -described in L</LOG FILE FORMAT> below. +modified the original request. + +When using C<logfile=FILE>, logs are written to a log file with the +format described in L</LOG FILE FORMAT> below. + +When using C<logscript=SCRIPT>, logs invoke the external script. See +L</LOG SCRIPT> below. An alternative to this filter is simply to run nbdkit with the I<-f> and I<-v> flags which enable verbose debugging to stderr. This logs @@ -22,11 +31,20 @@ parsable format and works when nbdkit runs in the background. =head1 PARAMETERS +C<logfile> or C<logscript> or both can be given. If neither then the +filter is inactive. + =over 4 =item B<logfile=>FILE -The file where the log is written. This parameter is required. +The file where the log is written. See L</LOG FILE FORMAT> below. + +=item B<logscript=>SCRIPT + +(nbdkit E<ge> 1.24) + +Log lines invoke an external script. See L</LOG SCRIPT> below. =item B<logappend=true> @@ -34,9 +52,9 @@ The file where the log is written. This parameter is required. (nbdkit E<ge> 1.8) -When set to C<false> (the default), if the file already exists it will -be truncated. When set to C<true>, the filter appends to the existing -file. +This only affects C<logfile>. If C<false> (the default), if the file +already exists it will be truncated. If C<true>, the filter appends +to the existing log file. =back @@ -84,6 +102,85 @@ unique per connection. Strings and lists are shell-quoted. +=head1 LOG SCRIPT + +If C<logscript=SCRIPT> is given on the command line then log entries +are passed to the external script. + +The script is passed several shell variables: + +=over 4 + +=item C<$act> + +The action name, like C<"Read">, C<"Write"> etc. + +=item C<$connection> + +The connection ID identifying the client, only for connected calls +like C<"Read">. + +=item C<$error> + +For messages of type C<"LEAVE"> which fail (C<$return = -1>), this +contains the errno as a string, for example C<"EIO">. + +=item C<$id> + +The transaction ID, used to correlate actions which are split into two +messages C<"ENTER"> and C<"LEAVE">. + +=item C<$return> + +For messages of type C<"LEAVE"> this is the return code, usually C<0> +for success and C<-1> if there was an error. + +=item C<$type> + +The message type: C<"ENTER">, C<"LEAVE"> or C<"PRINT">. + +=item other shell variables + +Other parameters like C<offset=N> are turned into shell variables +C<$offset> etc. + +=back + +Note the return value of the script is ignored. Log scripts cannot +modify or interrupt request processing. + +=head2 Log script examples + +The script: + + nbdkit -f --filter=log null 10M \ + logscript='echo $connection $type $id $act $offset >&2' + +might print lines like: + + PRINT Ready + 1 ENTER 1 Read 0x0 + 1 ENTER 2 Write 0x200 + 1 LEAVE 2 Write + 1 LEAVE 1 Read + +corresponding to log file lines: + + Ready thread_model=3 + connection=1 Read id=1 offset=0x0 count=0x200 ... + connection=1 Write id=2 offset=0x200 count=0x200 ... + connection=1 ...Write id=2 + connection=1 ...Read id=1 + +This script will trigger a message when any client reads: + + nbdkit -f --filter=log memory 10M \ + logscript=' + if [ "$act" = "Read" -a "$type" = "ENTER" ]; then + echo Client is reading $count bytes from $offset >&2 + fi + ' + =head1 FILES =over 4 diff --git a/filters/log/log.h b/filters/log/log.h index 8df27192..6dad10d4 100644 --- a/filters/log/log.h +++ b/filters/log/log.h @@ -50,6 +50,7 @@ struct handle { extern uint64_t connections; extern const char *logfilename; extern FILE *logfile; +extern const char *logscript; extern int append; extern pthread_mutex_t lock; diff --git a/filters/log/log.c b/filters/log/log.c index 37b36498..7b81a8f1 100644 --- a/filters/log/log.c +++ b/filters/log/log.c @@ -62,6 +62,7 @@ uint64_t connections; const char *logfilename; FILE *logfile; +const char *logscript; int append; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pid_t saved_pid; @@ -88,23 +89,17 @@ log_config (nbdkit_next_config *next, void *nxdata, return -1; return 0; } + if (strcmp (key, "logscript") == 0) { + logscript = value; + return 0; + } return next (nxdata, key, value); } -static int -log_config_complete (nbdkit_next_config_complete *next, void *nxdata) -{ - if (!logfilename) { - nbdkit_error ("missing logfile= parameter for the log filter"); - return -1; - } - - return next (nxdata); -} - #define log_config_help \ - "logfile=<FILE> (required) The file to place the log in.\n" \ - "logappend=<BOOL> True to append to the log (default false).\n" + "logfile=<FILE> The file to place the log in.\n" \ + "logappend=<BOOL> True to append to the log (default false).\n" \ + "logscript=<SCRIPT> Script to run for logging." /* Open the logfile. */ static int @@ -112,24 +107,26 @@ log_get_ready (nbdkit_next_get_ready *next, void *nxdata, int thread_model) { int fd; - /* Using fopen("ae"/"we") would be more convenient, but as Haiku - * still lacks that, use this instead. Atomicity is not essential - * here since .config completes before threads that might fork, if - * we have to later add yet another fallback to fcntl(fileno()) for - * systems without O_CLOEXEC. - */ - fd = open (logfilename, - O_CLOEXEC | O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), - 0666); - if (fd < 0) { - nbdkit_error ("open: %s: %m", logfilename); - return -1; - } - logfile = fdopen (fd, append ? "a" : "w"); - if (!logfile) { - nbdkit_error ("fdopen: %s: %m", logfilename); - close (fd); - return -1; + if (logfilename) { + /* Using fopen("ae"/"we") would be more convenient, but as Haiku + * still lacks that, use this instead. Atomicity is not essential + * here since .config completes before threads that might fork, if + * we have to later add yet another fallback to fcntl(fileno()) for + * systems without O_CLOEXEC. + */ + fd = open (logfilename, + O_CLOEXEC | O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), + 0666); + if (fd < 0) { + nbdkit_error ("open: %s: %m", logfilename); + return -1; + } + logfile = fdopen (fd, append ? "a" : "w"); + if (!logfile) { + nbdkit_error ("fdopen: %s: %m", logfilename); + close (fd); + return -1; + } } saved_pid = getpid (); @@ -450,7 +447,6 @@ static struct nbdkit_filter filter = { .name = "log", .longname = "nbdkit log filter", .config = log_config, - .config_complete = log_config_complete, .config_help = log_config_help, .unload = log_unload, .get_ready = log_get_ready, diff --git a/filters/log/output.c b/filters/log/output.c index 0bfcf7c8..c999150a 100644 --- a/filters/log/output.c +++ b/filters/log/output.c @@ -55,9 +55,10 @@ enum type { ENTER, LEAVE, PRINT }; +/* Adds an entry to the logfile. */ static void -output (struct handle *h, log_id_t id, const char *act, enum type type, - const char *fmt, va_list args) +to_file (struct handle *h, log_id_t id, const char *act, enum type type, + const char *fmt, va_list args) { struct timeval tv; struct tm tm; @@ -103,15 +104,62 @@ output (struct handle *h, log_id_t id, const char *act, enum type type, #endif } +/* Runs the script. */ +static void +to_script (struct handle *h, log_id_t id, const char *act, enum type type, + const char *fmt, va_list args) +{ + FILE *fp; + CLEANUP_FREE char *str = NULL; + size_t len = 0; + int r; + + /* Create the shell variables + script. */ + fp = open_memstream (&str, &len); + if (!fp) { + /* Not much we can do, but at least record the error. */ + nbdkit_error ("logscript: open_memstream: %m"); + return; + } + + fprintf (fp, "act=%s\n", act); + if (h) + fprintf (fp, "connection=%" PRIu64 "\n", h->connection); + switch (type) { + case ENTER: fprintf (fp, "type=ENTER\n"); break; + case LEAVE: fprintf (fp, "type=LEAVE\n"); break; + case PRINT: fprintf (fp, "type=PRINT\n"); break; + } + if (id) + fprintf (fp, "id=%" PRIu64 "\n", id); + + vfprintf (fp, fmt, args); + fprintf (fp, "\n"); + + fprintf (fp, "%s", logscript); + fclose (fp); + + /* Run the script. Log the status, but ignore it. */ + r = system (str); + exit_status_to_nbd_error (r, "logscript"); +} + void enter (struct handle *h, log_id_t id, const char *act, const char *fmt, ...) { va_list args; - va_start (args, fmt); - output (h, id, act, ENTER, fmt, args); - va_end (args); + if (logfile) { + va_start (args, fmt); + to_file (h, id, act, ENTER, fmt, args); + va_end (args); + } + if (logscript) { + va_start (args, fmt); + to_script (h, id, act, ENTER, fmt, args); + va_end (args); + } } void @@ -120,9 +168,16 @@ leave (struct handle *h, log_id_t id, const char *act, { va_list args; - va_start (args, fmt); - output (h, id, act, LEAVE, fmt, args); - va_end (args); + if (logfile) { + va_start (args, fmt); + to_file (h, id, act, LEAVE, fmt, args); + va_end (args); + } + if (logscript) { + va_start (args, fmt); + to_script (h, id, act, LEAVE, fmt, args); + va_end (args); + } } void @@ -130,9 +185,16 @@ print (struct handle *h, const char *act, const char *fmt, ...) { va_list args; - va_start (args, fmt); - output (h, 0, act, PRINT, fmt, args); - va_end (args); + if (logfile) { + va_start (args, fmt); + to_file (h, 0, act, PRINT, fmt, args); + va_end (args); + } + if (logscript) { + va_start (args, fmt); + to_script (h, 0, act, PRINT, fmt, args); + va_end (args); + } } void diff --git a/TODO b/TODO index cc7afab8..198939e6 100644 --- a/TODO +++ b/TODO @@ -202,10 +202,6 @@ Suggestions for filters * masking plugin features for testing clients (see 'nozero' and 'fua' filters for examples) -* "event" filter which triggers shell scripts on significant events - (like connection, close, read, write, etc). It would not modify the - requests but allow more flexible logging. - * "bandwidth quota" filter which would close a connection after it exceeded a certain amount of bandwidth up or down. -- 2.29.0.rc2
Eric Blake
2021-Jan-04 15:03 UTC
[Libguestfs] [PATCH nbdkit 1/2] log: Use strict shell quoting for every parameter displayed in the log file.
On 12/20/20 6:23 AM, Richard W.M. Jones wrote:> This is not fully backwards compatible, although the changes are > minor: > > * Lists returned by ListExports and Extents use the array format that > can be parsed by bash, eg: > > Extents id=1 extents=(0x0 0x8000 "hole,zero" 0x8000 0x8000 "") return=0 > > * Errors are returned as separate error= parameters, and simplified, eg: > > ...Read id=1 return=-1 error=EINVAL > > * Strings are quoted properly in all circumstances. > > This commit also updates the documentation and adds more tests.Makes sense to me. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3226 Virtualization: qemu.org | libvirt.org