Neko 1.99.3
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 neko_config, only : neko_version
36 use comm, only : pe_rank
37 use utils, only : neko_error, neko_warning
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
49 integer, public, parameter :: sec_head_size = 30
50
51 type, public :: log_t
52 integer, private :: indent_
53 integer, private :: section_id_
54 integer, private :: tab_size_
55 integer, private :: level_
56 integer, private :: unit_
57
58 character(len=LOG_SIZE), private :: section_header = ""
59
60 contains
61 procedure, pass(this) :: init => log_init
62 procedure, pass(this) :: free => log_free
63 procedure, pass(this) :: begin => log_begin
64 procedure, pass(this) :: end => log_end
65 procedure, pass(this) :: indent => log_indent
66 procedure, pass(this) :: newline => log_newline
67 procedure, pass(this) :: message => log_message
68 procedure, pass(this) :: section => log_section
69 procedure, pass(this) :: header => log_header
70 procedure, pass(this) :: error => log_error
71 procedure, pass(this) :: warning => log_warning
72 procedure, pass(this) :: deprecated => log_deprecated
73 procedure, pass(this) :: end_section => log_end_section
74
75 procedure, private, pass(this) :: print_section_header => &
77 end type log_t
78
80 type(log_t), public :: neko_log
82 integer, public, parameter :: neko_log_quiet = 0
84 integer, public, parameter :: neko_log_info = 1
86 integer, public, parameter :: neko_log_verbose = 2
88 integer, public, parameter :: neko_log_deprecation = 5
90 integer, public, parameter :: neko_log_debug = 10
91
93 character(len=50), dimension(:), allocatable :: deprecated_list
94
95contains
96
98 subroutine log_init(this)
99 class(log_t), intent(inout) :: this
100 character(len=255) :: log_level
101 character(len=255) :: log_tab_size
102 character(len=255) :: log_file
103 integer :: envvar_len
104
105 this%indent_ = 0
106 this%section_id_ = 0
107
108 call get_environment_variable("NEKO_LOG_TAB_SIZE", log_tab_size, envvar_len)
109 if (envvar_len .gt. 0) then
110 read(log_tab_size(1:envvar_len), *) this%tab_size_
111 else
112 this%tab_size_ = 1
113 end if
114
115 call get_environment_variable("NEKO_LOG_LEVEL", log_level, envvar_len)
116 if (envvar_len .gt. 0) then
117 read(log_level(1:envvar_len), *) this%level_
118 else
119 this%level_ = neko_log_info
120 end if
121
122 call get_environment_variable("NEKO_LOG_FILE", log_file, envvar_len)
123 if (envvar_len .gt. 0) then
124 open(newunit = this%unit_, file = trim(log_file), status = 'replace', &
125 action = 'write')
126 else
127 this%unit_ = stdout
128 end if
129
130 end subroutine log_init
131
133 subroutine log_free(this)
134 class(log_t), intent(inout) :: this
135 integer :: i
136
137 if (this%section_id_ .ne. 0) then
138 call neko_error("Log is unbalanced")
139 end if
140
141 if (allocated(deprecated_list)) then
142 call this%section("Deprecated features summary", neko_log_deprecation)
143
144 do i = 1, size(deprecated_list)
145 call this%message(trim(deprecated_list(i)), neko_log_deprecation)
146 end do
147 call this%end_section()
148 end if
149
150 if (this%unit_ .ne. stdout) then
151 close(this%unit_)
152 end if
153
154 this%indent_ = 0
155 this%level_ = neko_log_info
156 this%unit_ = -1
157
158 if (allocated(deprecated_list)) then
159 deallocate(deprecated_list)
160 end if
161
162 end subroutine log_free
163
165 subroutine log_begin(this)
166 class(log_t), intent(inout) :: this
167
168 if (pe_rank .eq. 0) then
169 this%section_id_ = this%section_id_ + 1
170 this%indent_ = this%indent_ + this%tab_size_
171 end if
172
173 end subroutine log_begin
174
176 subroutine log_end(this)
177 class(log_t), intent(inout) :: this
178
179 if (pe_rank .eq. 0) then
180 if (this%section_id_ .eq. 0) then
181 call neko_error("Log is unbalanced")
182 end if
183 this%section_id_ = this%section_id_ - 1
184 this%indent_ = this%indent_ - this%tab_size_
185 end if
186
187 this%section_header = ""
188
189 end subroutine log_end
190
192 subroutine log_indent(this)
193 class(log_t), intent(in) :: this
194
195 if (pe_rank .eq. 0) then
196 write(this%unit_, '(A)', advance = 'no') repeat(' ', this%indent_)
197 end if
198
199 end subroutine log_indent
200
202 subroutine log_newline(this, lvl)
203 class(log_t), intent(in) :: this
204 integer, optional :: lvl
205
206 integer :: lvl_
207
208 if (present(lvl)) then
209 lvl_ = lvl
210 else
211 lvl_ = neko_log_info
212 end if
213
214 if (lvl_ .gt. this%level_) then
215 return
216 end if
217
218 if (pe_rank .eq. 0) then
219 write(this%unit_, '(A)') ''
220 end if
221
222 end subroutine log_newline
223
225 subroutine log_message(this, msg, lvl)
226 class(log_t), intent(inout) :: this
227 character(len=*), intent(in) :: msg
228 integer, optional :: lvl
229 integer :: lvl_
230
231 if (present(lvl)) then
232 lvl_ = lvl
233 else
234 lvl_ = neko_log_info
235 end if
236
237 if (lvl_ .gt. this%level_) then
238 return
239 end if
240
241 if (len_trim(this%section_header) .gt. 0) then
242 call this%print_section_header(lvl)
243 end if
244
245 if (pe_rank .eq. 0) then
246 call this%indent()
247 write(this%unit_, '(A)') trim(msg)
248 end if
249
250 end subroutine log_message
251
253 subroutine log_header(this, version, build_info)
254 class(log_t), intent(in) :: this
255 character(len=*), intent(in) :: version
256 character(len=*), intent(in) :: build_info
257
258 if (pe_rank .eq. 0) then
259 write(this%unit_, '(A)') ''
260 write(this%unit_, '(1X,A)') ' _ __ ____ __ __ ____ '
261 write(this%unit_, '(1X,A)') ' / |/ / / __/ / //_/ / __ \ '
262 write(this%unit_, '(1X,A)') ' / / / _/ / ,< / /_/ / '
263 write(this%unit_, '(1X,A)') '/_/|_/ /___/ /_/|_| \____/ '
264 write(this%unit_, '(A)') ''
265 write(this%unit_, '(1X,A,A,A)') '(version: ', trim(version), ')'
266 write(this%unit_, '(1X,A)') trim(build_info)
267 write(this%unit_, '(A)') ''
268 end if
269
270 end subroutine log_header
271
273 subroutine log_error(this, msg)
274 class(log_t), intent(in) :: this
275 character(len=*), intent(in) :: msg
276
277 if (pe_rank .eq. 0) then
278 call this%indent()
279 write(stderr, '(A,A,A)') '*** ERROR: ', trim(msg), ' ***'
280 end if
281
282 end subroutine log_error
283
285 subroutine log_warning(this, msg)
286 class(log_t), intent(in) :: this
287 character(len=*), intent(in) :: msg
288
289 if (pe_rank .eq. 0) then
290 call this%indent()
291 write(this%unit_, '(A,A,A)') '*** WARNING: ', trim(msg), ' ***'
292 end if
293
294 end subroutine log_warning
295
300 subroutine log_deprecated(this, feature, removal_version, extra_info)
301 class(log_t), intent(inout) :: this
302 character(len=*), intent(in) :: feature
303 character(len=*), intent(in) :: removal_version
304 character(len=*), intent(in), optional :: extra_info
305 character(len=50), dimension(:), allocatable :: tmp_list
306 character(len=255) :: deprecation_error
307 character(len=LOG_SIZE) :: msg
308 integer :: i
309
310 if (pe_rank .ne. 0) return
311
312 if (this%level_ .ge. neko_log_deprecation .or. &
313 is_deprecated(removal_version)) then
314
315 ! Check that the feature have not already been logged
316 if (.not. allocated(deprecated_list)) then
317 allocate(character(len=50) :: deprecated_list(1))
318 deprecated_list = trim(feature)
319 else
320 do i = 1, size(deprecated_list)
321 if (trim(deprecated_list(i)) .eq. trim(feature)) return
322 end do
323
324 ! Save the feature to the list of deprecated features
325 call move_alloc(deprecated_list, tmp_list)
326 allocate(character(len=50)::deprecated_list(size(tmp_list)+1))
327 deprecated_list(1:size(tmp_list)) = tmp_list
328 deprecated_list(size(tmp_list) + 1) = trim(feature)
329 deallocate(tmp_list)
330 end if
331
332 ! Construct deprecation message
333 write(msg, '(A,A)') '*** DEPRECATION: ', trim(feature)
334 call this%message(msg, neko_log_deprecation)
335 write(msg, '(A,A,A)') 'The feature "', trim(feature), '" is deprecated.'
336 call this%message(msg, neko_log_deprecation)
337 write(msg, '(A,A,A)') 'It will be removed in version ', &
338 trim(removal_version), '.'
339 call this%message(msg, neko_log_deprecation)
340
341 if (present(extra_info)) then
342 call this%message(extra_info, neko_log_deprecation)
343 end if
344
345 call this%message('***', neko_log_deprecation)
346
347 if (is_deprecated(removal_version)) then
348 deprecation_error = ""
349 call get_environment_variable("NEKO_DEPRECATION_ERROR", &
350 deprecation_error)
351
352 if (trim(deprecation_error) .eq. "1") then
353 call neko_error('Deprecated feature "' // trim(feature) // &
354 '" should have been removed in version ' // &
355 trim(removal_version) // ' (current version: ' // &
356 trim(neko_version) // ').')
357 else
358 call neko_warning('Deprecated feature "' // trim(feature) // &
359 '" should have been removed in version ' // &
360 trim(removal_version) // ' (current version: ' // &
361 trim(neko_version) // ').')
362 end if
363 end if
364 end if
365
366 end subroutine log_deprecated
367
369 subroutine log_section(this, msg, lvl)
370 class(log_t), intent(inout) :: this
371 character(len=*), intent(in) :: msg
372 integer, optional :: lvl
373
374 integer :: pre, pos
375
376 if (len_trim(this%section_header) .gt. 0) then
377 call this%print_section_header(lvl)
378 end if
379
380 call this%begin()
381
382 if (pe_rank .eq. 0) then
383 pre = (30 - len_trim(msg)) / 2
384 pos = 30 - (len_trim(msg) + pre)
385
386 if (pre .lt. 0 .or. pos .lt. 0) then
387 pre = 1
388 pos = 1
389 write(this%section_header, '(A,A,A)') &
390 repeat('-', pre), trim(msg(1: sec_head_size - 2)), &
391 repeat('-', pos)
392 else
393 write(this%section_header, '(A,A,A)') &
394 repeat('-', pre), trim(msg), repeat('-', pos)
395 end if
396 end if
397
398 end subroutine log_section
399
401 subroutine log_print_section_header(this, lvl)
402 class(log_t), intent(inout) :: this
403 integer, optional :: lvl
404 integer :: lvl_
405
406 if (present(lvl)) then
407 lvl_ = lvl
408 else
409 lvl_ = neko_log_info
410 end if
411
412 if (lvl_ .gt. this%level_) then
413 return
414 end if
415
416 if (pe_rank .eq. 0) then
417 call this%newline(lvl)
418 call this%indent()
419 write(this%unit_, '(A)') trim(this%section_header)
420 this%section_header = ""
421 end if
422
423 end subroutine log_print_section_header
424
426 subroutine log_end_section(this, msg, lvl)
427 class(log_t), intent(inout) :: this
428 character(len=*), intent(in), optional :: msg
429 integer, optional :: lvl
430
431 if (present(msg)) then
432 call this%message(msg, lvl)
433 end if
434
435 call this%end()
436
437 end subroutine log_end_section
438
439 !
440 ! Rudimentary C interface
441 !
442
445 subroutine log_message_c(c_msg) bind(c, name = 'log_message')
446 use, intrinsic :: iso_c_binding
447 character(kind=c_char), dimension(*), intent(in) :: c_msg
448 character(len=LOG_SIZE) :: msg
449 integer :: len
450
451 if (pe_rank .eq. 0) then
452 len = 0
453 do
454 if (c_msg(len+1) .eq. c_null_char) exit
455 len = len + 1
456 msg(len:len) = c_msg(len)
457 end do
458
459 call neko_log%message(trim(msg(1:len)))
460 end if
461
462 end subroutine log_message_c
463
466 subroutine log_error_c(c_msg) bind(c, name = "log_error")
467 use, intrinsic :: iso_c_binding
468 character(kind=c_char), dimension(*), intent(in) :: c_msg
469 character(len=LOG_SIZE) :: msg
470 integer :: len
471
472 if (pe_rank .eq. 0) then
473 len = 0
474 do
475 if (c_msg(len+1) .eq. c_null_char) exit
476 len = len + 1
477 msg(len:len) = c_msg(len)
478 end do
479
480 call neko_log%indent()
481 write(stderr, '(A,A,A)') '*** ERROR: ', trim(msg(1:len)), ' ***'
482 end if
483
484 end subroutine log_error_c
485
488 subroutine log_warning_c(c_msg) bind(c, name = "log_warning")
489 use, intrinsic :: iso_c_binding
490 character(kind=c_char), dimension(*), intent(in) :: c_msg
491 character(len=LOG_SIZE) :: msg
492 integer :: len
493
494 if (pe_rank .eq. 0) then
495 len = 0
496 do
497 if (c_msg(len+1) .eq. c_null_char) exit
498 len = len + 1
499 msg(len:len) = c_msg(len)
500 end do
501
502 call neko_log%indent()
503 write(neko_log%unit_, '(A,A,A)') &
504 '*** WARNING: ', trim(msg(1:len)), ' ***'
505 end if
506
507 end subroutine log_warning_c
508
511 subroutine log_section_c(c_msg) bind(c, name = "log_section")
512 use, intrinsic :: iso_c_binding
513 character(kind=c_char), dimension(*), intent(in) :: c_msg
514 character(len=LOG_SIZE) :: msg
515 integer :: len
516
517 if (pe_rank .eq. 0) then
518 len = 0
519 do
520 if (c_msg(len+1) .eq. c_null_char) exit
521 len = len + 1
522 msg(len:len) = c_msg(len)
523 end do
524
525 call neko_log%section(trim(msg(1:len)))
526 end if
527
528 end subroutine log_section_c
529
532 subroutine log_end_section_c() bind(c, name = "log_end_section")
533
534 call neko_log%end_section()
535
536 end subroutine log_end_section_c
537
542 logical function is_deprecated(version_removal)
543 character(len=*), intent(in) :: version_removal
544 character(len=50) :: current_str, removal_str
545 integer :: current_number(3), removal_number(3)
546 integer :: i, current_size, removal_size
547 integer :: iostat_current, iostat_removal
548 logical :: versions_are_valid, is_newer_than_removal
549
550 current_str = trim(neko_version)
551 removal_str = trim(version_removal)
552
553 current_size = 1
554 do i = 1, len_trim(current_str)
555 if (current_str(i:i) .eq. '.') then
556 current_str(i:i) = ' '
557 current_size = current_size + 1
558 end if
559 end do
560
561 removal_size = 1
562 do i = 1, len_trim(removal_str)
563 if (removal_str(i:i) .eq. '.') then
564 removal_str(i:i) = ' '
565 removal_size = removal_size + 1
566 end if
567 end do
568
569 read(current_str, *, iostat = iostat_current) &
570 current_number(1:current_size)
571 read(removal_str, *, iostat = iostat_removal) &
572 removal_number(1:removal_size)
573 versions_are_valid = (iostat_current .eq. 0 .and. iostat_removal .eq. 0)
574
575 if (.not. versions_are_valid) then
576 call neko_error('Invalid version string in deprecation check: ' // &
577 'NEKO_VERSION=' // trim(neko_version) // ', ' // &
578 'removal_version=' // trim(version_removal))
579 end if
580
581 is_deprecated = .true.
582 do i = 1, current_size
583 if (current_number(i) .gt. removal_number(i)) then
584 is_deprecated = .true.
585 exit
586 else if (current_number(i) .lt. removal_number(i)) then
587 is_deprecated = .false.
588 exit
589 end if
590 end do
591
592 end function is_deprecated
593end module logger
Definition comm.F90:1
integer, public pe_rank
MPI rank.
Definition comm.F90:57
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:533
subroutine log_end(this)
Decrease indention level.
Definition log.f90:177
subroutine log_print_section_header(this, lvl)
Print a section header.
Definition log.f90:402
subroutine log_deprecated(this, feature, removal_version, extra_info)
Write a deprecation warning to a log.
Definition log.f90:301
subroutine log_header(this, version, build_info)
Write the Neko header to a log.
Definition log.f90:254
integer, parameter, public neko_log_deprecation
Deprecation log level.
Definition log.f90:88
integer, parameter, public neko_log_verbose
Verbose log level.
Definition log.f90:86
subroutine log_message(this, msg, lvl)
Write a message to a log.
Definition log.f90:226
integer, parameter, public neko_log_quiet
Always logged.
Definition log.f90:82
subroutine log_begin(this)
Increase indention level.
Definition log.f90:166
subroutine log_message_c(c_msg)
Write a message to a log (from C)
Definition log.f90:446
subroutine log_end_section(this, msg, lvl)
End a log section.
Definition log.f90:427
subroutine log_init(this)
Initialize a log.
Definition log.f90:99
subroutine log_warning(this, msg)
Write a warning message to a log.
Definition log.f90:286
character(len=50), dimension(:), allocatable deprecated_list
List of already logged deprecated features.
Definition log.f90:93
subroutine log_error_c(c_msg)
Write an error message to a log (from C)
Definition log.f90:467
subroutine log_indent(this)
Indent a log.
Definition log.f90:193
subroutine log_warning_c(c_msg)
Write a warning message to a log (from C)
Definition log.f90:489
subroutine log_newline(this, lvl)
Write a new line to a log.
Definition log.f90:203
logical function is_deprecated(version_removal)
Compare version strings.
Definition log.f90:543
integer, parameter, public sec_head_size
Length of the section header.
Definition log.f90:49
subroutine log_section_c(c_msg)
Begin a new log section (from C)
Definition log.f90:512
integer, parameter, public neko_log_debug
Debug log level.
Definition log.f90:90
type(log_t), public neko_log
Global log stream.
Definition log.f90:80
integer, parameter, public log_size
Definition log.f90:46
integer, parameter, public neko_log_info
Default log level.
Definition log.f90:84
subroutine log_free(this)
Free a log.
Definition log.f90:134
subroutine log_section(this, msg, lvl)
Begin a new log section.
Definition log.f90:370
subroutine log_error(this, msg)
Write an error message to a log.
Definition log.f90:274
Build configurations.
character(len=10), parameter neko_version
Utilities.
Definition utils.f90:35
subroutine, public neko_warning(warning_msg)
Reports a warning to standard output.
Definition utils.f90:392