about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2013-09-02T09·58+0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2013-09-02T09·58+0200
commitefe428946431c6c670151c949884fa8c1fa31794 (patch)
tree3d9d05c8397aef96010f10261912e458c44814ef
parentafc6c1bad63e27d68adf49e673f8aafd36495a8a (diff)
Add an option to limit the log output of builders
This is mostly useful for Hydra to deal with builders that get stuck
in an infinite loop writing data to stdout/stderr.
-rw-r--r--doc/manual/conf-file.xml15
-rw-r--r--src/libstore/build.cc13
-rw-r--r--src/libstore/globals.cc2
-rw-r--r--src/libstore/globals.hh4
4 files changed, 34 insertions, 0 deletions
diff --git a/doc/manual/conf-file.xml b/doc/manual/conf-file.xml
index c37a2da47413..c832108fed06 100644
--- a/doc/manual/conf-file.xml
+++ b/doc/manual/conf-file.xml
@@ -148,6 +148,7 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
 
   </varlistentry>
 
+
   <varlistentry xml:id="conf-build-timeout"><term><literal>build-timeout</literal></term>
 
     <listitem>
@@ -168,6 +169,20 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
   </varlistentry>
 
 
+  <varlistentry xml:id="conf-build-max-log-size"><term><literal>build-max-log-size</literal></term>
+
+    <listitem>
+
+      <para>This option defines the maximum number of bytes that a
+      builder can write to its stdout/stderr.  If the builder exceeds
+      this limit, it’s killed.  A value of <literal>0</literal> (the
+      default) means that there is no limit.</para>
+
+    </listitem>
+
+  </varlistentry>
+
+
   <varlistentry xml:id="conf-build-users-group"><term><literal>build-users-group</literal></term>
 
     <listitem><para>This options specifies the Unix group containing
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index b5d064e8c60d..25bf848ca697 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -813,6 +813,9 @@ private:
     BZFILE * bzLogFile;
     AutoCloseFD fdLogFile;
 
+    /* Number of bytes received from the builder's stdout/stderr. */
+    unsigned long logSize;
+
     /* Pipe for the builder's standard output/error. */
     Pipe builderOut;
 
@@ -2403,6 +2406,8 @@ string drvsLogDir = "drvs";
 
 Path DerivationGoal::openLogFile()
 {
+    logSize = 0;
+
     if (!settings.keepLog) return "";
 
     string baseName = baseNameOf(drvPath);
@@ -2478,6 +2483,14 @@ void DerivationGoal::handleChildOutput(int fd, const string & data)
     if ((hook && fd == hook->builderOut.readSide) ||
         (!hook && fd == builderOut.readSide))
     {
+        logSize += data.size();
+        if (settings.maxLogSize && logSize > settings.maxLogSize) {
+            printMsg(lvlError,
+                format("%1% killed after writing more than %2% bytes of log output")
+                % getName() % settings.maxLogSize);
+            cancel(true); // not really a timeout, but close enough
+            return;
+        }
         if (verbosity >= settings.buildVerbosity)
             writeToStderr(data);
         if (bzLogFile) {
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index d17bd947d3da..aeb52e1a8696 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -46,6 +46,7 @@ Settings::Settings()
     impersonateLinux26 = false;
     keepLog = true;
     compressLog = true;
+    maxLogSize = 0;
     cacheFailure = false;
     pollInterval = 5;
     checkRootReachability = false;
@@ -140,6 +141,7 @@ void Settings::update()
     get(impersonateLinux26, "build-impersonate-linux-26");
     get(keepLog, "build-keep-log");
     get(compressLog, "build-compress-log");
+    get(maxLogSize, "build-max-log-size");
     get(cacheFailure, "build-cache-failure");
     get(pollInterval, "build-poll-interval");
     get(checkRootReachability, "gc-check-reachability");
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index f129d9a11edc..50b61725c742 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -153,6 +153,10 @@ struct Settings {
     /* Whether to compress logs. */
     bool compressLog;
 
+    /* Maximum number of bytes a builder can write to stdout/stderr
+       before being killed (0 means no limit). */
+    unsigned long maxLogSize;
+
     /* Whether to cache build failures. */
     bool cacheFailure;