Author: timw
Date: Sun Mar 7 20:31:45 2010
New Revision: 920093
URL: http://svn.apache.org/viewvc?rev=920093&view=rev
Log:
Adding basic log rotation functionality to the ISAPI redirector - #48501
Config and functionality is modeled after the Apache HTTPD rotatelogs program
for consistency.
Modified:
tomcat/jk/trunk/native/iis/jk_isapi_plugin.c
tomcat/jk/trunk/xdocs/reference/iis.xml
Modified: tomcat/jk/trunk/native/iis/jk_isapi_plugin.c
URL:
http://svn.apache.org/viewvc/tomcat/jk/trunk/native/iis/jk_isapi_plugin.c?rev=920093&r1=920092&r2=920093&view=diff
==============================================================================
--- tomcat/jk/trunk/native/iis/jk_isapi_plugin.c (original)
+++ tomcat/jk/trunk/native/iis/jk_isapi_plugin.c Sun Mar 7 20:31:45 2010
@@ -128,6 +128,9 @@
#define ENABLE_CHUNKED_ENCODING_TAG ("enable_chunked_encoding")
#define ERROR_PAGE_TAG ("error_page")
+#define LOG_ROTATION_TIME_TAG ("log_rotationtime")
+#define LOG_FILESIZE_TAG ("log_filesize")
+
/* HTTP standard headers */
#define TRANSFER_ENCODING_CHUNKED_HEADER_COMPLETE ("Transfer-Encoding:
chunked")
#define TRANSFER_ENCODING_CHUNKED_HEADER_COMPLETE_LEN (26)
@@ -479,6 +482,7 @@
static jk_map_t *jk_environment_map = NULL;
static jk_logger_t *logger = NULL;
+static JK_CRIT_SEC log_cs;
static char *SERVER_NAME = "SERVER_NAME";
static char *SERVER_SOFTWARE = "SERVER_SOFTWARE";
static char *INSTANCE_ID = "INSTANCE_ID";
@@ -487,7 +491,12 @@
static char extension_uri[INTERNET_MAX_URL_LENGTH] =
"/jakarta/isapi_redirect.dll";
static char log_file[MAX_PATH * 2];
+static char log_file_effective[MAX_PATH * 2];
static int log_level = JK_LOG_DEF_LEVEL;
+static long log_rotationtime = 0;
+static time_t log_next_rotate_time = 0;
+static ULONGLONG log_filesize = 0;
+
static char worker_file[MAX_PATH * 2];
static char worker_mount_file[MAX_PATH * 2] = {0};
static int worker_mount_reload = JK_URIMAP_DEF_RELOAD;
@@ -557,6 +566,10 @@
static int init_jk(char *serverName);
+
+static int JK_METHOD iis_log_to_file(jk_logger_t *l, int level,
+ int used, char *what);
+
static BOOL initialize_extension(void);
static int read_registry_init_data(void);
@@ -2273,9 +2286,11 @@
}
wc_close(logger);
jk_shm_close();
+ JK_ENTER_CS(&(log_cs), rc);
if (logger) {
jk_close_file_logger(&logger);
}
+ JK_LEAVE_CS(&(log_cs), rc);
}
JK_LEAVE_CS(&(init_cs), rc);
@@ -2335,6 +2350,7 @@
StringCbPrintf(HTTP_WORKER_HEADER_INDEX, MAX_PATH,
HTTP_HEADER_TEMPLATE, WORKER_HEADER_INDEX_BASE, hInst);
JK_INIT_CS(&init_cs, rc);
+ JK_INIT_CS(&log_cs, rc);
break;
case DLL_PROCESS_DETACH:
@@ -2344,6 +2360,7 @@
__except(1) {
}
JK_DELETE_CS(&init_cs, rc);
+ JK_DELETE_CS(&log_cs, rc);
break;
default:
@@ -2387,17 +2404,147 @@
return 0;
}
+/*
+ * Reinitializes the logger, formatting the log file name if rotation is
enabled,
+ * and calculating the next rotation time if applicable.
+ */
+static int init_logger(int rotate, jk_logger_t **l)
+{
+ int rc = JK_TRUE;
+ int log_open = rotate; /* log is assumed open if a rotate is requested */
+ char *log_file_name;
+ char log_file_name_buf[MAX_PATH*2];
+
+ /* If log rotation is enabled, format the log filename */
+ if ((log_rotationtime > 0) || (log_filesize > 0)) {
+ time_t t;
+ t = time(NULL);
+
+ if (log_rotationtime > 0) {
+ /* Align time to rotationtime intervals */
+ t = (t / log_rotationtime) * log_rotationtime;
+
+ /* Calculate rotate time */
+ log_next_rotate_time = t + log_rotationtime;
+ }
+
+ log_file_name = log_file_name_buf;
+ if (strchr(log_file, '%')) {
+ struct tm *tm_now;
+
+ /* If there are %s in the log file name, treat it as a sprintf
format */
+ tm_now = localtime(&t);
+ strftime(log_file_name, sizeof(log_file_name_buf), log_file,
tm_now);
+ } else {
+ /* Otherwise append the number of seconds to the base name */
+ sprintf_s(log_file_name, sizeof(log_file_name_buf), "%s.%d",
log_file, (long)t);
+ }
+ } else {
+ log_file_name = log_file;
+ }
+
+ /* Close the current log file if required, and the effective log file name
has changed */
+ if (log_open && strncmp(log_file_name, log_file_effective,
strlen(log_file_name)) != 0) {
+ FILE* lf = ((jk_file_logger_t* )logger->logger_private)->logfile;
+ fprintf_s(lf, "Log rotated to %s\r\n", log_file_name);
+ fflush(lf);
+
+ rc = jk_close_file_logger(&logger);
+ log_open = JK_FALSE;
+ }
+
+ if (!log_open) {
+ if (jk_open_file_logger(&logger, log_file_name, log_level)) {
+ logger->log = iis_log_to_file;
+
+ /* Remember the current log file name for the next potential
rotate */
+ strcpy_s(log_file_effective, sizeof(log_file_effective),
log_file_name);
+ rc = JK_TRUE;
+ } else {
+ logger = NULL;
+ rc = JK_FALSE;
+ }
+ }
+
+ /* Update logger being used for this log call so it occurs on new file */
+ (*l) = logger;
+ return rc;
+}
+
+/*
+ * Checks whether the log needs to be rotated. Must be called while holding
the log lock.
+ * The behaviour here is based on the Apache rotatelogs program.
+ * http://httpd.apache.org/docs/2.0/programs/rotatelogs.html
+ */
+static int JK_METHOD rotate_log_file(jk_logger_t **l)
+{
+ int rc = JK_TRUE;
+ int rotate = JK_FALSE;
+
+ if (log_rotationtime > 0) {
+ time_t t = time(NULL);
+
+ if (t >= log_next_rotate_time) {
+ rotate = JK_TRUE;
+ }
+ } else if (log_filesize > 0) {
+ LARGE_INTEGER filesize;
+ HANDLE h = (HANDLE)_get_osfhandle(fileno(((jk_file_logger_t
*)(*l)->logger_private)->logfile));
+ GetFileSizeEx(h, &filesize);
+
+ if ((ULONGLONG)filesize.QuadPart >= log_filesize) {
+ rotate = JK_TRUE;
+ }
+ }
+ if (rotate) {
+ rc = init_logger(JK_TRUE, l);
+ }
+ return rc;
+}
+
+/*
+ * Log messages to the log file, rotating the log when required.
+ */
+static int JK_METHOD iis_log_to_file(jk_logger_t *l, int level,
+ int used, char *what)
+{
+ int rc = JK_FALSE;
+
+ if (l &&
+ (l->level <= level || level == JK_LOG_REQUEST_LEVEL) &&
+ l->logger_private && what && used > 0) {
+ jk_file_logger_t *p = l->logger_private;
+ rc = JK_TRUE;
+
+ if (p->logfile) {
+ what[used++] = '\r';
+ what[used++] = '\n';
+ what[used] = '\0';
+
+ /* Perform logging within critical section to protect rotation */
+ JK_ENTER_CS(&(log_cs), rc);
+ if (rc && rotate_log_file(&l)) {
+ /* The rotation process will reallocate the jk_logger_t
structure, so refetch */
+ FILE *rotated = ((jk_file_logger_t
*)l->logger_private)->logfile;
+ fputs(what, rotated);
+ fflush(rotated);
+ JK_LEAVE_CS(&(log_cs), rc);
+ }
+ }
+ }
+ return rc;
+}
+
static int init_jk(char *serverName)
{
char shm_name[MAX_PATH];
int rc = JK_FALSE;
+
+ init_logger(JK_FALSE, &logger);
+ /* TODO: Use System logging to notify the user that
+ * we cannot open the configured log file.
+ */
- if (!jk_open_file_logger(&logger, log_file, log_level)) {
- /* TODO: Use System logging to notify the user that
- * we cannot open the configured log file.
- */
- logger = NULL;
- }
StringCbCopy(shm_name, MAX_PATH, SHM_DEF_NAME);
jk_log(logger, JK_LOG_INFO, "Starting %s", (VERSION_STRING));
@@ -2428,6 +2575,9 @@
jk_log(logger, JK_LOG_DEBUG, "Using log file %s.", log_file);
jk_log(logger, JK_LOG_DEBUG, "Using log level %d.", log_level);
+ jk_log(logger, JK_LOG_DEBUG, "Using log rotation time %d seconds.",
log_rotationtime);
+ jk_log(logger, JK_LOG_DEBUG, "Using log file size %d bytes.",
log_filesize);
+
jk_log(logger, JK_LOG_DEBUG, "Using extension uri %s.", extension_uri);
jk_log(logger, JK_LOG_DEBUG, "Using worker file %s.", worker_file);
jk_log(logger, JK_LOG_DEBUG, "Using worker mount file %s.",
@@ -2456,6 +2606,12 @@
DEFAULT_WORKER_THREADS);
}
+ if ((log_rotationtime > 0) && (log_filesize > 0)) {
+ jk_log(logger, JK_LOG_WARNING,
+ "%s is defined in configuration, but will be ignored because %s is
set. ",
+ LOG_FILESIZE_TAG, LOG_ROTATION_TIME_TAG);
+ }
+
if (rewrite_rule_file[0] && jk_map_alloc(&rewrite_map)) {
if (jk_map_read_properties(rewrite_map, NULL, rewrite_rule_file,
NULL, JK_MAP_HANDLE_RAW, logger)) {
@@ -2640,6 +2796,28 @@
if (get_config_parameter(src, JK_LOG_LEVEL_TAG, tmpbuf, sizeof(tmpbuf))) {
log_level = jk_parse_log_level(tmpbuf);
}
+ if (get_config_parameter(src, LOG_ROTATION_TIME_TAG, tmpbuf,
sizeof(tmpbuf))) {
+ log_rotationtime = atol(tmpbuf);
+ if (log_rotationtime < 0) {
+ log_rotationtime = 0;
+ }
+ }
+ if (get_config_parameter(src, LOG_FILESIZE_TAG, tmpbuf, sizeof(tmpbuf))) {
+ size_t tl = strlen(tmpbuf);
+ if (tl > 0) {
+ /* rotatelogs has an 'M' suffix on filesize, which we optionally
support for consistency */
+ if (tmpbuf[tl - 1] == 'M') {
+ tmpbuf[tl - 1] = '\0';
+ }
+ log_filesize = atol(tmpbuf);
+ if (log_filesize < 0) {
+ log_filesize = 0;
+ }
+ /* Convert to MB as per Apache rotatelogs */
+ log_filesize *= (1000 * 1000);
+ }
+ }
+
ok = ok && get_config_parameter(src, EXTENSION_URI_TAG, extension_uri,
sizeof(extension_uri));
ok = ok && get_config_parameter(src, JK_WORKER_FILE_TAG, worker_file,
sizeof(worker_file));
ok = ok && get_config_parameter(src, JK_MOUNT_FILE_TAG, worker_mount_file,
sizeof(worker_mount_file));
Modified: tomcat/jk/trunk/xdocs/reference/iis.xml
URL:
http://svn.apache.org/viewvc/tomcat/jk/trunk/xdocs/reference/iis.xml?rev=920093&r1=920092&r2=920093&view=diff
==============================================================================
--- tomcat/jk/trunk/xdocs/reference/iis.xml (original)
+++ tomcat/jk/trunk/xdocs/reference/iis.xml Sun Mar 7 20:31:45 2010
@@ -75,11 +75,24 @@
<attribute name="log_file" required="false"><p>
A value pointing to location where log file will be created.
(for example <b>c:\tomcat\logs\isapi.log</b>)
+<br/>If one of the log rotation settings (<b>log_rotationtime</b> or
<b>log_filesize</b>) are specified then the actual log file name is based on
this setting.
+If the log file name includes any '%' characters, then it is treated as a
format string for <code>strftime(3)</code>,
+e.g. <b>c:\tomcat\logs\isapi-%Y-%m-%d-%H_%M_%S.log</b>. Otherwise, the suffix
<em>.nnnnnnnnnn</em> is automatically added and is the time in seconds.
+A full list of format string substitutions can be found in the <a
href="http://httpd.apache.org/docs/2.0/programs/rotatelogs.html">Apache
rotatelogs documentation</a>
</p></attribute>
<attribute name="log_level" required="false"><p>
A string value for log level
(can be debug, info, warn, error or trace).
</p></attribute>
+<attribute name="log_rotationtime" required="false"><p>
+The time between log file rotations in seconds.
+Setting this to 0 (the default) disables log rotation based on time.
+</p></attribute>
+<attribute name="log_filesize" required="false"><p>
+The maximum log file size in megabytes, after which the log file will be
rotated. Setting this to 0 (the default) disables log rotation based on file
size.
+<br>The value can have an optional <b>M</b> suffix, i.e. both <b>5</b> and
<b>5M</b> will rotate the log file when it grows to 5MB.
+<br>If <b>log_rotationtime</b> is specified, then this setting is ignored.
+</p></attribute>
<attribute name="worker_file" required="true"><p>
A string value which is the full path to workers.properties file
(for example <b>c:\tomcat\conf\workers.properties</b>)
@@ -289,6 +302,58 @@
</source></p>
</section>
+<section name="Log file rotation">
+<p>
+The ISAPI redirector with version 1.2.31 can perform log rotation, with
configuration and behaviour similar to the
+<a
href="http://httpd.apache.org/docs/2.0/programs/rotatelogs.html">rotatelogs</a>
program provided with Apache HTTP Server.
+</p>
+<p>
+To configure log rotation, configure a <b>log_file</b>, and one of the
<b>log_rotationtime</b> or <b>log_filesize</b> options.
+If both are specified, the <b>log_rotationtime</b> will take precedence, and
<b>log_filesize</b> will be ignored.
+<br/>For example, to configure daily rotation of the log file:
+</p>
+<source>
+# Configuration file for the Jakarta ISAPI Redirector
+...
+
+# Full path to the log file for the ISAPI Redirector
+log_file=c:\tomcat\logs\isapi_redirect.%Y-%m-%d.log
+
+# Log level (debug, info, warn, error or trace)
+log_level=info
+
+# Rotate the log file every day
+log_rotationtime=86400
+
+...
+</source>
+<p>
+Or to configure rotation of the log file when it reaches 5MB in size:
+</p>
+<source>
+# Configuration file for the Jakarta ISAPI Redirector
+...
+
+# Full path to the log file for the ISAPI Redirector
+log_file=c:\tomcat\logs\isapi_redirect.%Y-%m-%d-%H.log
+
+# Log level (debug, info, warn, error or trace)
+log_level=info
+
+# Rotate the log file at 5 MB
+log_filesize=5M
+
+...
+</source>
+<p>
+The log will be rotated whenever the configured limit is reached, but only if
the log file name would change. If you configure
+ a log file name with <code>strftime(3)</code> format codes in it, then ensure
it specifies the same granularity
+ as the rotation time configured, e.g. <b>%Y-%m-%d</b> if rotating daily
(<b>log_rotationtime=86400</b>).
+<br/>See the <a
href="http://httpd.apache.org/docs/2.0/programs/rotatelogs.html">rotatelogs</a>
documentation for more examples.
+</p>
+
+</section>
+
<section name="Using a simple rewrite rules">
<p>
The ISAPI redirector with version 1.2.16 can do a simple URL rewriting.
Although not
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]