Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
test
test_mpi
*.mod
/build/
35 changes: 35 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 3.11.0)

project(
Flogging
VERSION 1.0.0
LANGUAGES Fortran
)

# prepend custom CMake modules directory
list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")

# set destination for binaries, libraries, Fortran modules and generated doc
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_Fortran_MODULE_DIRECTORY "${CMAKE_BINARY_DIR}/modules")
set(CMAKE_DOC_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/doc")

# imports
find_package(MPI)

# import standard CMake modules
include(CMakePackageConfigHelpers)

# import custom CMake modules
include(Install)
include(Options)

# include code
add_subdirectory(src)
add_subdirectory(doc EXCLUDE_FROM_ALL)

if(BUILD_TESTING)
enable_testing()
add_subdirectory(tests)
endif()
14 changes: 10 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ endif
SOURCES = $(wildcard $(SRC)/*$(F90))
OBJS = $(patsubst $(SRC)/%$(F90), $(BUILD)/%$(OBJ), $(SOURCES))

$(LIB): $(OBJS)
$(LIB): warning $(OBJS)
$(FC) -shared -o $(LIB) $(OBJS)

$(BUILD)/%$(OBJ): $(SRC)/%$(F90)
Expand All @@ -28,12 +28,12 @@ $(BUILD)/flogging.o: $(BUILD)/vt100.o
# Some test executables
#
test : src/flogging.f90 tests/test.f90 src/vt100.f90 include/flogging.h
mpifort $(FLAGS) -Iinclude src/vt100.f90 src/flogging.f90 tests/test.f90 -o test
$(FC) $(FLAGS) -Iinclude src/vt100.f90 src/flogging.f90 tests/test.f90 -o test

test_mpi : src/flogging.f90 tests/test_mpi.f90 src/vt100.f90 include/flogging.h
mpifort $(FLAGS) -DUSE_MPI -Iinclude src/vt100.f90 src/flogging.f90 tests/test_mpi.f90 -o test_mpi
$(FC) $(FLAGS) -DUSE_MPI -Iinclude src/vt100.f90 src/flogging.f90 tests/test_mpi.f90 -o test_mpi

.PHONY: clean doc
.PHONY: clean doc warning
clean:
@find . -name '*.o' -delete
@find . -name '*.mod' -delete
Expand All @@ -44,3 +44,9 @@ doc:
ford flogging.md
doc_deploy: doc
git subtree push --prefix doc origin gh-pages

warning:
@echo "+--------------------------------------------------------------+"
@echo "| It is strongly recommended to use CMake to build the project |"
@echo "| Check README.md |"
@echo "+--------------------------------------------------------------+"
119 changes: 100 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
# Flogging
This logging system aims to be simple to use, similar to existing write statements and therefore easy to implement in existing codes,
while providing some convenient extra features not present in fortran by default.

This logging system aims to be simple to use, similar to existing write statements and therefore easy to implement in existing codes, while providing some convenient extra features not present in fortran by default.

Usage is very simple:

```fortran
use flogging
```

To load the logging module and its utility functions.
To use the preprovided macros, include the header file and turn on the preprocessor by compiling with `-cpp`

```C
#include "flogging.h"
```

This macro defines the following functions:

```fortran
log_fatal(format)
log_error(format)
Expand All @@ -28,66 +32,116 @@ log_root_info(format)
log_root_debug(format)
log_root_trace(format)
```
Where `format` is usually `*`, but can be adjusted to suit your needs. Remember to include a single `A` specifier for the log lead if you set it yourself.

Where `format` is usually `*`, but can be adjusted to suit your needs.
Remember to include a single `A` specifier for the log lead if you set it yourself.

The functions print a log message only if the level is greater than or equal to the current minimum loglevel.
The second functions include a check to print a log message only from the root MPI process, if compiled
with `USE_MPI`. If not compiled with `USE_MPI`, it works the same as the log function.
The second functions include a check to print a log message only from the root MPI process, if compiled with `USE_MPI`.
If not compiled with `USE_MPI`, it works the same as the log function.

If you do not want to use the preprocessor macros, you can log like this.

```fortran
if (logp(LEVEL)) then
write(logu,FORMAT) trim(logl(LEVEL))//" ", "this is a log message"
endif
```

Note that it is not possible to use the filename and linenumber features then.

# Installation
You can compile `flogging.f90` and `vt100.f90` into a library `flogging.so` with `make`.
To compile with MPI support use
```bash
make USE_MPI=1
## Build

This library is built with CMake:

```sh
mkdir build
cd build
cmake ..
make
```

To compile with MPI support, invoke CMake accordingly:

```sh
cmake -DUSE_MPI=ON ..
```

## Build and install

To install the library, you should request a release build, specify the installation directory prefix (default to `/usr/local`), then build.
Note that you can specify options to CMake with the text interface `ccmake`, or the GUI interface on Windows:

```
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/path/to/install/dir ..
make
make install
```

This will also install CMake scripts to use the library in other CMake projects with:

```cmake
find_package(Flogging)

add_library(mylib ...)
target_link_libraries(mylib PRIVATE Flogging::Flogging)
```
Then, place `libflogging.so` into your `LD_LIBRARY_PATH` and put `flogging.h` into your include path.

## Compilation flags

Compile your own code with

```
-DDISABLE_LOG_DEBUG
```
to remove any debug statements from your code. Note that you cannot use `-v` to get these back then.
By default any `log_trace` messages are not included in the executable. Compile with

to remove any debug statements from your code.
Note that you cannot use `-v` to get these back then.
By default any `log_trace` messages are not included in the executable.
Compile with

```
-DENABLE_LOG_TRACE
```
to get these back. Note that you still need to use `-vv` (by default) to see the messages.

to get these back.
Note that you still need to use `-vv` (by default) to see the messages.
This is a good compilation flag to have in your debug build profile.

## Transitioning to flogging

You can change all of the messages in your application to the `log_info` level by

```bash
git sed 's/write ?(\*,\*)/log_info(*)/g'
```

You might need to split some lines, as the `__FILE__` and `__LINE__` macros require quite some space.
This can also be circumvented by compiling with `-ffree-line-length-none` or equivalent.

# Examples

```fortran
log_error(*) "this is an error"
log_warn(*) "this is a warning"
log_info(*) "here, have some info"
log_debug(*) "and this is a debug message"
```

outputs (without any compilation flags)

```
localhost test.f90:9 ERROR this is an error
localhost test.f90:10 WARN this is a warning
localhost test.f90:11 INFO here, have some info
```
(The leading space is a consequence of using the fortran * format specifier)

(The leading space is a consequence of using the fortran * format specifier.)

## Interface

The module `flogging` defines some subroutines you can use to alter it's behaviour:

```fortran
public :: log_set_output_hostname
public :: log_set_output_severity
Expand All @@ -100,7 +154,9 @@ public :: log_disable_cli_arguments
```

## Command-line flags

The logging module allows the following command-line flags, checked at the time of the first log output.

```
-v, --verbose Increase the logging verbosity
-q, --quiet Decrease the logging verbosity
Expand All @@ -112,35 +168,60 @@ The logging module allows the following command-line flags, checked at the time
```

### Argument parsing
By default, flogging parses the command-line arguments above on the first invocation of `log()`.

By default, flogging parses the command-line arguments above on the first invocation of `log_*()`.
If you want to use your own argument parsing you can disable this behaviour by calling `log_disable_cli_arguments` before any output is logged.

## Output to a file

Logging is to stderr by default. Another output unit can be selected by setting

```fortran
logu = some_unit
```

This will probably not work well with MPI.

## Internals

The latest documentation can be found [here](http://exteris.github.io/flogging/).

You can build the documentation with Ford, or directly when building the project:

```sh
make doc
```

The module defines a function defining whether or not to print this log message,

```fortran
logp(level)
```

where level is one of `LOG_FATAL`, `LOG_ERROR`, `LOG_WARN`, `LOG_INFO`, `LOG_DEBUG` or `LOG_TRACE`.
The logp function can also be used with MPI support, using an optional integer parameter `only_n` to return true
only if the level is sufficient and the MPI rank of the current thread is equal to `only_n`.
This can be used to print messages only from the root thread, to prevent log messages from being printed N times as shown below.
The `logp` function can also be used with MPI support, using an optional integer parameter `only_n` to return true only if the level is sufficient and the MPI rank of the current thread is equal to `only_n`.
This can be used to print messages only from the root thread, to prevent log messages from being printed *N* times as shown below.

```fortran
logp(level,0)
```

## Testing

You can build a test program when invoking CMake and run it:

```sh
cmake -DBUILD_TESTING=ON ..
make
ctest
```

## Contributing

Pull requests and comments are appreciated.

## TODO

- Argument parsing is quite flaky (try -qqqqqq and see what happens)
- Time and date output at the same time does not work yet
- Compilation flag to control argument parsing
Expand Down
3 changes: 3 additions & 0 deletions cmake/Config.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@PACKAGE_INIT@

include("${CMAKE_CURRENT_LIST_DIR}/FloggingTargets.cmake")
30 changes: 30 additions & 0 deletions cmake/Modules/Install.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# export targets to be found by CMake in another project
install(
EXPORT FloggingTargets
FILE FloggingTargets.cmake
DESTINATION lib/cmake/Flogging
NAMESPACE "Flogging::"
)

# generate config
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/FloggingConfig.cmake"
INSTALL_DESTINATION lib/cmake/Flogging
NO_SET_AND_CHECK_MACRO
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)

# add version of the project to config
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/FloggingConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)

# export config
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/FloggingConfig.cmake"
DESTINATION lib/cmake/Flogging
)
15 changes: 15 additions & 0 deletions cmake/Modules/Options.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# flag to use MPI
option(
USE_MPI
"Build using MPI"
)

if(NOT MPI_FOUND AND USE_MPI)
message(FATAL_ERROR "MPI requested but not found")
endif()

# flag to build tests
option(
BUILD_TESTING
"Build tests"
)
14 changes: 14 additions & 0 deletions doc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
find_program(FORD_EXE NAMES ford)

if(FORD_EXE)
set(FORD_CONFIG "${CMAKE_SOURCE_DIR}/flogging.md")
add_custom_target(
doc
COMMAND ${FORD_EXE} -o "${CMAKE_DOC_OUTPUT_DIRECTORY}" "${FORD_CONFIG}"
)

add_custom_target(
doc-deploy
COMMAND git subtree push --prefix doc origin gh-pages
)
endif()
Loading