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 deprecation_error = ""
348 call get_environment_variable("NEKO_DEPRECATION_ERROR", &
349 deprecation_error)
350
351 if (trim(deprecation_error) .eq. "1") then
352 call neko_error('Deprecated feature "' // trim(feature) // &
353 '" is scheduled for removal in version: ' // &
354 trim(removal_version) // ' (current version: ' // &
355 trim(neko_version) // ').')
356 else if (is_deprecated(removal_version)) then
357 call neko_warning('Deprecated feature "' // trim(feature) // &
358 '" is scheduled for removal in version: ' // &
359 trim(removal_version) // ' (current version: ' // &
360 trim(neko_version) // ').')
361 end if
362 end if
363
364 end subroutine log_deprecated
365
367 subroutine log_section(this, msg, lvl)
368 class(log_t), intent(inout) :: this
369 character(len=*), intent(in) :: msg
370 integer, optional :: lvl
371
372 integer :: pre, pos
373
374 if (len_trim(this%section_header) .gt. 0) then
375 call this%print_section_header(lvl)
376 end if
377
378 call this%begin()
379
380 if (pe_rank .eq. 0) then
381 pre = (30 - len_trim(msg)) / 2
382 pos = 30 - (len_trim(msg) + pre)
383
384 if (pre .lt. 0 .or. pos .lt. 0) then
385 pre = 1
386 pos = 1
387 write(this%section_header, '(A,A,A)') &
388 repeat('-', pre), trim(msg(1: sec_head_size - 2)), &
389 repeat('-', pos)
390 else
391 write(this%section_header, '(A,A,A)') &
392 repeat('-', pre), trim(msg), repeat('-', pos)
393 end if
394 end if
395
396 end subroutine log_section
397
399 subroutine log_print_section_header(this, lvl)
400 class(log_t), intent(inout) :: this
401 integer, optional :: lvl
402 integer :: lvl_
403
404 if (present(lvl)) then
405 lvl_ = lvl
406 else
407 lvl_ = neko_log_info
408 end if
409
410 if (lvl_ .gt. this%level_) then
411 return
412 end if
413
414 if (pe_rank .eq. 0) then
415 call this%newline(lvl)
416 call this%indent()
417 write(this%unit_, '(A)') trim(this%section_header)
418 this%section_header = ""
419 end if
420
421 end subroutine log_print_section_header
422
424 subroutine log_end_section(this, msg, lvl)
425 class(log_t), intent(inout) :: this
426 character(len=*), intent(in), optional :: msg
427 integer, optional :: lvl
428
429 if (present(msg)) then
430 call this%message(msg, lvl)
431 end if
432
433 call this%end()
434
435 end subroutine log_end_section
436
437 !
438 ! Rudimentary C interface
439 !
440
443 subroutine log_message_c(c_msg) bind(c, name = 'log_message')
444 use, intrinsic :: iso_c_binding
445 character(kind=c_char), dimension(*), intent(in) :: c_msg
446 character(len=LOG_SIZE) :: msg
447 integer :: len
448
449 if (pe_rank .eq. 0) then
450 len = 0
451 do
452 if (c_msg(len+1) .eq. c_null_char) exit
453 len = len + 1
454 msg(len:len) = c_msg(len)
455 end do
456
457 call neko_log%message(trim(msg(1:len)))
458 end if
459
460 end subroutine log_message_c
461
464 subroutine log_error_c(c_msg) bind(c, name = "log_error")
465 use, intrinsic :: iso_c_binding
466 character(kind=c_char), dimension(*), intent(in) :: c_msg
467 character(len=LOG_SIZE) :: msg
468 integer :: len
469
470 if (pe_rank .eq. 0) then
471 len = 0
472 do
473 if (c_msg(len+1) .eq. c_null_char) exit
474 len = len + 1
475 msg(len:len) = c_msg(len)
476 end do
477
478 call neko_log%indent()
479 write(stderr, '(A,A,A)') '*** ERROR: ', trim(msg(1:len)), ' ***'
480 end if
481
482 end subroutine log_error_c
483
486 subroutine log_warning_c(c_msg) bind(c, name = "log_warning")
487 use, intrinsic :: iso_c_binding
488 character(kind=c_char), dimension(*), intent(in) :: c_msg
489 character(len=LOG_SIZE) :: msg
490 integer :: len
491
492 if (pe_rank .eq. 0) then
493 len = 0
494 do
495 if (c_msg(len+1) .eq. c_null_char) exit
496 len = len + 1
497 msg(len:len) = c_msg(len)
498 end do
499
500 call neko_log%indent()
501 write(neko_log%unit_, '(A,A,A)') &
502 '*** WARNING: ', trim(msg(1:len)), ' ***'
503 end if
504
505 end subroutine log_warning_c
506
509 subroutine log_section_c(c_msg) bind(c, name = "log_section")
510 use, intrinsic :: iso_c_binding
511 character(kind=c_char), dimension(*), intent(in) :: c_msg
512 character(len=LOG_SIZE) :: msg
513 integer :: len
514
515 if (pe_rank .eq. 0) then
516 len = 0
517 do
518 if (c_msg(len+1) .eq. c_null_char) exit
519 len = len + 1
520 msg(len:len) = c_msg(len)
521 end do
522
523 call neko_log%section(trim(msg(1:len)))
524 end if
525
526 end subroutine log_section_c
527
530 subroutine log_end_section_c() bind(c, name = "log_end_section")
531
532 call neko_log%end_section()
533
534 end subroutine log_end_section_c
535
540 logical function is_deprecated(version_removal)
541 character(len=*), intent(in) :: version_removal
542 character(len=50) :: current_str, removal_str
543 integer :: current_number(3), removal_number(3)
544 integer :: i, current_size, removal_size
545 integer :: iostat_current, iostat_removal
546 logical :: versions_are_valid, is_newer_than_removal
547
548 current_str = trim(neko_version)
549 removal_str = trim(version_removal)
550
551 current_size = 1
552 do i = 1, len_trim(current_str)
553 if (current_str(i:i) .eq. '.') then
554 current_str(i:i) = ' '
555 current_size = current_size + 1
556 end if
557 end do
558
559 removal_size = 1
560 do i = 1, len_trim(removal_str)
561 if (removal_str(i:i) .eq. '.') then
562 removal_str(i:i) = ' '
563 removal_size = removal_size + 1
564 end if
565 end do
566
567 read(current_str, *, iostat = iostat_current) &
568 current_number(1:current_size)
569 read(removal_str, *, iostat = iostat_removal) &
570 removal_number(1:removal_size)
571 versions_are_valid = (iostat_current .eq. 0 .and. iostat_removal .eq. 0)
572
573 if (.not. versions_are_valid) then
574 call neko_error('Invalid version string in deprecation check: ' // &
575 'NEKO_VERSION=' // trim(neko_version) // ', ' // &
576 'removal_version=' // trim(version_removal))
577 end if
578
579 is_deprecated = .true.
580 do i = 1, current_size
581 if (current_number(i) .gt. removal_number(i)) then
582 is_deprecated = .true.
583 exit
584 else if (current_number(i) .lt. removal_number(i)) then
585 is_deprecated = .false.
586 exit
587 end if
588 end do
589
590 end function is_deprecated
591end module logger
Definition comm.F90:1
integer, public pe_rank
MPI rank.
Definition comm.F90:58
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:531
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:400
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:444
subroutine log_end_section(this, msg, lvl)
End a log section.
Definition log.f90:425
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:465
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:487
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:541
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:510
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:368
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:398