mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-27 03:20:22 +08:00
ITS#6949 add support for logfile rotation
Uses debuglevel, not sysloglevel.
This commit is contained in:
parent
27a5424371
commit
9f4de680e3
@ -567,10 +567,23 @@ option description. The default is 71.
|
||||
Specify a file for recording slapd debug messages. By default these messages
|
||||
only go to stderr, are not recorded anywhere else, and are unrelated to
|
||||
messages exposed by the
|
||||
.B loglevel
|
||||
.B olcLogLevel
|
||||
configuration parameter. Specifying a logfile copies messages to both stderr
|
||||
and the logfile.
|
||||
.TP
|
||||
.B olcLogFileOnly: TRUE | FALSE
|
||||
Specify that debug messages should only go to the configured logfile, and
|
||||
not to stderr.
|
||||
.TP
|
||||
.B olcLogFileRotate: <max> <Mbytes> <hours>
|
||||
Specify automatic rotation for the configured logfile as the maximum
|
||||
number of old logfiles to retain, a maximum size in megabytes to allow a
|
||||
logfile to grow before rotation, and a maximum age in hours for a logfile
|
||||
to be used before rotation. The maximum number must be in the range 1-99.
|
||||
Setting Mbytes or hours to zero disables the size or age check, respectively.
|
||||
At least one of Mbytes or hours must be non-zero. By default no automatic
|
||||
rotation will be performed.
|
||||
.TP
|
||||
.B olcLogLevel: <integer> [...]
|
||||
Specify the level at which debugging statements and operation
|
||||
statistics should be syslogged (currently logged to the
|
||||
|
@ -625,6 +625,19 @@ messages exposed by the
|
||||
configuration parameter. Specifying a logfile copies messages to both stderr
|
||||
and the logfile.
|
||||
.TP
|
||||
.B logfile-only on | off
|
||||
Specify that debug messages should only go to the configured logfile, and
|
||||
not to stderr.
|
||||
.TP
|
||||
.B logfile-rotate <max> <Mbytes> <hours>
|
||||
Specify automatic rotation for the configured logfile as the maximum
|
||||
number of old logfiles to retain, a maximum size in megabytes to allow a
|
||||
logfile to grow before rotation, and a maximum age in hours for a logfile
|
||||
to be used before rotation. The maximum number must be in the range 1-99.
|
||||
Setting Mbytes or hours to zero disables the size or age check, respectively.
|
||||
At least one of Mbytes or hours must be non-zero. By default no automatic
|
||||
rotation will be performed.
|
||||
.TP
|
||||
.B loglevel <integer> [...]
|
||||
Specify the level at which debugging statements and operation
|
||||
statistics should be syslogged (currently logged to the
|
||||
|
@ -80,8 +80,6 @@ typedef struct {
|
||||
static CfBackInfo cfBackInfo;
|
||||
|
||||
static char *passwd_salt;
|
||||
static FILE *logfile;
|
||||
static char *logfileName;
|
||||
static AccessControl *defacl_parsed = NULL;
|
||||
|
||||
static struct berval cfdir;
|
||||
@ -203,6 +201,7 @@ enum {
|
||||
CFG_TLS_CACERT,
|
||||
CFG_TLS_CERT,
|
||||
CFG_TLS_KEY,
|
||||
CFG_LOGFILE_ROTATE,
|
||||
|
||||
CFG_LAST
|
||||
};
|
||||
@ -486,6 +485,14 @@ static ConfigTable config_back_cf_table[] = {
|
||||
&config_generic, "( OLcfgGlAt:27 NAME 'olcLogFile' "
|
||||
"EQUALITY caseExactMatch "
|
||||
"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
|
||||
{ "logfile-only", "on|off", 2, 2, 0, ARG_ON_OFF,
|
||||
&logfile_only, "( OLcfgGlAt:102 NAME 'olcLogFileOnly' "
|
||||
"EQUALITY booleanMatch "
|
||||
"SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
|
||||
{ "logfile-rotate", "max> <Mbyte> <hours", 4, 4, 0, ARG_MAGIC|CFG_LOGFILE_ROTATE,
|
||||
&config_generic, "( OLcfgGlAt:103 NAME 'olcLogFileRotate' "
|
||||
"EQUALITY caseIgnoreMatch "
|
||||
"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
|
||||
{ "loglevel", "level", 2, 0, 0, ARG_MAGIC,
|
||||
&config_loglevel, "( OLcfgGlAt:28 NAME 'olcLogLevel' "
|
||||
"EQUALITY caseIgnoreMatch "
|
||||
@ -980,7 +987,7 @@ static ConfigOCs cf_ocs[] = {
|
||||
"olcIndexSubstrAnyLen $ olcIndexSubstrAnyStep $ olcIndexHash64 $ "
|
||||
"olcIndexIntLen $ "
|
||||
"olcListenerThreads $ olcLocalSSF $ olcLogFile $ olcLogLevel $ "
|
||||
"olcMaxFilterDepth $ "
|
||||
"olcLogFileOnly $ olcLogFileRotate $ olcMaxFilterDepth $ "
|
||||
"olcPasswordCryptSaltFormat $ olcPasswordHash $ olcPidFile $ "
|
||||
"olcPluginLogFile $ olcReadOnly $ olcReferral $ "
|
||||
"olcReplogFile $ olcRequires $ olcRestrict $ olcReverseLookup $ "
|
||||
@ -1373,11 +1380,27 @@ config_generic(ConfigArgs *c) {
|
||||
rc = 1;
|
||||
}
|
||||
break;
|
||||
case CFG_LOGFILE:
|
||||
if ( logfileName )
|
||||
case CFG_LOGFILE: {
|
||||
const char *logfileName = logfile_name();
|
||||
if ( logfileName && *logfileName )
|
||||
c->value_string = ch_strdup( logfileName );
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
break;
|
||||
case CFG_LOGFILE_ROTATE:
|
||||
rc = 1;
|
||||
if ( logfile_max ) {
|
||||
char buf[64];
|
||||
struct berval bv;
|
||||
bv.bv_len = snprintf( buf, sizeof(buf), "%d %ld %ld", logfile_max,
|
||||
(long) logfile_fslimit / 1048576, (long) logfile_age / 3600 );
|
||||
if ( bv.bv_len > 0 && bv.bv_len < sizeof(buf) ) {
|
||||
bv.bv_val = buf;
|
||||
value_add_one( &c->rvalue_vals, &bv );
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CFG_LASTMOD:
|
||||
c->value_int = (SLAP_NOLASTMOD(c->be) == 0);
|
||||
@ -1610,12 +1633,11 @@ config_generic(ConfigArgs *c) {
|
||||
break;
|
||||
|
||||
case CFG_LOGFILE:
|
||||
ch_free( logfileName );
|
||||
logfileName = NULL;
|
||||
if ( logfile ) {
|
||||
fclose( logfile );
|
||||
logfile = NULL;
|
||||
}
|
||||
logfile_close();
|
||||
break;
|
||||
|
||||
case CFG_LOGFILE_ROTATE:
|
||||
logfile_max = logfile_fslimit = logfile_age = 0;
|
||||
break;
|
||||
|
||||
case CFG_SERVERID: {
|
||||
@ -2392,11 +2414,44 @@ sortval_reject:
|
||||
}
|
||||
break;
|
||||
case CFG_LOGFILE: {
|
||||
if ( logfileName ) ch_free( logfileName );
|
||||
logfileName = c->value_string;
|
||||
logfile = fopen(logfileName, "w");
|
||||
if(logfile) lutil_debug_file(logfile);
|
||||
} break;
|
||||
int rc = logfile_open( c->value_string );
|
||||
ch_free( c->value_string );
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
|
||||
case CFG_LOGFILE_ROTATE: {
|
||||
unsigned lf_max, lf_mbyte, lf_hour;
|
||||
if ( lutil_atoux( &lf_max, c->argv[1], 0 ) != 0 ) {
|
||||
snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> "
|
||||
"invalid max value \"%s\"", c->argv[0], c->argv[1] );
|
||||
return 1;
|
||||
}
|
||||
if ( !lf_max || lf_max > 99 ) {
|
||||
snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> "
|
||||
"invalid max value \"%s\" must be 1-99", c->argv[0], c->argv[1] );
|
||||
return 1;
|
||||
}
|
||||
if ( lutil_atoux( &lf_mbyte, c->argv[2], 0 ) != 0 ) {
|
||||
snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> "
|
||||
"invalid Mbyte value \"%s\"", c->argv[0], c->argv[1] );
|
||||
return 1;
|
||||
}
|
||||
if ( lutil_atoux( &lf_hour, c->argv[3], 0 ) != 0 ) {
|
||||
snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> "
|
||||
"invalid hours value \"%s\"", c->argv[0], c->argv[2] );
|
||||
return 1;
|
||||
}
|
||||
if ( !lf_mbyte && !lf_hour ) {
|
||||
snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> "
|
||||
"Mbyte and hours cannot both be zero", c->argv[0] );
|
||||
return 1;
|
||||
}
|
||||
logfile_max = lf_max;
|
||||
logfile_fslimit = lf_mbyte * 1048576; /* Megabytes to bytes */
|
||||
logfile_age = lf_hour * 3600; /* hours to seconds */
|
||||
}
|
||||
break;
|
||||
|
||||
case CFG_LASTMOD:
|
||||
if(SLAP_NOLASTMODCMD(c->be)) {
|
||||
|
@ -35,6 +35,10 @@
|
||||
#include <ac/wait.h>
|
||||
#include <ac/errno.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/uio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "slap.h"
|
||||
#include "lutil.h"
|
||||
#include "ldif.h"
|
||||
@ -377,27 +381,121 @@ usage( char *name )
|
||||
);
|
||||
}
|
||||
|
||||
static char logfile_suffix[sizeof(".xx.gz")];
|
||||
char logfile_path[MAXPATHLEN - sizeof(logfile_suffix) -1];
|
||||
long logfile_fslimit;
|
||||
int logfile_age, logfile_only, logfile_max;
|
||||
|
||||
static ldap_pvt_thread_mutex_t logfile_mutex;
|
||||
static off_t logfile_fsize;
|
||||
static time_t logfile_fcreated;
|
||||
static int logfile_fd;
|
||||
static char logpaths[2][MAXPATHLEN];
|
||||
static int logpathlen;
|
||||
|
||||
typedef void (BER_logger)(const char *buf);
|
||||
static BER_logger *ber_logger;
|
||||
static void debug_print( const char *data )
|
||||
{
|
||||
char buf[4136]; /* 4096 + 40 */
|
||||
char prefix[sizeof("ssssssssssssssss.ffffffff 0xtttttttttttttttt ")];
|
||||
struct iovec iov[2];
|
||||
int rotate = 0;
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
struct timespec tv;
|
||||
#define TS "%08x"
|
||||
#define Tfrac tv.tv_nsec
|
||||
clock_gettime( CLOCK_REALTIME, &tv );
|
||||
#define gettime(tv) clock_gettime( CLOCK_REALTIME, tv )
|
||||
#else
|
||||
struct timeval tv;
|
||||
#define TS "%05x"
|
||||
#define Tfrac tv.tv_usec
|
||||
gettimeofday( &tv, NULL );
|
||||
#define gettime(tv) gettimeofday( tv, NULL )
|
||||
#endif
|
||||
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
snprintf( buf, sizeof(buf)-1, "%lx." TS " %p %s",
|
||||
(long)tv.tv_sec, Tfrac, (void *)ldap_pvt_thread_self(), data );
|
||||
ber_logger( buf );
|
||||
gettime( &tv );
|
||||
iov[0].iov_base = prefix;
|
||||
iov[0].iov_len = sprintf( prefix, "%lx." TS " %p ",
|
||||
(long)tv.tv_sec, (unsigned int)Tfrac, (void *)ldap_pvt_thread_self() );
|
||||
iov[1].iov_base = (void *)data;
|
||||
iov[1].iov_len = strlen( data );
|
||||
if ( !logfile_only )
|
||||
writev( 2, iov, 2 );
|
||||
if ( logfile_fd ) {
|
||||
int len = iov[0].iov_len + iov[1].iov_len;
|
||||
if ( logfile_fslimit || logfile_age ) {
|
||||
ldap_pvt_thread_mutex_lock( &logfile_mutex );
|
||||
if ( logfile_fslimit && logfile_fsize + len > logfile_fslimit )
|
||||
rotate = 1;
|
||||
if ( logfile_age && tv.tv_sec - logfile_fcreated >= logfile_age )
|
||||
rotate |= 2;
|
||||
if ( rotate ) {
|
||||
close( logfile_fd );
|
||||
strcpy( logpaths[0]+logpathlen, ".tmp" );
|
||||
rename( logfile_path, logpaths[0] );
|
||||
logfile_open( logfile_path );
|
||||
}
|
||||
}
|
||||
len = writev( logfile_fd, iov, 2 );
|
||||
if ( len > 0 )
|
||||
logfile_fsize += len;
|
||||
if ( logfile_fslimit || logfile_age )
|
||||
ldap_pvt_thread_mutex_unlock( &logfile_mutex );
|
||||
}
|
||||
if ( rotate ) {
|
||||
int i;
|
||||
for (i=logfile_max; i > 1; i--) {
|
||||
sprintf( logpaths[0]+logpathlen, ".%02d", i );
|
||||
sprintf( logpaths[1]+logpathlen, ".%02d", i-1 );
|
||||
rename( logpaths[1], logpaths[0] );
|
||||
}
|
||||
sprintf( logpaths[0]+logpathlen, ".tmp" );
|
||||
rename( logpaths[0], logpaths[1] );
|
||||
}
|
||||
}
|
||||
|
||||
void logfile_close()
|
||||
{
|
||||
if ( logfile_fd ) {
|
||||
close( logfile_fd );
|
||||
logfile_fd = 0;
|
||||
}
|
||||
logfile_path[0] = '\0';
|
||||
}
|
||||
|
||||
int logfile_open( const char *path )
|
||||
{
|
||||
struct stat st;
|
||||
int fd;
|
||||
|
||||
fd = open( path, O_CREAT|O_WRONLY, 0640 );
|
||||
if ( fd < 0 )
|
||||
return errno;
|
||||
|
||||
if ( fstat( fd, &st )) {
|
||||
close( fd );
|
||||
return errno;
|
||||
}
|
||||
|
||||
if ( !logfile_path[0] ) {
|
||||
logpathlen = strlen( path );
|
||||
if ( logpathlen >= sizeof(logfile_path) )
|
||||
return ENAMETOOLONG;
|
||||
strcpy( logfile_path, path );
|
||||
strcpy( logpaths[0], path );
|
||||
strcpy( logpaths[1], path );
|
||||
}
|
||||
|
||||
logfile_fsize = st.st_size;
|
||||
logfile_fcreated = st.st_ctime; /* not strictly true but close enough */
|
||||
logfile_fd = fd;
|
||||
lseek( fd, 0, SEEK_END );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *logfile_name()
|
||||
{
|
||||
return logfile_path[0] ? logfile_path : NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_NT_SERVICE_MANAGER
|
||||
@ -449,8 +547,8 @@ int main( int argc, char **argv )
|
||||
|
||||
slap_sl_mem_init();
|
||||
|
||||
|
||||
(void) ldap_pvt_thread_initialize();
|
||||
ldap_pvt_thread_mutex_init( &logfile_mutex );
|
||||
|
||||
serverName = lutil_progname( "slapd", argc, argv );
|
||||
|
||||
@ -1164,6 +1262,7 @@ stop:
|
||||
mal_dumpleaktrace( leakfile );
|
||||
#endif
|
||||
|
||||
ldap_pvt_thread_mutex_destroy( &logfile_mutex );
|
||||
MAIN_RETURN(rc);
|
||||
}
|
||||
|
||||
|
@ -1254,6 +1254,16 @@ LDAP_SLAPD_F (int)
|
||||
parse_debug_unknowns LDAP_P(( char **unknowns, int *levelp ));
|
||||
LDAP_SLAPD_F (void)
|
||||
slap_check_unknown_level LDAP_P(( char *levelstr, int level ));
|
||||
LDAP_SLAPD_F (int)
|
||||
logfile_open LDAP_P(( const char *path ));
|
||||
LDAP_SLAPD_F (void)
|
||||
logfile_close LDAP_P(( void ));
|
||||
LDAP_SLAPD_F (const char *)
|
||||
logfile_name LDAP_P(( void ));
|
||||
LDAP_SLAPD_V(int) logfile_age;
|
||||
LDAP_SLAPD_V(int) logfile_only;
|
||||
LDAP_SLAPD_V(int) logfile_max;
|
||||
LDAP_SLAPD_V(long) logfile_fslimit;
|
||||
|
||||
/*
|
||||
* matchedValues.c
|
||||
|
Loading…
Reference in New Issue
Block a user