1 /*
2  * test_rollingfile_appender.c
3  *
4  * This file  demonstrates how to programatically use the rolling
5  * file appender and tests it in a multi-threaded environment.  See
6  * also the API documentation for the appender_type_rollingfile.h file.
7  *
8  * It is possible to be more terse here if you accept the default values,
9  * but we spell it out explicitly.
10  *
11  * See the COPYING file for the terms of usage and distribution.
12  */
13 
14  #ifdef HAVE_CONFIG_H
15  #include "config.h"
16  #endif
17 
18 #include <stdio.h>
19 #ifdef HAVE_SYS_TIME_H
20 #include <sys/time.h>
21 #endif
22 #ifdef HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
25 #ifdef HAVE_PTHREAD_H
26 #include <pthread.h>
27 #endif
28 #include <string.h>
29 #include <stdlib.h>
30 #include <log4c.h>
31 #include <log4c/appender_type_rollingfile.h>
32 #include <log4c/rollingpolicy_type_sizewin.h>
33 
34 /*
35  * Include sd_xplatform to pick up handy xplatform macros.
36  * This file is not part of the distribution of log4c so an application using the
37  * distribution of log4c must handle it's own x-platform issues: eg. threading,
38  * the slight differences between the c functions etc.
39 */
40 #include <sd/sd_xplatform.h>
41 
42 /*********************** Parameters **********************************
43  *
44  * could be taken from the command line to facilitate testing
45  *
46 */
47 
48 /*
49  * rolling file specific params
50 */
51 char *param_log_dir = ROLLINGFILE_DEFAULT_LOG_DIR;
52 char* param_log_prefix = ROLLINGFILE_DEFAULT_LOG_PREFIX"rfmt";
53 long param_max_file_size = 10*1024; /* 0 means 'no_limit' */
54 long param_max_num_files = 6;
55 
56 /*
57  * Other Logging params
58 */
59 char *param_layout_to_use = "basic"; /* could also be "dated" */
60 #define PARAM_NUM_THREADS 10
61 int param_loops_per_thread = 100;
62 
63 /*******************************************************************
64  *
65  * Globals
66  *
67  */
68 log4c_category_t* root = NULL;
69 log4c_appender_t* file_appender = NULL;
70 log4c_layout_t* basic_layout = NULL;
71 /******************************************************************************
72 *
73 * Local functions
74 */
75 
76 typedef XP_UINT64 usec_t;
now(void)77 static usec_t now(void)
78 {
79 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__)
80  FILETIME tv;
81  ULARGE_INTEGER   li;
82 #else
83  struct timeval tv;
84 #endif
85 
86    SD_GETTIMEOFDAY(&tv, NULL);
87 
88 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__)
89 	memcpy(&li, &tv, sizeof(FILETIME));
90 	li.QuadPart /= 10;                /* In microseconds */
91 	/* printf("timestampstamp usec %I64u\n", li.QuadPart);*/
92 	return li.QuadPart;
93 #else
94   return (usec_t) (tv.tv_sec * 1000000 + tv.tv_usec);
95 #endif
96 
97 }
98 
99 /******************************************************************************/
100 
101 /*
102  * Init log4c and configure a rolling file appender
103  *
104 */
init_log4c_with_rollingfile_appender()105 static void init_log4c_with_rollingfile_appender(){
106   int rc = 2;
107   rollingfile_udata_t *rfup = NULL;
108   log4c_rollingpolicy_t *policyp = NULL;
109   rollingpolicy_sizewin_udata_t *sizewin_confp = NULL;
110 
111   printf("using the rolling file appender with multiple logging threads"
112           "to write test log files\n"
113           "to log directory '%s', log file prefix is '%s'"
114           ", max file size is '%ld'\n"
115           "max num files is '%ld'\n",
116           param_log_dir, param_log_prefix, param_max_file_size,
117           param_max_num_files);
118 
119   if ( (rc = log4c_init()) == 0 ) {
120     printf("log4c init success\n");
121   } else {
122     printf("log4c init failed--error %d\n", rc);
123     return;
124   }
125 
126   /*
127    * Get a reference to the root category
128   */
129   root = log4c_category_get("root");
130   log4c_category_set_priority(root,
131 			      LOG4C_PRIORITY_WARN);
132 
133   /*
134    * Get a file appender and set the type to rollingfile
135   */
136   file_appender = log4c_appender_get("aname");
137   log4c_appender_set_type(file_appender,
138     log4c_appender_type_get("rollingfile"));
139 
140   /*
141    * Make a rolling file conf object and set the basic parameters
142   */
143   rfup = rollingfile_make_udata();
144   rollingfile_udata_set_logdir(rfup, param_log_dir);
145   rollingfile_udata_set_files_prefix(rfup, param_log_prefix);
146 
147   /*
148    * Get a new rollingpolicy
149    * type defaults to "sizewin" but set the type explicitly here
150    * to show how to do it.
151   */
152   policyp = log4c_rollingpolicy_get("a_policy_name");
153   log4c_rollingpolicy_set_type(policyp,
154               log4c_rollingpolicy_type_get("sizewin"));
155 
156   /*
157    * Get a new sizewin policy type and configure it.
158    * Then attach it to the policy object.
159   */
160   sizewin_confp = sizewin_make_udata();
161   sizewin_udata_set_file_maxsize(sizewin_confp, param_max_file_size);
162   sizewin_udata_set_max_num_files(sizewin_confp, param_max_num_files);
163   log4c_rollingpolicy_set_udata(policyp,sizewin_confp);
164 
165   /*
166    * Configure our rolling policy, then use that to configure
167    * our rolling file appender.
168   */
169 
170   rollingfile_udata_set_policy(rfup, policyp);
171   log4c_appender_set_udata(file_appender, rfup);
172 
173   /*
174    * Open the rollingfile appender.  This will also trigger
175    * the initialization of the rollingpolicy.
176    * Log4c is not thread safe with respect to creation/initialization
177    * of categories and appenders, so we must call the open
178    * once, before all the threads kick in logging with this appender.
179    * Calling open as a side effect of the first call to append does
180    * not work in a MT environment.
181    *
182    * For info, could also call init directly on the rollingpolicy here:
183    *   log4c_rollingpolicy_init(policyp, rfup);
184    *
185    *
186   */
187   log4c_appender_open(file_appender);
188 
189   /*
190    * Configure a layout for the rolling file appender
191    * (could also have chosen "basic" here, for example)
192   */
193   log4c_appender_set_layout(file_appender,
194                             log4c_layout_get(param_layout_to_use) );
195 
196   /*
197    * Configure the root category with our rolling file appender...
198    * and we can then start logging to it.
199    *
200   */
201   log4c_category_set_appender(root,file_appender );
202 
203   log4c_dump_all_instances(stderr);
204 
205 
206 }
207 
208 /*
209  * thread function to log messages
210  *
211 */
212 #ifdef _WIN32
thread_log_messages(void * arg)213 unsigned int thread_log_messages(void *arg)
214 #else
215 void * thread_log_messages(void *arg)
216 #endif
217 {
218 
219   int loop;
220   usec_t stop_time;
221   usec_t start_time;
222   unsigned long elapsed;
223   int tid,j;
224   char buf[1024];
225 
226   tid= *((int *)arg);
227 
228   loop = 0 ;
229   while (loop < param_loops_per_thread) {
230 
231     /* Now start the transaction measurement. */
232 	 start_time = now();
233 
234     /* Do a bit of work, fabricate a string containing the thread id */
235     buf[0] = '\0';
236     j = 0;
237     while( j < 128) {
238       snprintf(&buf[strlen(buf)], 1024-strlen(buf), "%d", tid);
239       j++;
240     }
241     sleep(1);
242 
243     stop_time = now();
244     elapsed = (unsigned long)(((usec_t)stop_time - (usec_t)start_time)/1000);
245     /*printf("Hello world--thread(%d)! (loop %d of %d) sleeping for 1 second"
246       "--measured time %lld--%s\n", tid, loop, param_loops_per_thread,
247         stop_time-start_time,buf);*/
248     log4c_category_fatal(root,
249       "Hello world--thread(%d)! (loop %d of %d) sleeping for 1 second"
250       "--measured tme %ld ms--%s\n", tid, loop, param_loops_per_thread,
251         elapsed,buf);
252 
253     loop++;
254   }
255 #ifndef _WIN32
256   return(NULL);
257 #else
258 	return(0);
259 #endif
260 }
261 
262 
main(int argc,char * argv[])263 int main(int argc, char *argv[])
264 {
265 
266   int rc = 0;
267   pthread_t tid[PARAM_NUM_THREADS];
268   int i;
269 
270   init_log4c_with_rollingfile_appender();
271 
272 
273   /* Simple start/stop example. */
274   printf("Launching %d threads to log messages\n", PARAM_NUM_THREADS);
275   for ( i = 0; i < PARAM_NUM_THREADS; i++){
276 	  int * this_thread_arg =
277     NULL;
278 
279 		  if ((this_thread_arg = (int *)malloc(sizeof(int))) == NULL){
280 			  exit(1);
281 		  }
282 		*this_thread_arg = i;
283 		rc = pthread_create(&tid[i], NULL, thread_log_messages,
284 								 (void *)this_thread_arg);
285 		if ( tid[i] == 0 ) {
286 								printf("Error creating thead %d...exiting\n", i);
287 								exit(1);
288 		}
289   }
290 
291   for ( i = 0; i < PARAM_NUM_THREADS; i++){
292     pthread_join(tid[i], NULL);
293   }
294 
295   /* Explicitly call the log4c cleanup routine */
296   if ( log4c_fini()){
297     printf("log4c_fini() failed");
298   }
299 
300   return rc;
301 }
302 
303