[PATCH] smsc specific logging

Stipe Tolj <[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Organization Wapme Systems AG
Message-ID <[email protected]>
Hi list,

inspired by Angel's HTTP admin command 'loglevel' I had my hands on
the 'logging every smsc to it's own log-file' task today. This was on
my TODO for some time.

Ok, this seems to work for me and it's pretty simple, without changing
to heavily the gwlib/log.[ch] logic.

Here is what it does:

  * gw/smscconn.c: adding new fields to the SMSCConn structure
      log_idx: holds the gwlib/log.c:logfiles[] array index we will
write to
      log_file: the log-file filename
      log_level: the log-level
  * gw/log.c:log_open() has to be extended to determine if we are
opening the log-file exlusively (GW_EXCL) or not (GW_NON_EXCL).
  * gw/bearerbox.c, gw/smsbox.c, gw/wapbox.c, and various others:
extend the log_open() call to indicate this log-file is opened in
GW_NON_EXCL mode.
  * gw/log.c: added thread_to[] array to map thread id to logfiles[]
index.
  * gw/log.c:log_thread_to() new function to allow smsc threads to
register to a specific logfiles[] array index to write their output to
an GW_EXCL log. This is done using an entry in the thread_to[] mapping
array.
  * gw/log.c:debug(), info(), warning(), error() checks if the current
thread has been registed for exlusive log file writing. If yes cann
FUNCTION_GUTS_EXCL instead of FUNCTION_GUTS which causes not to loop
throught all GW_NON_EXCL log files, but only to it's registered
GW_EXCL log file in the given logfiles[] entry.
  * gw/log.c:log_init() new initialization function to set all entries
within the thread_to[] mapping array to the default 0.
  * gwlib/gwlib.c: adding log_init() for the gwlib_init() call.
  * gwlib/log.c: a maximum of 128 log files can be opened now. 
  * doc/userguide/userguide.xml: the documentatin section for the smsc
group
  * gw/smsc_[at2|cgw|emi2|fake|http|smasi|smpp|wrapper].c: added
log_thread_to() registration calls to all working threads. They will
register the working thread to an GW_EXCL log in case a specific log
file should be used.


Ok, I hope you guys know now what I did ;)

Try on your own. I'd like to see some votes for this please. Have fun.

Stipe

[email protected]
-------------------------------------------------------------------
Wapme Systems AG

Vogelsanger Weg 80
40470 Düsseldorf

Tel: +49-211-74845-0
Fax: +49-211-74845-299

E-Mail: [email protected]
Internet: http://www.wapme-systems.de
-------------------------------------------------------------------
wapme.net - wherever you are
smsc-logging.diff (text/plain, 17.3 KB)
diff -ur gateway/doc/userguide/userguide.xml gateway-new/doc/userguide/userguide.xml
--- gateway/doc/userguide/userguide.xml	2003-02-27 21:33:11.000000000 +0100
+++ gateway-new/doc/userguide/userguide.xml	2003-02-27 21:42:54.000000000 +0100
@@ -2064,6 +2064,21 @@
      end. TCP/IP connection only.
      </entry></row>
 
+    <row><entry><literal>log-file</literal></entry>
+     <entry>filename</entry>
+     <entry valign="bottom">
+        A file in which to write a log of the given smsc output. Hence
+ 		  this allows to log smsc specific entries to a seperate file.
+     </entry></row>
+
+    <row><entry><literal>log-level</literal></entry>
+     <entry>number 0..5</entry>
+     <entry valign="bottom">
+        Minimum level of logfile events logged. 0 is for 'debug', 1
+        'info', 2 'warning, 3 'error' and 4 'panic' (see Command Line
+        Options)
+     </entry></row>
+
   </tbody>
   </tgroup>
  </table>
diff -ur gateway/gw/bearerbox.c gateway-new/gw/bearerbox.c
--- gateway/gw/bearerbox.c	2003-02-27 20:23:44.000000000 +0100
+++ gateway-new/gw/bearerbox.c	2003-02-27 21:43:55.000000000 +0100
@@ -300,7 +300,7 @@
     if (log != NULL) {
 	if (cfg_get_integer(&loglevel, grp, octstr_imm("log-level")) == -1)
 	    loglevel = 0;
-	log_open(octstr_get_cstr(log), loglevel);
+	log_open(octstr_get_cstr(log), loglevel, GW_NON_EXCL);
 	octstr_destroy(log);
     }
 
