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 comm, only : pe_rank
36 use utils, only : neko_error
37 use, intrinsic :: iso_fortran_env, only : stdout => output_unit, &
38 stderr => error_unit
39 implicit none
40 private
41
42 ! > Size of the log message buffer
43 !! @note This adjust for the leading space applied by `write`. 80 character
44 !! output log leaves 79 characters for the message.
45 integer, public, parameter :: log_size = 79
46
47 type, public :: log_t
48 integer, private :: indent_
49 integer, private :: section_id_
50 integer, private :: tab_size_
51 integer, private :: level_
52 integer, private :: unit_
53
54 character(len=LOG_SIZE), private :: section_header = ""
55
56 contains
57 procedure, pass(this) :: init => log_init
58 procedure, pass(this) :: free => log_free
59 procedure, pass(this) :: begin => log_begin
60 procedure, pass(this) :: end => log_end
61 procedure, pass(this) :: indent => log_indent
62 procedure, pass(this) :: newline => log_newline
63 procedure, pass(this) :: message => log_message
64 procedure, pass(this) :: section => log_section
65 procedure, pass(this) :: header => log_header
66 procedure, pass(this) :: error => log_error
67 procedure, pass(this) :: warning => log_warning
68 procedure, pass(this) :: deprecated => log_deprecated
69 procedure, pass(this) :: end_section => log_end_section
70
71 procedure, private, pass(this) :: print_section_header => &
73 end type log_t
74
76 type(log_t), public :: neko_log
78 integer, public, parameter :: neko_log_quiet = 0
80 integer, public, parameter :: neko_log_info = 1
82 integer, public, parameter :: neko_log_verbose = 2
84 integer, public, parameter :: neko_log_deprecation_error = 5
86 integer, public, parameter :: neko_log_debug = 10
87
89 character(len=50), dimension(:), allocatable :: deprecated_list
90
91contains
92
94 subroutine log_init(this)
95 class(log_t), intent(inout) :: this
96 character(len=255) :: log_level
97 character(len=255) :: log_tab_size
98 character(len=255) :: log_file
99 integer :: envvar_len
100
101 this%indent_ = 0
102 this%section_id_ = 0
103
104 call get_environment_variable("NEKO_LOG_TAB_SIZE", log_tab_size, envvar_len)
105 if (envvar_len .gt. 0) then
106 read(log_tab_size(1:envvar_len), *) this%tab_size_
107 else
108 this%tab_size_ = 1
109 end if
110
111 call get_environment_variable("NEKO_LOG_LEVEL", log_level, envvar_len)
112 if (envvar_len .gt. 0) then
113 read(log_level(1:envvar_len), *) this%level_
114 else
115 this%level_ = neko_log_info
116 end if
117
118 call get_environment_variable("NEKO_LOG_FILE", log_file, envvar_len)
119 if (envvar_len .gt. 0) then
120 open(newunit = this%unit_, file = trim(log_file), status = 'replace', &
121 action = 'write')
122 else
123 this%unit_ = stdout
124 end if
125
126 end subroutine log_init
127
129 subroutine log_free(this)
130 class(log_t), intent(inout) :: this
131
132 if (this%section_id_ .ne. 0) then
133 call neko_error("Log is unbalanced")
134 end if
135
136 if (this%unit_ .ne. stdout) then
137 close(this%unit_)
138 end if
139
140 this%indent_ = 0
141 this%level_ = neko_log_info
142 this%unit_ = -1
143
144 if (allocated(deprecated_list)) then
145 deallocate(deprecated_list)
146 end if
147
148 end subroutine log_free
149
151 subroutine log_begin(this)
152 class(log_t), intent(inout) :: this
153
154 if (pe_rank .eq. 0) then
155 this%section_id_ = this%section_id_ + 1
156 this%indent_ = this%indent_ + this%tab_size_
157 end if
158
159 end subroutine log_begin
160
162 subroutine log_end(this)
163 class(log_t), intent(inout) :: this
164
165 if (pe_rank .eq. 0) then
166 if (this%section_id_ .eq. 0) then
167 call neko_error("Log is unbalanced")
168 end if
169 this%section_id_ = this%section_id_ - 1
170 this%indent_ = this%indent_ - this%tab_size_
171 end if
172
173 this%section_header = ""
174
175 end subroutine log_end
176
178 subroutine log_indent(this)
179 class(log_t), intent(in) :: this
180
181 if (pe_rank .eq. 0) then
182 write(this%unit_, '(A)', advance = 'no') repeat(' ', this%indent_)
183 end if
184
185 end subroutine log_indent
186
188 subroutine log_newline(this, lvl)
189 class(log_t), intent(in) :: this
190 integer, optional :: lvl
191
192 integer :: lvl_
193
194 if (present(lvl)) then
195 lvl_ = lvl
196 else
197 lvl_ = neko_log_info
198 end if
199
200 if (lvl_ .gt. this%level_) then
201 return
202 end if
203
204 if (pe_rank .eq. 0) then
205 write(this%unit_, '(A)') ''
206 end if
207
208 end subroutine log_newline
209
211 subroutine log_message(this, msg, lvl)
212 class(log_t), intent(inout) :: this
213 character(len=*), intent(in) :: msg
214 integer, optional :: lvl
215 integer :: lvl_
216
217 if (present(lvl)) then
218 lvl_ = lvl
219 else
220 lvl_ = neko_log_info
221 end if
222
223 if (lvl_ .gt. this%level_) then
224 return
225 end if
226
227 if (len_trim(this%section_header) .gt. 0) then
228 call this%print_section_header(lvl)
229 end if
230
231 if (pe_rank .eq. 0) then
232 call this%indent()
233 write(this%unit_, '(A)') trim(msg)
234 end if
235
236 end subroutine log_message
237
239 subroutine log_header(this, version, build_info)
240 class(log_t), intent(in) :: this
241 character(len=*), intent(in) :: version
242 character(len=*), intent(in) :: build_info
243
244 if (pe_rank .eq. 0) then
245 write(this%unit_, '(A)') ''
246 write(this%unit_, '(1X,A)') ' _ __ ____ __ __ ____ '
247 write(this%unit_, '(1X,A)') ' / |/ / / __/ / //_/ / __ \ '
248 write(this%unit_, '(1X,A)') ' / / / _/ / ,< / /_/ / '
249 write(this%unit_, '(1X,A)') '/_/|_/ /___/ /_/|_| \____/ '
250 write(this%unit_, '(A)') ''
251 write(this%unit_, '(1X,A,A,A)') '(version: ', trim(version), ')'
252 write(this%unit_, '(1X,A)') trim(build_info)
253 write(this%unit_, '(A)') ''
254 end if
255
256 end subroutine log_header
257
259 subroutine log_error(this, msg)
260 class(log_t), intent(in) :: this
261 character(len=*), intent(in) :: msg
262
263 if (pe_rank .eq. 0) then
264 call this%indent()
265 write(stderr, '(A,A,A)') '*** ERROR: ', trim(msg), ' ***'
266 end if
267
268 end subroutine log_error
269
271 subroutine log_warning(this, msg)
272 class(log_t), intent(in) :: this
273 character(len=*), intent(in) :: msg
274
275 if (pe_rank .eq. 0) then
276 call this%indent()
277 write(this%unit_, '(A,A,A)') '*** WARNING: ', trim(msg), ' ***'
278 end if
279
280 end subroutine log_warning
281
286 subroutine log_deprecated(this, feature, removal_version, extra_info)
287 class(log_t), intent(inout) :: this
288 character(len=*), intent(in) :: feature
289 character(len=*), intent(in), optional :: removal_version
290 character(len=*), intent(in), optional :: extra_info
291 character(len=LOG_SIZE) :: msg
292 character(len=50), dimension(:), allocatable :: deprecated_list_local
293 integer :: i
294
295 if (this%level_ .lt. neko_log_quiet) return
296
297 if (.not. allocated(deprecated_list)) then
298 allocate(character(len=50) :: deprecated_list(1))
299 deprecated_list = trim(feature)
300 else
301 ! Check that the feature have not already been logged
302 do i = 1, size(deprecated_list)
303 if (trim(deprecated_list(i)) .eq. trim(feature)) return
304 end do
305
306 ! Save the feature to the list of deprecated features
307 call move_alloc(deprecated_list, deprecated_list_local)
308 allocate(character(len=50)::deprecated_list(size(deprecated_list_local)+1))
309 deprecated_list(1:size(deprecated_list_local)) = deprecated_list_local
310 deprecated_list(size(deprecated_list_local) + 1) = trim(feature)
311 deallocate(deprecated_list_local)
312 end if
313
314 ! Construct deprecation message
315 write(msg, '(A,A)') '*** DEPRECATION: ', trim(feature)
316 call this%message(msg)
317 write(msg, '(A,A,A)') 'The feature "', trim(feature), &
318 '" is deprecated.'
319 call this%message(msg)
320
321 if (present(removal_version)) then
322 write(msg, '(A,A,A)') 'It will be removed in version ', &
323 trim(removal_version), '.'
324 call this%message(msg)
325 end if
326
327 if (present(extra_info)) then
328 call this%message(extra_info)
329 end if
330
331 call this%message('***')
332
333 if (this%level_ .ge. neko_log_deprecation_error) then
334 call neko_error('Deprecated feature used: ' // trim(feature))
335 end if
336
337 end subroutine log_deprecated
338
340 subroutine log_section(this, msg, lvl)
341 class(log_t), intent(inout) :: this
342 character(len=*), intent(in) :: msg
343 integer, optional :: lvl
344
345 integer :: pre, pos
346
347 if (len_trim(this%section_header) .gt. 0) then
348 call this%print_section_header(lvl)
349 end if
350
351 call this%begin()
352
353 if (pe_rank .eq. 0) then
354 pre = (30 - len_trim(msg)) / 2
355 pos = 30 - (len_trim(msg) + pre)
356
357 write(this%section_header, '(A,A,A)') &
358 repeat('-', pre), trim(msg), repeat('-', pos)
359 end if
360
361 end subroutine log_section
362
364 subroutine log_print_section_header(this, lvl)
365 class(log_t), intent(inout) :: this
366 integer, optional :: lvl
367 integer :: lvl_
368
369 if (present(lvl)) then
370 lvl_ = lvl
371 else
372 lvl_ = neko_log_info
373 end if
374
375 if (lvl_ .gt. this%level_) then
376 return
377 end if
378
379 if (pe_rank .eq. 0) then
380 call this%newline(lvl)
381 call this%indent()
382 write(this%unit_, '(A)') trim(this%section_header)
383 this%section_header = ""
384 end if
385
386 end subroutine log_print_section_header
387
389 subroutine log_end_section(this, msg, lvl)
390 class(log_t), intent(inout) :: this
391 character(len=*), intent(in), optional :: msg
392 integer, optional :: lvl
393
394 if (present(msg)) then
395 call this%message(msg, lvl)
396 end if
397
398 call this%end()
399
400 end subroutine log_end_section
401
402 !
403 ! Rudimentary C interface
404 !
405
408 subroutine log_message_c(c_msg) bind(c, name = 'log_message')
409 use, intrinsic :: iso_c_binding
410 character(kind=c_char), dimension(*), intent(in) :: c_msg
411 character(len=LOG_SIZE) :: msg
412 integer :: len
413
414 if (pe_rank .eq. 0) then
415 len = 0
416 do
417 if (c_msg(len+1) .eq. c_null_char) exit
418 len = len + 1
419 msg(len:len) = c_msg(len)
420 end do
421
422 call neko_log%message(trim(msg(1:len)))
423 end if
424
425 end subroutine log_message_c
426
429 subroutine log_error_c(c_msg) bind(c, name = "log_error")
430 use, intrinsic :: iso_c_binding
431 character(kind=c_char), dimension(*), intent(in) :: c_msg
432 character(len=LOG_SIZE) :: msg
433 integer :: len
434
435 if (pe_rank .eq. 0) then
436 len = 0
437 do
438 if (c_msg(len+1) .eq. c_null_char) exit
439 len = len + 1
440 msg(len:len) = c_msg(len)
441 end do
442
443 call neko_log%indent()
444 write(stderr, '(A,A,A)') '*** ERROR: ', trim(msg(1:len)), ' ***'
445 end if
446
447 end subroutine log_error_c
448
451 subroutine log_warning_c(c_msg) bind(c, name = "log_warning")
452 use, intrinsic :: iso_c_binding
453 character(kind=c_char), dimension(*), intent(in) :: c_msg
454 character(len=LOG_SIZE) :: msg
455 integer :: len
456
457 if (pe_rank .eq. 0) then
458 len = 0
459 do
460 if (c_msg(len+1) .eq. c_null_char) exit
461 len = len + 1
462 msg(len:len) = c_msg(len)
463 end do
464
465 call neko_log%indent()
466 write(neko_log%unit_, '(A,A,A)') &
467 '*** WARNING: ', trim(msg(1:len)), ' ***'
468 end if
469
470 end subroutine log_warning_c
471
474 subroutine log_section_c(c_msg) bind(c, name = "log_section")
475 use, intrinsic :: iso_c_binding
476 character(kind=c_char), dimension(*), intent(in) :: c_msg
477 character(len=LOG_SIZE) :: msg
478 integer :: len
479
480 if (pe_rank .eq. 0) then
481 len = 0
482 do
483 if (c_msg(len+1) .eq. c_null_char) exit
484 len = len + 1
485 msg(len:len) = c_msg(len)
486 end do
487
488 call neko_log%section(trim(msg(1:len)))
489 end if
490
491 end subroutine log_section_c
492
495 subroutine log_end_section_c() bind(c, name = "log_end_section")
496
497 call neko_log%end_section()
498
499 end subroutine log_end_section_c
500
501end 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:496
subroutine log_end(this)
Decrease indention level.
Definition log.f90:163
subroutine log_print_section_header(this, lvl)
Print a section header.
Definition log.f90:365
subroutine log_deprecated(this, feature, removal_version, extra_info)
Write a deprecation warning to a log.
Definition log.f90:287
subroutine log_header(this, version, build_info)
Write the Neko header to a log.
Definition log.f90:240
integer, parameter, public neko_log_verbose
Verbose log level.
Definition log.f90:82
subroutine log_message(this, msg, lvl)
Write a message to a log.
Definition log.f90:212
integer, parameter, public neko_log_quiet
Always logged.
Definition log.f90:78
subroutine log_begin(this)
Increase indention level.
Definition log.f90:152
subroutine log_message_c(c_msg)
Write a message to a log (from C)
Definition log.f90:409
subroutine log_end_section(this, msg, lvl)
End a log section.
Definition log.f90:390
subroutine log_init(this)
Initialize a log.
Definition log.f90:95
subroutine log_warning(this, msg)
Write a warning message to a log.
Definition log.f90:272
character(len=50), dimension(:), allocatable deprecated_list
List of already logged deprecated features.
Definition log.f90:89
subroutine log_error_c(c_msg)
Write an error message to a log (from C)
Definition log.f90:430
subroutine log_indent(this)
Indent a log.
Definition log.f90:179
subroutine log_warning_c(c_msg)
Write a warning message to a log (from C)
Definition log.f90:452
subroutine log_newline(this, lvl)
Write a new line to a log.
Definition log.f90:189
integer, parameter, public neko_log_deprecation_error
Deprecation error level.
Definition log.f90:84
subroutine log_section_c(c_msg)
Begin a new log section (from C)
Definition log.f90:475
integer, parameter, public neko_log_debug
Debug log level.
Definition log.f90:86
type(log_t), public neko_log
Global log stream.
Definition log.f90:76
integer, parameter, public log_size
Definition log.f90:45
integer, parameter, public neko_log_info
Default log level.
Definition log.f90:80
subroutine log_free(this)
Free a log.
Definition log.f90:130
subroutine log_section(this, msg, lvl)
Begin a new log section.
Definition log.f90:341
subroutine log_error(this, msg)
Write an error message to a log.
Definition log.f90:260
Utilities.
Definition utils.f90:35