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