libsim Versione 8.0.0
log4fortran.F90
1! Copyright (C) 2010 ARPA-SIM <urpsim@smr.arpa.emr.it>
2! authors:
3! Davide Cesari <dcesari@arpa.emr.it>
4! Paolo Patruno <ppatruno@arpa.emr.it>
5
6! This program is free software; you can redistribute it and/or
7! modify it under the terms of the GNU General Public License as
8! published by the Free Software Foundation; either version 2 of
9! the License, or (at your option) any later version.
10
11! This program is distributed in the hope that it will be useful,
12! but WITHOUT ANY WARRANTY; without even the implied warranty of
13! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14! GNU General Public License for more details.
15
16! You should have received a copy of the GNU General Public License
17! along with this program. If not, see <http://www.gnu.org/licenses/>.
18#include "config.h"
19
20!> \defgroup log4fortran Libsim package, log4fortran library.
21!! Fortran interface to a basic set of log4c library for performing
22!! logging within a program.
23
24!>\brief classe per la gestione del logging
25!!
26!!Questo modulo permette una semplice, ma potente gestione della messagistica.
27!!E' utile sia in fase di debug che di monitoraggio utente.
28!!
29!!Questo modulo fornisce funzionalità simili, ma non identiche a
30!!seconda che siano disponibili in fase di compilazione le librerie
31!!log4c e cnf.
32!!
33!!There are three fundamental types of object in Log4C: categories,
34!!appenders and layouts. You can think of these objects as
35!!corresponding to the what, where and how of the logging system:
36!!categories describe what sub-system the message relates to,
37!!appenders determine where the message goes and layouts determine how
38!!the message is formatted.
39!!
40!!First, you have to figure out what kind of categories you
41!!want. Maybe you want one logger for GUI code and another one for
42!!memory management and a third one for user access
43!!logging. Okay. That's fine. Me, I like to have a separate logger for
44!!each class or data structure. I've already gone to the trouble of
45!!breaking my code down into such categories. Why not just use those?
46!!Feel free to set it up any way you like. Just don't make the mistake
47!!of using message severity as your categories. That's what the
48!!priority is all about.
49!!
50!! La gestione di appenders e layouts viene demandata in toto al file
51!! di configurazione di log4c (vedere apposita documentazione
52!! http://log4c.cvs.sourceforge.net/\*checkout\*/log4c/log4c/doc/Log4C-DevelopersGuide.odt )
53!!
54!!log4fortran by default can log messages with some standard priority levels:
55!!
56!!Use debug to write debugging messages which should not be printed
57!!when the application is in production.
58!!
59!!Use info for messages similar to the "verbose" mode of many
60!!applications.
61!!
62!!Use warn for warning messages which are logged to some log but the
63!!application is able to carry on without a problem.
64!!
65!!Use error for application error messages which are also logged to
66!!some log but, still, the application can hobble along. Such as when
67!!some administrator-supplied configuration parameter is incorrect and
68!!you fall back to using some hard-coded default value.
69!!
70!!Use fatal for critical messages, after logging of which the
71!!application quits abnormally.
72!!
73!!Configuration syntax:
74!!
75!!The log4crc configuration file uses an XML syntax. The root element
76!!is &lt;log4c&gt; and it can be used to control the configuration file
77!!version interface with the attribute "version". The following 4
78!!elements are supported: &lt;config&gt;, &lt;category&gt;, &lt;appender&gt; and
79!!&lt;layout&gt;.
80!!
81!! The &lt;config&gt; element controls the global log4c
82!! configuration. It has 3 sub elements. The &lt;nocleanup&gt; flag
83!! inhibits the log4c destructors routines. The &lt;bufsize&gt; element
84!! sets the buffer size used to format log4c_logging_event_t
85!! objects. If is set to 0, the allocation is dynamic (the &lt;debug&gt;
86!! element is currently unused).
87!!
88!! The &lt;category&gt; element has 3 possible attributes: the category
89!! "name", the category "priority" and the category
90!! "appender". Future versions will handle multple appenders per
91!! category.
92!!
93!! The &lt;appender&gt; element has 3 possible attributes: the appender
94!! "name", the appender "type", and the appender "layout".
95!!
96!! The &lt;layout&gt; element has 2 possible attributes: the layout
97!! "name" and the layout "type".
98!!
99!!
100!!This initial version of the log4c configuration file syntax is quite
101!!different from log4j. XML seemed the best choice to keep the log4j
102!!configuration power in a C API. Environment variables
103!!
104!! LOG4C_RCPATH holds the path to the main log4crc configuration file
105!! LOG4C_PRIORITY holds the "root" category priority
106!! LOG4C_APPENDER holds the "root" category appender
107!!
108!!
109!!Programma esempio \include log4fortran.f90
110!!Here's one sample log4crc configuration file \include log4crc
111!!
112!!\ingroup log4fortran
113MODULE log4fortran
114USE iso_c_binding
115IMPLICIT NONE
116
117INTEGER(kind=c_int),PARAMETER :: L4F_FATAL = 000 !< standard priority
118INTEGER(kind=c_int),PARAMETER :: L4F_ALERT = 100 !< standard priority
119INTEGER(kind=c_int),PARAMETER :: L4F_CRIT = 200 !< standard priority
120INTEGER(kind=c_int),PARAMETER :: L4F_ERROR = 300 !< standard priority
121INTEGER(kind=c_int),PARAMETER :: L4F_WARN = 400 !< standard priority
122INTEGER(kind=c_int),PARAMETER :: L4F_NOTICE = 500 !< standard priority
123INTEGER(kind=c_int),PARAMETER :: L4F_INFO = 600 !< standard priority
124INTEGER(kind=c_int),PARAMETER :: L4F_DEBUG = 700 !< standard priority
125INTEGER(kind=c_int),PARAMETER :: L4F_TRACE = 800 !< standard priority
126INTEGER(kind=c_int),PARAMETER :: L4F_NOTSET = 900 !< standard priority
127INTEGER(kind=c_int),PARAMETER :: L4F_UNKNOWN = 1000 !< standard priority
128
129!> Default priority value. It is used only when compiled without log4c
130!! since the configuration file is ignored, but it is better to define
131!! it all the time.
132INTEGER(kind=c_int),PUBLIC :: l4f_priority=l4f_notice
133
134#ifdef HAVE_LIBLOG4C
135
136!> l4f handle. This type defines an opaque handle
137!! to a l4f category (mapped to a log4c category),
138!! it has to be initialised with the l4f_category_get_handle method.
139TYPE,BIND(C) :: l4f_handle
140 PRIVATE
141 TYPE(c_ptr) :: ptr = c_null_ptr
142END TYPE l4f_handle
143
144
145TYPE(l4f_handle),SAVE :: l4f_global_default
146
147#undef ARRAYOF_ORIGEQ
148#undef ARRAYOF_ORIGTYPE
149#undef ARRAYOF_TYPE
150#define ARRAYOF_ORIGTYPE TYPE(l4f_handle)
151#define ARRAYOF_TYPE arrayof_l4f_handle
152#include "arrayof_pre_nodoc.F90"
153
154TYPE(arrayof_l4f_handle) :: l4f_global_ptr
155
156!> Global log4fortran constructor. It can be called by Fortran.
157INTERFACE
158 FUNCTION l4f_init() bind(C,name='log4c_init')
159 IMPORT
160 INTEGER(kind=c_int) :: l4f_init
161 END FUNCTION l4f_init
162END INTERFACE
163
164! Internal C interface not to be used by user Fortran code
165INTERFACE
166 FUNCTION l4f_category_get_c(a_name) bind(C,name='log4c_category_get')
167 IMPORT
168 CHARACTER(kind=c_char),INTENT(in) :: a_name(*) !< category name
169 TYPE(l4f_handle) :: l4f_category_get_c
170 END FUNCTION l4f_category_get_c
171END INTERFACE
172
173! Internal C interface not to be used by user Fortran code
174! this function has been disabled because after deleting a category
175! the following log4c_fini fails with a double free, we must
176! understand the log4c docs
177INTERFACE
178 SUBROUTINE l4f_category_delete_c(a_category) bind(C,name='log4c_category_delete')
179 IMPORT
180 TYPE(l4f_handle),VALUE :: a_category !< category as C native pointer
181 END SUBROUTINE l4f_category_delete_c
182END INTERFACE
183
184!! Delete a logging category. It can receive a l4f_handle pointer or a
185!! legacy integer value.
186INTERFACE l4f_category_delete
187 MODULE PROCEDURE l4f_category_delete_legacy, l4f_category_delete_f
188END INTERFACE
189
190! Internal C interface not to be used by user Fortran code
191INTERFACE
192 SUBROUTINE l4f_category_log_c(a_category, a_priority, a_format) bind(C,name='log4c_category_log_c')
193 IMPORT
194 TYPE(l4f_handle),VALUE :: a_category !< category
195 INTEGER(kind=c_int),VALUE :: a_priority !< priority level
196! TYPE(c_ptr),VALUE :: locinfo !< not used
197 CHARACTER(kind=c_char),INTENT(in) :: a_format(*) !< message to emit
198 ! TYPE(c_ptr),VALUE :: a_args
199 END SUBROUTINE l4f_category_log_c
200END INTERFACE
201
202!> Emit log message for a category with specific priority.
203!! It can receive a l4f_handle or a legacy integer value.
204INTERFACE l4f_category_log
205 MODULE PROCEDURE l4f_category_log_f, l4f_category_log_legacy
206END INTERFACE l4f_category_log
207
208!> Return true if the corresponding category handle exists.
209INTERFACE l4f_category_exist
210 MODULE PROCEDURE l4f_category_exist_f, l4f_category_exist_legacy
211END INTERFACE l4f_category_exist
212
213!> Global log4fortran destructor. It can be called by Fortran.
214INTERFACE
215 FUNCTION l4f_fini() bind(C,name='log4c_fini')
216 IMPORT
217 INTEGER(kind=c_int) :: l4f_fini
218 END FUNCTION l4f_fini
219END INTERFACE
220
221!>Ritorna un messaggio caratteristico delle priorità standard
222!interface
223!CHARACTER(len=12) FUNCTION l4f_msg(a_priority)
224!integer,intent(in):: a_priority !< category name
225!end function l4f_msg
226!end interface
227
228#else
229
230CHARACTER(len=510),PRIVATE:: dummy_a_name
231
232!> l4f handle. Dummy handle.
233TYPE :: l4f_handle
234 PRIVATE
235 INTEGER :: ptr = 0
236END TYPE l4f_handle
237
238#endif
239
240PRIVATE
241PUBLIC l4f_fatal, l4f_alert, l4f_crit, l4f_error, l4f_warn, l4f_notice, &
242 l4f_info, l4f_debug, l4f_trace, l4f_notset, l4f_unknown
243PUBLIC l4f_handle, l4f_init, l4f_category_get_handle, l4f_category_get, l4f_category_delete, l4f_category_log, &
245PUBLIC l4f_launcher
246
247CONTAINS
248
249!> Routine specifica per il SIM. Cattura le variabili di ambiente
250!! LOG4_APPLICATION_NAME,LOG4_APPLICATION_ID e compone il nome univoco
251!! per il logging. Se le variabili di ambiente non sono impostate
252!! ritorna un nome definito dal nome del processo e da un timestamp.
253SUBROUTINE l4f_launcher(a_name, a_name_force, a_name_append)
254CHARACTER(len=*),INTENT(out) :: a_name !< nome univoco per logging
255CHARACTER(len=*),INTENT(in),OPTIONAL :: a_name_force !< forza il valore di a_name
256CHARACTER(len=*),INTENT(in),OPTIONAL :: a_name_append !< valore da appendere a a_name
257
258INTEGER :: tarray(8)
259CHARACTER(len=255) :: LOG4_APPLICATION_NAME,LOG4_APPLICATION_ID,arg
260CHARACTER(len=255),SAVE :: a_name_save=""
261
262IF (PRESENT(a_name_force))THEN
263 a_name=a_name_force
264ELSE IF (a_name_save /= "")THEN
265 a_name=a_name_save
266ELSE
267
268 CALL date_and_time(values=tarray)
269 CALL getarg(0, arg)
270 CALL getenv("LOG4_APPLICATION_NAME", log4_application_name)
271 CALL getenv("LOG4_APPLICATION_ID", log4_application_id)
272
273 IF (log4_application_name == "" .AND. log4_application_id == "") THEN
274 WRITE(a_name,"(a,a,8i5,a)")trim(arg),"[",tarray,"]"
275 ELSE
276 a_name = trim(log4_application_name)//"["//trim(log4_application_id)//"]"
277 END IF
278
279END IF
280
281a_name_save=a_name
282
283IF (PRESENT(a_name_append)) THEN
284 a_name=trim(a_name)//"."//trim(a_name_append)
285END IF
286
287END SUBROUTINE l4f_launcher
288
289#ifndef HAVE_LIBLOG4C
290! define dummy function to replace log4c interface
291
292!> log4fortran global constructor
293INTEGER FUNCTION l4f_init()
294CHARACTER(len=10) :: priority
295INTEGER :: iostat
296
297CALL getenv("LOG4C_PRIORITY",priority)
298IF (priority=="") THEN
299 l4f_priority = l4f_notice
300ELSE
301 READ(priority,*,iostat=iostat)l4f_priority
302END IF
303
304IF (iostat /= 0) THEN
305 l4f_priority = l4f_notice
306END IF
310END FUNCTION l4f_init
313!>Initialize a logging category.
314FUNCTION l4f_category_get(a_name) RESULT(handle)
315CHARACTER(len=*),INTENT(in) :: a_name !< category name
316
317TYPE(l4f_handle) :: handle
318
319handle%ptr = 1
320dummy_a_name = a_name
321
322END FUNCTION l4f_category_get
323
324
325!>Delete a logging category.
326SUBROUTINE l4f_category_delete(a_category)
327TYPE(l4f_handle),INTENT(in) :: a_category !< category
328
329a_category%ptr = 0
330dummy_a_name = ""
331
332END SUBROUTINE l4f_category_delete
333
334
335!> Emit log message for a category with specific priority
336SUBROUTINE l4f_category_log(a_category,a_priority,a_format)
337TYPE(l4f_handle),INTENT(in) :: a_category !< category
338INTEGER,INTENT(in):: a_priority !< priority level
339CHARACTER(len=*),INTENT(in):: a_format !< message to emit
340
341IF (a_category%ptr == 1 .AND. a_priority <= l4f_priority) THEN
342 WRITE(*,*)"[dummy] ",l4f_msg(a_priority),trim(dummy_a_name)," - ",trim(a_format)
343ENDIF
344
345END SUBROUTINE l4f_category_log
346
347
348!> Emit log message without category with specific priority
349SUBROUTINE l4f_log(a_priority,a_format)
350INTEGER,INTENT(in):: a_priority !< priority level
351CHARACTER(len=*),INTENT(in):: a_format !< message to emit
352
353IF (a_priority <= l4f_priority) THEN
354 WRITE(*,*)"[_default] ",l4f_msg(a_priority),trim(dummy_a_name)," - ",trim(a_format)
355ENDIF
356
357END SUBROUTINE l4f_log
358
359
360!> Return True if category exist
361LOGICAL FUNCTION l4f_category_exist(a_category)
362TYPE(l4f_handle),INTENT(in) :: a_category !< category
363
364l4f_category_exist = a_category%ptr == 1
365
366END FUNCTION l4f_category_exist
367
368
369!>log4fortran destructors
370INTEGER FUNCTION l4f_fini()
371
372l4f_fini= 0
373
374END FUNCTION l4f_fini
375
376!>Ritorna un messaggio caratteristico delle priorità standard
377CHARACTER(len=12) FUNCTION l4f_msg(a_priority)
378INTEGER,INTENT(in):: a_priority !< priority level
379
380write(l4f_msg,*)a_priority
381
382if (a_priority == l4f_fatal) l4f_msg="FATAL"
383if (a_priority == l4f_alert) l4f_msg="ALERT"
384if (a_priority == l4f_crit) l4f_msg="CRIT"
385if (a_priority == l4f_error) l4f_msg="ERROR"
386if (a_priority == l4f_warn) l4f_msg="WARN"
387if (a_priority == l4f_notice) l4f_msg="NOTICE"
388if (a_priority == l4f_info) l4f_msg="INFO"
389if (a_priority == l4f_debug) l4f_msg="DEBUG"
390if (a_priority == l4f_trace) l4f_msg="TRACE"
391if (a_priority == l4f_notset) l4f_msg="NOTSET"
392if (a_priority == l4f_unknown) l4f_msg="UNKNOWN"
393
394END FUNCTION l4f_msg
395
396#else
397
398#include "arrayof_post_nodoc.F90"
399
400!> Initialize a logging category. This is the
401!! Fortran legacy version that receives a Fortran character argument
402!! and returns an integer.
403FUNCTION l4f_category_get(a_name) RESULT(handle)
404CHARACTER(kind=c_char,len=*),INTENT(in) :: a_name !< category name
405INTEGER :: handle
406
407handle = append(l4f_global_ptr, l4f_category_get_c(trim(a_name)//char(0)))
408
409END FUNCTION l4f_category_get
410
411
412!> Initialize a logging category. This is the
413!! Fortran version that receives a Fortran character argument
414!! and returns a typed handle.
415FUNCTION l4f_category_get_handle(a_name) RESULT(handle)
416CHARACTER(kind=c_char,len=*),INTENT(in) :: a_name !< category name
417TYPE(l4f_handle) :: handle
418
419handle = l4f_category_get_c(trim(a_name)//char(0))
420
421END FUNCTION l4f_category_get_handle
422
423
424!> Delete a logging category. Legacy version with an integer argument.
425SUBROUTINE l4f_category_delete_legacy(a_category)
426INTEGER,INTENT(in) :: a_category !< category as an integer
427
428IF (a_category <= 0 .OR. a_category > l4f_global_ptr%arraysize) RETURN
429CALL remove(l4f_global_ptr, pos=a_category)
430
431END SUBROUTINE l4f_category_delete_legacy
432
433
434!> Delete a logging category. No-op version with a typed handle.
435SUBROUTINE l4f_category_delete_f(a_category)
436TYPE(l4f_handle),INTENT(inout) :: a_category !< category as C native pointer
437
438! hee the C function should be called, see comment above
439! CALL l4f_category_delete_c(a_category)
440a_category%ptr = c_null_ptr
441
442END SUBROUTINE l4f_category_delete_f
443
444
445!> Emit log message for a category with specific priority.
446!! Fortran version that receives a Fortran character argument.
447SUBROUTINE l4f_category_log_f(a_category, a_priority, a_format)
448TYPE(l4f_handle),INTENT(in) :: a_category !< category
449INTEGER(kind=c_int),INTENT(in) :: a_priority !< priority level
450CHARACTER(len=*),INTENT(in) :: a_format !< message to emit
451
452CALL l4f_category_log_c(a_category, a_priority, trim(a_format)//char(0))
453
454END SUBROUTINE l4f_category_log_f
455
456
457!> Emit log message for a category with specific priority.
458!! Legacy Fortran version that receives an integer instead of a C
459!! pointer and a Fortran character argument.
460SUBROUTINE l4f_category_log_legacy(a_category, a_priority, a_format)
461INTEGER(kind=c_int),INTENT(in) :: a_category !< category
462INTEGER(kind=c_int),INTENT(in) :: a_priority !< priority level
463CHARACTER(len=*),INTENT(in) :: a_format !< message to emit
464
465CALL l4f_category_log_c(l4f_global_ptr%array(a_category), l4f_warn, &
466 'You are using the legacy log4fortran interface!'//char(0))
467CALL l4f_category_log_c(l4f_global_ptr%array(a_category), l4f_warn, &
468 'Please, upgrade your code by defining category as `TYPE(l4f_handle)`'//char(0))
469CALL l4f_category_log_c(l4f_global_ptr%array(a_category), l4f_warn, &
470 'and replacing `l4f_category_get` with `l4f_category_get_handle`'//char(0))
471CALL l4f_category_log_c(l4f_global_ptr%array(a_category), a_priority, trim(a_format)//char(0))
473END SUBROUTINE l4f_category_log_legacy
474
475
476!> Emit log message without category with specific priority.
477!! Fortran version that receives a Fortran character argument.
478SUBROUTINE l4f_log(a_priority, a_format)
479INTEGER(kind=c_int),INTENT(in) :: a_priority !< priority level
480CHARACTER(len=*),INTENT(in) :: a_format !< message to emit
481
482INTEGER :: i
483
484IF (.NOT.l4f_category_exist(l4f_global_default)) THEN
485 i = l4f_init()
486 l4f_global_default = l4f_category_get_handle('_default')
487ENDIF
488CALL l4f_category_log(l4f_global_default, a_priority, a_format)
489
490END SUBROUTINE l4f_log
491
492
493!> Return true if the corresponding category handle exists
494!! (is associated with a category).
495FUNCTION l4f_category_exist_f(a_category) RESULT(exist)
496TYPE(l4f_handle),INTENT(in) :: a_category !< category
497LOGICAL :: exist
498
499exist = c_associated(a_category%ptr)
501END FUNCTION l4f_category_exist_f
502
503!> Return true if the corresponding category handle exists
504!! (is associated with a category).
505!! Legacy Fortran version that receives an integer instead of a C
506!! pointer.
507FUNCTION l4f_category_exist_legacy(a_category) RESULT(exist)
508INTEGER,INTENT(in):: a_category !< category
509LOGICAL :: exist
510
511IF (a_category <= 0 .OR. a_category > l4f_global_ptr%arraysize) THEN
512 exist = .false.
513ELSE
514 exist = l4f_category_exist(l4f_global_ptr%array(a_category))
515ENDIF
516
517END FUNCTION l4f_category_exist_legacy
518
519#endif
520
521END MODULE log4fortran
Return true if the corresponding category handle exists.
Emit log message for a category with specific priority.
Global log4fortran destructor.
Global log4fortran constructor.
classe per la gestione del logging

Generated with Doxygen.