roxen.lists.roxen.general

Subject Author Date
[PATCH 16/17] New module: autosplitted virtual-host logfiles Stephen R. van den Berg <srb[at]cuci[dot]nl> 20-01-2009
---

 server/modules/logging/vhostlog.pike |  119 ++++++++++++++++++++++++++++++++++
 1 files changed, 119 insertions(+), 0 deletions(-)
 create mode 100644 server/modules/logging/vhostlog.pike

diff --git a/server/modules/logging/vhostlog.pike
b/server/modules/logging/vhostlog.pike
new file mode 100644
index 0000000..9b61f7e
--- /dev/null
+++ b/server/modules/logging/vhostlog.pike
@@ -0,0 +1,119 @@
+// This is a roxen module which provides splitted virtual host logging.
+// Copyright (c) 2007-2009, Stephen R. van den Berg, The Netherlands.
+//                     <<srb[at]cuci.nl>>
+//
+// This module is open source software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as published
+// by the Free Software Foundation; either version 2, or (at your option) any
+// later version.
+//
+
+constant thread_safe=1;
+
+#include <config.h>
+inherit "module";
+#include <module.h>
+
+constant module_type = MODULE_LOGGER;
+constant module_name = "Logger: Virtual host logger";
+constant module_doc  = 
+ "This module provides separated virtual host logging.<br>"
+ "<p>Copyright &copy; 2007-2009, by "
+ "<a href='mailto:<srb[at]cuci.nl>'>Stephen R. van den Berg</a>, "
+ "The Netherlands.</p>"
+ "<p>This module is open source software; you can redistribute it and/or "
+ "modify it under the terms of the GNU General Public License as published "
+ "by the Free Software Foundation; either version 2, or (at your option) any "
+ "later version.</p>";
+
+string create()
+{
+  set_module_creator("Stephen R. van den Berg <<srb[at]cuci.nl>>");
+  defvar("block", 0, "Only log in userlog", TYPE_FLAG,
+	 "If set, no entry will be written to the normal log.\n");
+
+  defvar("LogFormat",
+ "*: $ip_number - $user [$cern_date] \"$method $full_resource $protocol\"
$response $length \"$referrer\" \"$user_agent_raw\""
+	 ,
+
+	 "Logging Format",
+	 TYPE_TEXT_FIELD,
+	
+       "What format to use for logging. See standard logspecs for reference.\n"
+	 );
+
+  defvar("LogFile", "$LOGDIR/vhostlogs/%v/Log",
+         "Logging: Log file", TYPE_FILE,
+         "The log file. "
+         ""
+         "A file name. Some substitutions will be done:"
+         "<pre>"
+         "%y    Year  (e.g. '1997')\n"
+         "%m    Month (e.g. '08')\n"
+         "%d    Day   (e.g. '10' for the tenth)\n"
+         "%h    Hour  (e.g. '00')\n"
+         "%H    Hostname\n"
+         "%v    Virtual hostname\n"
+         "</pre>"
+         );
+}
+
+mapping(int:string) log_format = ([]);
+mapping(string:object) logfiles = ([]);
+
+private void parse_log_formats()
+{ string b;
+  array foo=query("LogFormat")/"\n";
+  log_format = ([]);
+  foreach(foo, b)
+    if(strlen(b) && b[0] != '#' && sizeof(b/":")>1)
+      log_format[(int)(b/":")[0]]=String.trim_whites((b/":")[1..]*":");
+}
+
+string start()
+{ parse_log_formats();
+}
+
+static string lastfile,lasthost;
+
+string status() {
+  return sprintf("Total logfiles accessed: %d<br />"
+   "Last logfile opened: %s<br />"
+   "Last virtual host accessed: %s",
+   sizeof(logfiles),lastfile||"NONE",lasthost||"NONE");
+}
+
+int log(RequestID id, mapping file)
+{ object curlogfile;
+  { string vhost;
+    sscanf(id->url_base(), "%*[a-z]://%[^:/]", vhost);
+    if(!(curlogfile=logfiles[vhost]))
+    { string logfile;
+      logfile=replace(query("LogFile"),"%v",vhost);
+
+      if(file->error==404 || file->error==200 &&
+        "/"==(string)(id->raw_url
+         ||(id->misc->common && id->misc->common->orig_url)
+         ||id->not_query))
+      { string dirn=dirname(logfile);
+        if(!dirn || !file_stat(dirn))
+          return 0;	    // Do not create vhosts on 404 errors or / fetches
+      }
+      logfiles[vhost]=curlogfile=roxen.LogFile(lastfile=logfile,
+       ""/*query("LogFileCompressor")*/);   // FIXME from the global config?
+    }
+    lasthost=vhost;
+  }
+  if(curlogfile)
+  { string form;
+    if(!(form=log_format[file->error]))
+      form=log_format[0];
+    if(form)
+      catch
+      { roxen.run_log_format(form, curlogfile->write, id, file);
+        if(query("block"))
+          return 1;
+      };
+  }
+  return 0;
+}