Neko 1.99.2
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
log.f90
Go to the documentation of this file.
1! Copyright (c) 2021-2024, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32!
34module logger
35 use comm, only : pe_rank
36 use num_types, only : rp
37 use utils, only : neko_error
38 use, intrinsic :: iso_fortran_env, only : stdout => output_unit, &
39 stderr => error_unit
40 implicit none
41 private
42
43 ! > Size of the log message buffer
44 !! @note This adjust for the leading space applied by `write`. 80 character
45 !! output log leaves 79 characters for the message.
46 integer, public, parameter :: log_size = 79
47
48 type, public :: log_t
49 integer, private :: indent_
50 integer, private :: section_id_
51 integer, private :: tab_size_
52 integer, private :: level_
53 integer, private :: unit_
54
55 character(len=LOG_SIZE), private :: section_header = ""
56
57 contains
58 procedure, pass(this) :: init => log_init
59 procedure, pass(this) :: free => log_free
60 procedure, pass(this) :: begin => log_begin
61 procedure, pass(this) :: end => log_end
62 procedure, pass(this) :: indent => log_indent
63 procedure, pass(this) :: newline => log_newline
64 procedure, pass(this) :: message => log_message
65 procedure, pass(this) :: section => log_section
66 procedure, pass(this) :: header => log_header
67 procedure, pass(this) :: error => log_error
68 procedure, pass(this) :: warning => log_warning
69 procedure, pass(this) :: deprecated => log_deprecated
70 procedure, pass(this) :: end_section => log_end_section
71
72 procedure, private, pass(this) :: print_section_header => &
74 end type log_t
75
77 type(log_t), public :: neko_log
79 integer, public, parameter :: neko_log_quiet = 0
81 integer, public, parameter :: neko_log_info = 1
83 integer, public, parameter :: neko_log_verbose = 2
85 integer, public, parameter :: neko_log_deprecation_error = 5
87 integer, public, parameter :: neko_log_debug = 10
88
90 character(len=50), dimension(:), allocatable :: deprecated_list
91
92contains
93
95 subroutine log_init(this)
96 class(log_t), intent(inout) :: this
97 character(len=255) :: log_level
98 character(len=255) :: log_tab_size
99 character(len=255) :: log_file
100 integer :: envvar_len
101
102 this%indent_ = 0
103 this%section_id_ = 0
104
105 call get_environment_variable("NEKO_LOG_TAB_SIZE", log_tab_size, envvar_len)
106 if (envvar_len .gt. 0) then
107 read(log_tab_size(1:envvar_len), *) this%tab_size_
108 else
109 this%tab_size_ = 1
110 end if
111
112 call get_environment_variable("NEKO_LOG_LEVEL", log_level, envvar_len)
113 if (envvar_len .gt. 0) then
114 read(log_level(1:envvar_len), *) this%level_
115 else
116 this%level_ = neko_log_info
117 end if
118
119 call get_environment_variable("NEKO_LOG_FILE", log_file, envvar_len)
120 if (envvar_len .gt. 0) then
121 open(newunit = this%unit_, file = trim(log_file), status = 'replace', &
122 action = 'write')
123 else
124 this%unit_ = stdout
125 end if
126
127 end subroutine log_init
128
130 subroutine log_free(this)
131 class(log_t), intent(inout) :: this
132
133 if (this%section_id_ .ne. 0) then
134 call neko_error("Log is unbalanced")
135 end if
136
137 if (this%unit_ .ne. stdout) then
138 close(this%unit_)
139 end if
140
141 this%indent_ = 0
142 this%level_ = neko_log_info
143 this%unit_ = -1
144
145 if (allocated(deprecated_list)) then
146 deallocate(deprecated_list)
147 end if
148
149 end subroutine log_free
150
152 subroutine log_begin(this)
153 class(log_t), intent(inout) :: this
154
155 if (pe_rank .eq. 0) then
156 this%section_id_ = this%section_id_ + 1
157 this%indent_ = this%indent_ + this%tab_size_
158 end if
159
160 end subroutine log_begin
161
163 subroutine log_end(this)
164 class(log_t), intent(inout) :: this
165
166 if (pe_rank .eq. 0) then
167 if (this%section_id_ .eq. 0) then
168 call neko_error("Log is unbalanced")
169 end if
170 this%section_id_ = this%section_id_ - 1
171 this%indent_ = this%indent_ - this%tab_size_
172 end if
173
174 this%section_header = ""
175
176 end subroutine log_end
177
179 subroutine log_indent(this)
180 class(log_t), intent(in) :: this
181
182 if (pe_rank .eq. 0) then
183 write(this%unit_, '(A)', advance = 'no') repeat(' ', this%indent_)
184 end if
185
186 end subroutine log_indent
187
189 subroutine log_newline(this, lvl)
190 class(log_t), intent(in) :: this
191 integer, optional :: lvl
192
193 integer :: lvl_
194
195 if (present(lvl)) then
196 lvl_ = lvl
197 else
198 lvl_ = neko_log_info
199 end if
200
201 if (lvl_ .gt. this%level_) then
202 return
203 end if
204
205 if (pe_rank .eq. 0) then
206 write(this%unit_, '(A)') ''
207 end if
208
209 end subroutine log_newline
210
212 subroutine log_message(this, msg, lvl)
213 class(log_t), intent(inout) :: this
214 character(len=*), intent(in) :: msg
215 integer, optional :: lvl
216 integer :: lvl_
217
218 if (present(lvl)) then
219 lvl_ = lvl
220 else
221 lvl_ = neko_log_info
222 end if
223
224 if (lvl_ .gt. this%level_) then
225 return
226 end if
227
228 if (len_trim(this%section_header) .gt. 0) then
229 call this%print_section_header(lvl)
230 end if
231
232 if (pe_rank .eq. 0) then
233 call this%indent()
234 write(this%unit_, '(A)') trim(msg)
235 end if
236
237 end subroutine log_message
238
240 subroutine log_header(this, version, build_info)
241 class(log_t), intent(in) :: this
242 character(len=*), intent(in) :: version
243 character(len=*), intent(in) :: build_info
244
245 if (pe_rank .eq. 0) then
246 write(this%unit_, '(A)') ''
247 write(this%unit_, '(1X,A)') ' _ __ ____ __ __ ____ '
248 write(this%unit_, '(1X,A)') ' / |/ / / __/ / //_/ / __ \ '
249 write(this%unit_, '(1X,A)') ' / / / _/ / ,< / /_/ / '
250 write(this%unit_, '(1X,A)') '/_/|_/ /___/ /_/|_| \____/ '
251 write(this%unit_, '(A)') ''
252 write(this%unit_, '(1X,A,A,A)') '(version: ', trim(version), ')'
253 write(this%unit_, '(1X,A)') trim(build_info)
254 write(this%unit_, '(A)') ''
255 end if
256
257 end subroutine log_header
258
260 subroutine log_error(this, msg)
261 class(log_t), intent(in) :: this
262 character(len=*), intent(in) :: msg
263
264 if (pe_rank .eq. 0) then
265 call this%indent()
266 write(stderr, '(A,A,A)') '*** ERROR: ', trim(msg), ' ***'
267 end if
268
269 end subroutine log_error
270
272 subroutine log_warning(this, msg)
273 class(log_t), intent(in) :: this
274 character(len=*), intent(in) :: msg
275
276 if (pe_rank .eq. 0) then
277 call this%indent()
278 write(this%unit_, '(A,A,A)') '*** WARNING: ', trim(msg), ' ***'
279 end if
280
281 end subroutine log_warning
282
287 subroutine log_deprecated(this, feature, removal_version, extra_info)
288 class(log_t), intent(inout) :: this
289 character(len=*), intent(in) :: feature
290 character(len=*), intent(in), optional :: removal_version
291 character(len=*), intent(in), optional :: extra_info
292 character(len=LOG_SIZE) :: msg
293 character(len=50), dimension(:), allocatable :: deprecated_list_local
294 integer :: i
295
296 if (this%level_ .lt. neko_log_quiet) return
297
298 if (.not. allocated(deprecated_list)) then
299 allocate(character(len=50) :: deprecated_list(1))
300 deprecated_list = trim(feature)
301 else
302 ! Check that the feature have not already been logged
303 do i = 1, size(deprecated_list)
304 if (trim(deprecated_list(i)) .eq. trim(feature)) return
305 end do
306
307 ! Save the feature to the list of deprecated features
308 call move_alloc(deprecated_list, deprecated_list_local)
309 allocate(character(len=50)::deprecated_list(size(deprecated_list_local)+1))
310 deprecated_list(1:size(deprecated_list_local)) = deprecated_list_local
311 deprecated_list(size(deprecated_list_local) + 1) = trim(feature)
312 deallocate(deprecated_list_local)
313 end if
314
315 ! Construct deprecation message
316 write(msg, '(A,A)') '*** DEPRECATION: ', trim(feature)
317 call this%message(msg)
318 write(msg, '(A,A,A)') 'The feature "', trim(feature), &
319 '" is deprecated.'
320 call this%message(msg)
321
322 if (present(removal_version)) then
323 write(msg, '(A,A,A)') 'It will be removed in version ', &
324 trim(removal_version), '.'
325 call this%message(msg)
326 end if
327
328 if (present(extra_info)) then
329 call this%message(extra_info)
330 end if
331
332 call this%message('***')
333
334 if (this%level_ .ge. neko_log_deprecation_error) then
335 call neko_error('Deprecated feature used: ' // trim(feature))
336 end if
337
338 end subroutine log_deprecated
339
341 subroutine log_section(this, msg, lvl)
342 class(log_t), intent(inout) :: this
343 character(len=*), intent(in) :: msg
344 integer, optional :: lvl
345
346 integer :: pre, pos
347
348 if (len_trim(this%section_header) .gt. 0) then
349 call this%print_section_header(lvl)
350 end if
351
352 call this%begin()
353
354 if (pe_rank .eq. 0) then
355 pre = (30 - len_trim(msg)) / 2
356 pos = 30 - (len_trim(msg) + pre)
357
358 write(this%section_header, '(A,A,A)') &
359 repeat('-', pre), trim(msg), repeat('-', pos)
360 end if
361
362 end subroutine log_section
363
365 subroutine log_print_section_header(this, lvl)
366 class(log_t), intent(inout) :: this
367 integer, optional :: lvl
368 integer :: lvl_
369
370 if (present(lvl)) then
371 lvl_ = lvl
372 else
373 lvl_ = neko_log_info
374 end if
375
376 if (lvl_ .gt. this%level_) then
377 return
378 end if
379
380 if (pe_rank .eq. 0) then
381 call this%newline(lvl)
382 call this%indent()
383 write(this%unit_, '(A)') trim(this%section_header)
384 this%section_header = ""
385 end if
386
387 end subroutine log_print_section_header
388
390 subroutine log_end_section(this, msg, lvl)
391 class(log_t), intent(inout) :: this
392 character(len=*), intent(in), optional :: msg
393 integer, optional :: lvl
394 integer :: lvl_
395
396 if (present(msg)) then
397 call this%message(msg, lvl)
398 end if
399
400 call this%end()
401
402 end subroutine log_end_section
403
404 !
405 ! Rudimentary C interface
406 !
407
410 subroutine log_message_c(c_msg) bind(c, name = 'log_message')
411 use, intrinsic :: iso_c_binding
412 character(kind=c_char), dimension(*), intent(in) :: c_msg
413 character(len=LOG_SIZE) :: msg
414 integer :: len
415
416 if (pe_rank .eq. 0) then
417 len = 0
418 do
419 if (c_msg(len+1) .eq. c_null_char) exit
420 len = len + 1
421 msg(len:len) = c_msg(len)
422 end do
423
424 call neko_log%message(trim(msg(1:len)))
425 end if
426
427 end subroutine log_message_c
428
431 subroutine log_error_c(c_msg) bind(c, name = "log_error")
432 use, intrinsic :: iso_c_binding
433 character(kind=c_char), dimension(*), intent(in) :: c_msg
434 character(len=LOG_SIZE) :: msg
435 integer :: len
436
437 if (pe_rank .eq. 0) then
438 len = 0
439 do
440 if (c_msg(len+1) .eq. c_null_char) exit
441 len = len + 1
442 msg(len:len) = c_msg(len)
443 end do
444
445 call neko_log%indent()
446 write(stderr, '(A,A,A)') '*** ERROR: ', trim(msg(1:len)), ' ***'
447 end if
448
449 end subroutine log_error_c
450
453 subroutine log_warning_c(c_msg) bind(c, name = "log_warning")
454 use, intrinsic :: iso_c_binding
455 character(kind=c_char), dimension(*), intent(in) :: c_msg
456 character(len=LOG_SIZE) :: msg
457 integer :: len
458
459 if (pe_rank .eq. 0) then
460 len = 0
461 do
462 if (c_msg(len+1) .eq. c_null_char) exit
463 len = len + 1
464 msg(len:len) = c_msg(len)
465 end do
466
467 call neko_log%indent()
468 write(neko_log%unit_, '(A,A,A)') &
469 '*** WARNING: ', trim(msg(1:len)), ' ***'
470 end if
471
472 end subroutine log_warning_c
473
476 subroutine log_section_c(c_msg) bind(c, name = "log_section")
477 use, intrinsic :: iso_c_binding
478 character(kind=c_char), dimension(*), intent(in) :: c_msg
479 character(len=LOG_SIZE) :: msg
480 integer :: len
481
482 if (pe_rank .eq. 0) then
483 len = 0
484 do
485 if (c_msg(len+1) .eq. c_null_char) exit
486 len = len + 1
487 msg(len:len) = c_msg(len)
488 end do
489
490 call neko_log%section(trim(msg(1:len)))
491 end if
492
493 end subroutine log_section_c
494
497 subroutine log_end_section_c() bind(c, name = "log_end_section")
498
499 call neko_log%end_section()
500
501 end subroutine log_end_section_c
502
503end module logger
Definition comm.F90:1
integer, public pe_rank
MPI rank.
Definition comm.F90:56
Module for file I/O operations.
Definition file.f90:34
Logging routines.
Definition log.f90:34
subroutine log_end_section_c()
End a log section (from C)
Definition log.f90:498
subroutine log_end(this)
Decrease indention level.
Definition log.f90:164
subroutine log_print_section_header(this, lvl)
Print a section header.
Definition log.f90:366
subroutine log_deprecated(this, feature, removal_version, extra_info)
Write a deprecation warning to a log.
Definition log.f90:288
subroutine log_header(this, version, build_info)
Write the Neko header to a log.
Definition log.f90:241
integer, parameter, public neko_log_verbose
Verbose log level.
Definition log.f90:83
subroutine log_message(this, msg, lvl)
Write a message to a log.
Definition log.f90:213
integer, parameter, public neko_log_quiet
Always logged.
Definition log.f90:79
subroutine log_begin(this)
Increase indention level.
Definition log.f90:153
subroutine log_message_c(c_msg)
Write a message to a log (from C)
Definition log.f90:411
subroutine log_end_section(this, msg, lvl)
End a log section.
Definition log.f90:391
subroutine log_init(this)
Initialize a log.
Definition log.f90:96
subroutine log_warning(this, msg)
Write a warning message to a log.
Definition log.f90:273
character(len=50), dimension(:), allocatable deprecated_list
List of already logged deprecated features.
Definition log.f90:90
subroutine log_error_c(c_msg)
Write an error message to a log (from C)
Definition log.f90:432
subroutine log_indent(this)
Indent a log.
Definition log.f90:180
subroutine log_warning_c(c_msg)
Write a warning message to a log (from C)
Definition log.f90:454
subroutine log_newline(this, lvl)
Write a new line to a log.
Definition log.f90:190
integer, parameter, public neko_log_deprecation_error
Deprecation error level.
Definition log.f90:85
subroutine log_section_c(c_msg)
Begin a new log section (from C)
Definition log.f90:477
integer, parameter, public neko_log_debug
Debug log level.
Definition log.f90:87
type(log_t), public neko_log
Global log stream.
Definition log.f90:77
integer, parameter, public log_size
Definition log.f90:46
integer, parameter, public neko_log_info
Default log level.
Definition log.f90:81
subroutine log_free(this)
Free a log.
Definition log.f90:131
subroutine log_section(this, msg, lvl)
Begin a new log section.
Definition log.f90:342
subroutine log_error(this, msg)
Write an error message to a log.
Definition log.f90:261
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Utilities.
Definition utils.f90:35