summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/s6-log.html12
-rw-r--r--src/daemontools-extras/s6-log.c45
2 files changed, 37 insertions, 20 deletions
diff --git a/doc/s6-log.html b/doc/s6-log.html
index 7f461bc..158dd57 100644
--- a/doc/s6-log.html
+++ b/doc/s6-log.html
@@ -68,11 +68,13 @@ Currently supported verbosity levels:
<li> 1: write alerts, warnings and fatal errors </li>
</ul> </li>
<li> <tt>-l&nbsp;<em>linelimit</em></tt>&nbsp;: if a log line is longer than
-<em>linelimit</em> bytes, cut it in two by inserting a newline. The newline
-may appear anywhere after <em>linelimit</em> or more bytes. <em>linelimit</em>
-cannot be less than 48. Using this option ensures that an ill-formatted log
-stream will not make s6-log uncontrollably eat memory by trying to read and
-process an extremely long line in one go. The default is 8192 bytes. </li>
+<em>linelimit</em> bytes, split it by inserting a newline after the
+<em>linelimit</em>th byte. After the split, the remainder of the line will
+also be processed, so it will go through the selection process, timestamping,
+etc. <em>linelimit</em> cannot be less than 48, unless it is 0 (which means
+infinite). The default is 8192 bytes. Setting <em>linelimit</em> to 0 ensures
+that lines will never be split; this may cause important memory consumption
+by s6-log if it is fed extremely long lines, so use with caution. </li>
</ul>
<h2> Logdirs </h2>
diff --git a/src/daemontools-extras/s6-log.c b/src/daemontools-extras/s6-log.c
index f3355f0..7959222 100644
--- a/src/daemontools-extras/s6-log.c
+++ b/src/daemontools-extras/s6-log.c
@@ -31,7 +31,6 @@
#include <skalibs/sig.h>
#include <skalibs/selfpipe.h>
#include <skalibs/siovec.h>
-#include <skalibs/skamisc.h>
#include <skalibs/exec.h>
#include <s6/config.h>
@@ -1010,6 +1009,29 @@ static void prepare_to_exit (void)
flagexiting = 1 ;
}
+static inline int getchunk (buffer *b, stralloc *sa, size_t linelimit)
+{
+ struct iovec v[2] ;
+ size_t pos ;
+ int r ;
+ buffer_rpeek(b, v) ;
+ pos = siovec_bytein(v, 2, "\n", 2) ;
+ if (linelimit && sa->len + pos > linelimit)
+ {
+ r = 2 ;
+ pos = linelimit - sa->len ;
+ }
+ else
+ {
+ r = pos < buffer_len(b) ;
+ pos += r ;
+ }
+ if (!stralloc_readyplus(sa, pos + (r == 2))) return -1 ;
+ buffer_getnofill(b, sa->s + sa->len, pos) ; sa->len += pos ;
+ if (r == 2) sa->s[sa->len++] = 0 ;
+ return r ;
+}
+
static void normal_stdin (scriptelem_t const *script, unsigned int scriptlen, size_t linelimit, unsigned int gflags)
{
ssize_t r = sanitize_read(buffer_fill(buffer_0)) ;
@@ -1018,21 +1040,14 @@ static void normal_stdin (scriptelem_t const *script, unsigned int scriptlen, si
if ((errno != EPIPE) && verbosity) strerr_warnwu1sys("read from stdin") ;
prepare_to_exit() ;
}
- else if (r)
+ else if (r) for (;;)
{
- while (skagetln_nofill(buffer_0, &indata, '\n') > 0)
- {
- indata.s[indata.len - 1] = 0 ;
- script_run(script, scriptlen, indata.s, indata.len - 1, gflags) ;
- indata.len = 0 ;
- }
- if (linelimit && indata.len > linelimit)
- {
- if (!stralloc_0(&indata)) dienomem() ;
- if (verbosity) strerr_warnw2x("input line too long, ", "inserting a newline") ;
- script_run(script, scriptlen, indata.s, indata.len - 1, gflags) ;
- indata.len = 0 ;
- }
+ r = getchunk(buffer_0, &indata, linelimit) ;
+ if (r < 0) dienomem() ;
+ else if (!r) break ;
+ indata.s[indata.len - 1] = 0 ;
+ script_run(script, scriptlen, indata.s, indata.len - 1, gflags) ;
+ indata.len = 0 ;
}
}