diff -ur gateway/gw/smsbox.c gateway-new/gw/smsbox.c
--- gateway/gw/smsbox.c	2003-02-27 20:23:44.000000000 +0100
+++ gateway-new/gw/smsbox.c	2003-02-27 21:44:02.000000000 +0100
@@ -2978,7 +2978,7 @@
     if (logfile != NULL) {
 	info(0, "Starting to log to file %s level %ld", 
 	     octstr_get_cstr(logfile), lvl);
-	log_open(octstr_get_cstr(logfile), lvl);
+	log_open(octstr_get_cstr(logfile), lvl, GW_NON_EXCL);
 	octstr_destroy(logfile);
     }
     if (global_sender != NULL) {
diff -ur gateway/gw/smsc/smsc_at2.c gateway-new/gw/smsc/smsc_at2.c
--- gateway/gw/smsc/smsc_at2.c	2003-01-29 23:59:52.000000000 +0100
+++ gateway-new/gw/smsc/smsc_at2.c	2003-02-27 22:11:48.000000000 +0100
@@ -832,6 +832,9 @@
 
     conn->status = SMSCCONN_CONNECTING;
 
+    /* Make sure we log into our own log-file if defined */
+    log_thread_to(conn->log_idx);
+
 reconnect:
 
     do {
diff -ur gateway/gw/smsc/smsc_cgw.c gateway-new/gw/smsc/smsc_cgw.c
--- gateway/gw/smsc/smsc_cgw.c	2003-02-26 23:15:59.000000000 +0100
+++ gateway-new/gw/smsc/smsc_cgw.c	2003-02-27 22:12:40.000000000 +0100
@@ -568,6 +568,9 @@
 
     conn->status = SMSCCONN_CONNECTING;
 
+    /* Make sure we log into our own log-file if defined */
+    log_thread_to(conn->log_idx);
+
     while (!privdata->shutdown) {
 
         // check that connection is active
@@ -915,6 +918,9 @@
     Connection	*server;
     int s, ret;
 
+    /* Make sure we log into our own log-file if defined */
+    log_thread_to(conn->log_idx);
+
     while (!privdata->shutdown) {
         server_addr_len = sizeof(server_addr);
 	
diff -ur gateway/gw/smsc/smsc_emi2.c gateway-new/gw/smsc/smsc_emi2.c
--- gateway/gw/smsc/smsc_emi2.c	2003-02-27 20:25:30.000000000 +0100
+++ gateway-new/gw/smsc/smsc_emi2.c	2003-02-27 22:10:29.000000000 +0100
@@ -1280,6 +1280,9 @@
     Msg *msg;
     Connection *server;
 
+    /* Make sure we log into our own log-file if defined */
+    log_thread_to(conn->log_idx);
+
     while (!privdata->shutdown) {
 	if ((server = open_send_connection(conn)) == NULL) {
 	    privdata->shutdown = 1;
@@ -1402,6 +1405,9 @@
     Connection	*server;
     int 	s, ret;
 
+    /* Make sure we log into our own log-file if defined */
+    log_thread_to(conn->log_idx);
+
     while (!privdata->shutdown) {
 	server_addr_len = sizeof(server_addr);
 	ret = gwthread_pollfd(privdata->listening_socket, POLLIN, -1);
diff -ur gateway/gw/smsc/smsc_fake.c gateway-new/gw/smsc/smsc_fake.c
--- gateway/gw/smsc/smsc_fake.c	2003-02-26 23:15:59.000000000 +0100
+++ gateway-new/gw/smsc/smsc_fake.c	2003-02-27 22:12:58.000000000 +0100
@@ -227,6 +227,9 @@
     int s, ret;
     Msg	*msg;
 
+    /* Make sure we log into our own log-file if defined */
+    log_thread_to(conn->log_idx);
+
     while (1) {
         client_addr_len = sizeof(client_addr);
         ret = gwthread_pollfd(privdata->listening_socket, POLLIN, -1);
diff -ur gateway/gw/smsc/smsc_http.c gateway-new/gw/smsc/smsc_http.c
--- gateway/gw/smsc/smsc_http.c	2003-02-26 23:15:59.000000000 +0100
+++ gateway-new/gw/smsc/smsc_http.c	2003-02-27 22:13:49.000000000 +0100
@@ -120,7 +120,10 @@
     HTTPClient *client;
     Octstr *ip, *url, *body;
     List *headers, *cgivars;
-    
+   
+    /* Make sure we log into our own log-file if defined */
+    log_thread_to(conn->log_idx);
+ 
     while(conndata->shutdown == 0) {
 
 	/* XXX if conn->is_stopped, do not receive new messages.. */
@@ -167,6 +170,9 @@
     List *headers;
     Octstr *final_url, *body;
 
+    /* Make sure we log into our own log-file if defined */
+    log_thread_to(conn->log_idx);
+
     while(conndata->shutdown == 0 || conndata->open_sends) {
 
 	msg = http_receive_result(conndata->http_ref, &status,
diff -ur gateway/gw/smsc/smsc_smasi.c gateway-new/gw/smsc/smsc_smasi.c
--- gateway/gw/smsc/smsc_smasi.c	2003-02-26 23:15:59.000000000 +0100
+++ gateway-new/gw/smsc/smsc_smasi.c	2003-02-27 22:14:45.000000000 +0100
@@ -860,6 +860,9 @@
 
     smasi = arg;
 
+    /* Make sure we log into our own log-file if defined */
+    log_thread_to(smasi->conn->log_idx);
+    
     while (!smasi->quitting) {
 
         conn = open_connection(smasi);
diff -ur gateway/gw/smsc/smsc_smpp.c gateway-new/gw/smsc/smsc_smpp.c
--- gateway/gw/smsc/smsc_smpp.c	2003-02-27 20:25:30.000000000 +0100
+++ gateway-new/gw/smsc/smsc_smpp.c	2003-02-27 22:08:52.000000000 +0100
@@ -1106,6 +1106,9 @@
     smpp = io_arg->smpp; 
     transmitter = io_arg->transmitter; 
     gw_free(io_arg); 
+
+    /* Make sure we log into our own log-file if defined */
+    log_thread_to(smpp->conn->log_idx);
  
     conn = NULL; 
     while (!smpp->quitting) { 
diff -ur gateway/gw/smsc/smsc_wrapper.c gateway-new/gw/smsc/smsc_wrapper.c
--- gateway/gw/smsc/smsc_wrapper.c	2002-11-11 01:55:56.000000000 +0100
+++ gateway-new/gw/smsc/smsc_wrapper.c	2003-02-27 22:15:23.000000000 +0100
@@ -140,6 +140,8 @@
     /* SmscWrapper *wrap = conn->data; ** non-used */
     double 	sleep = 0.0001;
     
+    /* Make sure we log into our own log-file if defined */
+    log_thread_to(conn->log_idx);
     
     /* remove messages from SMSC until we are killed */
     while(conn->why_killed == SMSCCONN_ALIVE) {
@@ -202,6 +204,9 @@
     SMSCConn 	*conn = arg;
     SmscWrapper *wrap = conn->data;
 
+    /* Make sure we log into our own log-file if defined */
+    log_thread_to(conn->log_idx);
+
     /* send messages to SMSC until our putgoing_list is empty and
      * no producer anymore (we are set to shutdown) */
     while(conn->status != SMSCCONN_DEAD) {
diff -ur gateway/gw/smscconn.c gateway-new/gw/smscconn.c
--- gateway/gw/smscconn.c	2003-02-27 20:23:44.000000000 +0100
+++ gateway-new/gw/smscconn.c	2003-02-27 21:57:49.000000000 +0100
@@ -45,6 +45,8 @@
     conn->stop_conn = NULL;
     conn->start_conn = NULL;
 
+    conn->log_idx = 0;
+
 #define GET_OPTIONAL_VAL(x, n) x = cfg_get(grp, octstr_imm(n))
     
     GET_OPTIONAL_VAL(conn->id, "smsc-id");
@@ -56,6 +58,15 @@
     GET_OPTIONAL_VAL(conn->preferred_prefix, "preferred-prefix");
     GET_OPTIONAL_VAL(conn->unified_prefix, "unified-prefix");
     GET_OPTIONAL_VAL(conn->our_host, "our-host");
+    GET_OPTIONAL_VAL(conn->log_file, "log-file");
+    
+    if (cfg_get_integer(&conn->log_level, grp, octstr_imm("log-level")) == -1)
+        conn->log_level = 0;
+
+    /* open a smsc-id specific log-file in exlusive mode */
+    if (conn->log_file)
+        conn->log_idx = log_open(octstr_get_cstr(conn->log_file), 
+                                 conn->log_level, GW_EXCL); 
 
     if (conn->allowed_smsc_id && conn->denied_smsc_id)
 	warning(0, "Both 'allowed-smsc-id' and 'denied-smsc-id' set, deny-list "
@@ -139,6 +150,8 @@
     octstr_destroy(conn->allowed_prefix);
     octstr_destroy(conn->preferred_prefix);
     octstr_destroy(conn->unified_prefix);
+    octstr_destroy(conn->our_host);
+    octstr_destroy(conn->log_file);
     
     mutex_unlock(conn->flow_mutex);
     mutex_destroy(conn->flow_mutex);
diff -ur gateway/gw/smscconn_p.h gateway-new/gw/smscconn_p.h
--- gateway/gw/smscconn_p.h	2003-02-27 20:23:44.000000000 +0100
+++ gateway-new/gw/smscconn_p.h	2003-02-27 21:54:50.000000000 +0100
@@ -120,7 +120,13 @@
     Octstr *preferred_prefix;
     Octstr *unified_prefix;
     
-    Octstr *our_host;
+    Octstr *our_host;   /* local device IP to bind for TCP communication */
+
+    /* Our smsc specific log-file data */
+    Octstr *log_file;
+    long log_level;
+    int log_idx;    /* index position within the global logfiles[] array in gwlib/log.c */
+
 
     /* XXX: move rest global data from Smsc here
      */
diff -ur gateway/gw/wapbox.c gateway-new/gw/wapbox.c
--- gateway/gw/wapbox.c	2003-02-27 20:23:44.000000000 +0100
+++ gateway-new/gw/wapbox.c	2003-02-27 21:44:09.000000000 +0100
@@ -117,7 +117,7 @@
     if (cfg_get_integer(&logfilelevel, grp, octstr_imm("log-level")) == -1)
     	logfilelevel = 0;
     if (logfile != NULL) {
-        log_open(octstr_get_cstr(logfile), logfilelevel);
+        log_open(octstr_get_cstr(logfile), logfilelevel, GW_NON_EXCL);
         info(0, "Starting to log to file %s level %ld", 
              octstr_get_cstr(logfile), logfilelevel);
     }
diff -ur gateway/gwlib/cfg.def gateway-new/gwlib/cfg.def
--- gateway/gwlib/cfg.def	2003-02-27 20:25:31.000000000 +0100
+++ gateway-new/gwlib/cfg.def	2003-02-27 21:46:44.000000000 +0100
@@ -184,6 +184,8 @@
     OCTSTR(preferred-prefix)
     OCTSTR(unified-prefix)
     OCTSTR(alt-charset)
+    OCTSTR(log-file)
+    OCTSTR(log-level)
     OCTSTR(host)
     OCTSTR(alt-host)
     OCTSTR(port)
diff -ur gateway/gwlib/gwlib.c gateway-new/gwlib/gwlib.c
--- gateway/gwlib/gwlib.c	2003-02-27 20:25:31.000000000 +0100
+++ gateway-new/gwlib/gwlib.c	2003-02-27 21:58:30.000000000 +0100
@@ -29,6 +29,7 @@
     http_init();
     socket_init();
     charset_init();
+    log_init();
     init = 1;
 }
 
diff -ur gateway/gwlib/log.c gateway-new/gwlib/log.c
--- gateway/gwlib/log.c	2003-02-27 21:24:09.000000000 +0100
+++ gateway-new/gwlib/log.c	2003-02-27 22:27:30.000000000 +0100
@@ -39,15 +39,24 @@
 /*
  * List of currently open log files.
  */
-#define MAX_LOGFILES 8
+#define MAX_LOGFILES 128
 static struct {
     FILE *file;
     int minimum_output_level;
     char filename[FILENAME_MAX + 1]; /* to allow re-open */
+    enum excl_state exclusive;
 } logfiles[MAX_LOGFILES];
 static int num_logfiles = 0;
 
 
+/* 
+ * Mapping array between thread id and logfiles[] index.
+ * This is used for smsc specific logging.
+ */
+#define THREADTABLE_SIZE 1024
+static unsigned int thread_to[THREADTABLE_SIZE];
+
+
 /*
  * List of places that should be logged at debug-level.
  */
@@ -75,10 +84,22 @@
 	    return;
     logfiles[num_logfiles].file = stderr;
     logfiles[num_logfiles].minimum_output_level = GW_DEBUG;
+    logfiles[num_logfiles].exclusive = GW_NON_EXCL;
     ++num_logfiles;
 }
 
 
+void log_init()
+{
+    unsigned long i;
+
+    /* default all possible thread to logging index 0, stderr */
+    for (i = 0; i <= THREADTABLE_SIZE; i++) {
+        thread_to[i] = 0;
+    }
+}
+
+
 void log_set_output_level(enum output_level level) 
 {
     int i;
@@ -148,7 +169,7 @@
 }
 
 
-void log_open(char *filename, int level) 
+int log_open(char *filename, int level, enum excl_state excl) 
 {
     FILE *f;
     
@@ -172,9 +193,12 @@
     
     logfiles[num_logfiles].file = f;
     logfiles[num_logfiles].minimum_output_level = level;
+    logfiles[num_logfiles].exclusive = excl;
     strcpy(logfiles[num_logfiles].filename, filename);
     ++num_logfiles;
     info(0, "Added logfile `%s' with level `%d'.", filename, level);
+
+    return (num_logfiles - 1);
 }
 
 
@@ -296,7 +320,8 @@
 	    add_stderr(); \
 	    format(buf, level, place, e, fmt); \
 	    for (i = 0; i < num_logfiles; ++i) { \
-		if (level >= logfiles[i].minimum_output_level) { \
+		if (logfiles[i].exclusive == GW_NON_EXCL && \
+            level >= logfiles[i].minimum_output_level) { \
 		    va_start(args, fmt); \
 		    output(logfiles[i].file, buf, args); \
 		    va_end(args); \
@@ -309,9 +334,29 @@
 	    } \
 	} while (0)
 
+#define FUNCTION_GUTS_EXCL(level, place) \
+	do { \
+	    int i; \
+	    char buf[FORMAT_SIZE]; \
+	    va_list args; \
+	    \
+	    add_stderr(); \
+	    format(buf, level, place, 0, fmt); \
+        if (logfiles[e].exclusive == GW_EXCL && \
+            level >= logfiles[e].minimum_output_level) { \
+            va_start(args, fmt); \
+            output(logfiles[e].file, buf, args); \
+            va_end(args); \
+        } \
+	} while (0)
+
 
 void gw_panic(int e, const char *fmt, ...) 
 {
+    /* 
+     * we don't want PANICs to spread accross smsc logs, so
+     * this will be always within the main core log.
+     */
     FUNCTION_GUTS(GW_PANIC, "");
     exit(EXIT_FAILURE);
 }
@@ -319,19 +364,31 @@
 
 void error(int e, const char *fmt, ...) 
 {
-    FUNCTION_GUTS(GW_ERROR, "");
+    if ((e = thread_to[gwthread_self()])) {
+        FUNCTION_GUTS_EXCL(GW_ERROR, "");
+    } else {
+        FUNCTION_GUTS(GW_ERROR, "");
+    }
 }
 
 
 void warning(int e, const char *fmt, ...) 
 {
-    FUNCTION_GUTS(GW_WARNING, "");
+    if ((e = thread_to[gwthread_self()])) {
+        FUNCTION_GUTS_EXCL(GW_WARNING, "");
+    } else {
+        FUNCTION_GUTS(GW_WARNING, "");
+    }
 }
 
 
 void info(int e, const char *fmt, ...) 
 {
-   FUNCTION_GUTS(GW_INFO, "");
+    if ((e = thread_to[gwthread_self()])) {
+        FUNCTION_GUTS_EXCL(GW_INFO, "");
+    } else {
+        FUNCTION_GUTS(GW_INFO, "");
+    }
 }
 
 
@@ -379,13 +436,17 @@
 void debug(const char *place, int e, const char *fmt, ...) 
 {
     if (place_should_be_logged(place) && place_is_not_logged(place) == 0) {
-	FUNCTION_GUTS(GW_DEBUG, "");
 	/*
 	 * Note: giving `place' to FUNCTION_GUTS makes log lines
     	 * too long and hard to follow. We'll rely on an external
     	 * list of what places are used instead of reading them
     	 * from the log file.
 	 */
+        if ((e = thread_to[gwthread_self()])) {
+            FUNCTION_GUTS_EXCL(GW_DEBUG, "");
+        } else {
+            FUNCTION_GUTS(GW_DEBUG, "");
+        }
     }
 }
 
@@ -401,3 +462,14 @@
 	p = strtok(NULL, " ,");
     }
 }
+
+
+void log_thread_to(unsigned int idx)
+{
+    long thread_id = gwthread_self();
+
+    info(0, "Logging thread `%ld' to logfile `%s' with level `%d'.", 
+         thread_id, &logfiles[idx].filename, logfiles[idx].minimum_output_level);
+    thread_to[thread_id] = idx;
+}
+
diff -ur gateway/gwlib/log.h gateway-new/gwlib/log.h
--- gateway/gwlib/log.h	2003-02-27 21:28:37.000000000 +0100
+++ gateway-new/gwlib/log.h	2003-02-27 22:07:26.000000000 +0100
@@ -22,6 +22,14 @@
 	GW_DEBUG, GW_INFO, GW_WARNING, GW_ERROR, GW_PANIC
 };
 
+/* defines if a log-file is exclusive or not */
+enum excl_state {
+    GW_NON_EXCL, GW_EXCL
+};
+
+/* Initialize the log file module */
+void log_init();
+
 /* Print a panicky error message and terminate the program with a failure.
  * So, this function is called when there is no other choice than to exit
  * immediately, with given reason
@@ -87,8 +95,11 @@
 /* Start logging to a file as well. The file will get messages at least of
    level `level'. There is no need and no way to close the log file;
    it will be closed automatically when the program finishes. Failures
-   when opening to the log file are printed to stderr. */
-void log_open(char *filename, int level);
+   when opening to the log file are printed to stderr. 
+   Where `excl' defines if the log file will be exclusive or not.
+   Returns the index within the global logfiles[] array where this
+   log file entry has been added. */
+int log_open(char *filename, int level, enum excl_state excl);
 
 /* Close and re-open all logfiles */
 void log_reopen(void);
@@ -98,4 +109,10 @@
  */
 void log_close_all(void);
 
+/* 
+ * Register a thread to a specific logfiles[] index and hence 
+ * to a specific exclusive log file.
+ */
+void log_thread_to(unsigned int idx);
+
 #endif
diff -ur gateway/gwlib/utils.c gateway-new/gwlib/utils.c
--- gateway/gwlib/utils.c	2003-02-27 20:25:31.000000000 +0100
+++ gateway-new/gwlib/utils.c	2003-02-27 21:45:01.000000000 +0100
@@ -133,7 +133,7 @@
     if (debug_places != NULL)
         log_set_debug_places(debug_places);
     if (log_file != NULL)
-	log_open(log_file, file_lvl);
+	log_open(log_file, file_lvl, GW_NON_EXCL);
 
     info(0, "Debug_lvl = %d, log_file = %s, log_lvl = %d",
 	  debug_lvl, log_file ? log_file : "<none>", file_lvl);
diff -ur gateway/test/drive_smpp.c gateway-new/test/drive_smpp.c
--- gateway/test/drive_smpp.c	2003-02-27 20:25:31.000000000 +0100
+++ gateway-new/test/drive_smpp.c	2003-02-27 21:45:07.000000000 +0100
@@ -470,7 +470,7 @@
     }
 
     if (log_file != NULL)
-    	log_open(log_file, GW_DEBUG);
+    	log_open(log_file, GW_DEBUG, GW_NON_EXCL);
 
     info(0, "Starting drive_smpp test.");
     gwthread_create(accept_thread, &port);
diff -ur gateway/test/wml_tester.c gateway-new/test/wml_tester.c
--- gateway/test/wml_tester.c	2003-02-27 20:25:31.000000000 +0100
+++ gateway-new/test/wml_tester.c	2003-02-27 21:45:16.000000000 +0100
@@ -146,7 +146,7 @@
 
 	    if (file && outputti != BINARY_OUT) {
 		fclose(fp);
-		log_open(octstr_get_cstr(filename), 0);
+		log_open(octstr_get_cstr(filename), 0, GW_NON_EXCL);
 		octstr_dump(wml_binary, 0);
 		log_close_all();
 		fp = fopen(octstr_get_cstr(filename), "a");
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.