Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding actions for opening, flushing, and closing the logs #1442

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project aspires to adhere to [Semantic Versioning](https://semver.org/s
- [email protected]

### Added
- Added action options relating to logging functionality including `open_log`, `flush_log`, and `close_log` to toggle logging as well as `set_log_threshold` and `set_echo_threshold` to control logging and standard output levels.
- Added a new unified logging infrastructure.
- Added support for unstructured topologies with mixed elements types (for example, hexs and tets).
- Added support for `pyramid` and `wedge` elements.
Expand Down
5 changes: 5 additions & 0 deletions src/docs/sphinx/Actions/Actions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ The currently supported actions are:
- ``add_triggers`` : adds a list of triggers that executes a set of actions based on a condition
- ``save_info`` : saves ascent info result at the end of execution
- ``save_session`` : saves expression session info at the end of execution (see :ref:`ExpressionsSaveSession`)
- ``open_log`` : opens an assent logging stream and starts logging
- ``flush_log`` : flushes the current logging stream to the output file
- ``close_log`` : closes the current logging stream which stops logging
- ``set_log_threshold`` : changes the threshold of messages recorded in the log file
- ``set_echo_threshold`` : changes the threshold of messages displayed in standard output


Ascent actions can be specified within the integration using Conduit Nodes and can be read in through a file.
Expand Down
85 changes: 85 additions & 0 deletions src/docs/sphinx/Actions/Logging.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
.. ############################################################################
.. # Copyright (c) Lawrence Livermore National Security, LLC and other Ascent
.. # Project developers. See top-level LICENSE AND COPYRIGHT files for dates and
.. # other details. No copyright assignment is required to contribute to Ascent.
.. ############################################################################

.. _Logging:

Logging Overview
================

Ascent's logging options allow for control over the types of messages and information that are
recorded and displayed. These functionalities are provided to allow for additional information to
be recorded while the tool is being run in order to identify and diagnose any erroneous behavior.

The ``log`` options refer to the messages that are collected in a designated log stream and output
to a designated log file. The ``echo`` options control the messages and types of information output
to the standard output stream.

Log Levels:
- ``all`` : all messages will be recorded
- ``debug`` : extra verbose output messages useful for diagnosing issues
- ``info`` : normal system operations
- ``warn`` : potential issues that could become a problem
- ``error`` : significant issues that need to be addressed
- ``none`` : no messages will be recorded.

Opening Logs
------------

The ``open_log`` action can be used to start a logging stream. While there are no required keywords,
options to set the output log file name and location using the ``file_pattern`` keyword as well as
the logging threshold level using the ``log_threshold`` are available. The Default ``file_pattern``
is ``ascent_log_output.yaml`` and the default ``log_threshold`` is ``debug``.

.. code-block:: yaml

-
action: "open_log"
file_pattern: "ascent_log_out_{rank:05d}.yaml"
log_threshold: "debug"

Flushing Logs
-------------

The ``flush_log`` action can be used to flush the current log streams to disk.

.. code-block:: yaml

-
action: "flush_log"

Closing Logs
------------

The ``close_log`` action can be used to close the current log stream.

.. code-block:: yaml

-
action: "close_log"

Setting the Logging Threshold
-----------------------------

The ``set_log_threshold`` action allows for the adjustment of the level of log messages being
recorded to the current log stream.

.. code-block:: yaml

-
action: "set_log_threshold"
log_threshold: "all"

Setting the Echo Threshold
-----------------------------

The ``set_echo_threshold`` action allows for the adjustment of the level of log messages being
recorded to the standard output stream.

.. code-block:: yaml

-
action: "set_echo_threshold"
echo_threshold: "info"
1 change: 1 addition & 0 deletions src/docs/sphinx/Actions/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Ascent Actions
Pipelines
Extracts
Triggers
Logging
Examples
ExpressionsOverview
expression_objects
Expand Down
71 changes: 71 additions & 0 deletions src/libs/ascent/runtimes/ascent_main_runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//-----------------------------------------------------------------------------

#include "ascent_main_runtime.hpp"
#include <ascent_logging.hpp>

// standard lib includes
#include <string.h>
Expand Down Expand Up @@ -1936,6 +1937,76 @@ AscentRuntime::BuildGraph(const conduit::Node &actions)
// the workspace executes.
m_save_info_actions.append() = action;
}
else if(action_name == "open_log")
{
// Open Ascent Logging Stream
// This starts logging


if(action.has_path("log_threshold"))
{
ascent::Logger::instance().set_log_threshold(action["log_threshold"].as_string());
}
else
{
ascent::Logger::instance().set_log_threshold(ascent::Logger::LOG_DEBUG_ID);
}

#if defined(ASCENT_MPI_ENABLED)
std::string file_pattern = action.has_path("file_pattern") ?
action["file_pattern"].as_string() : "ascent_log_output_rank_{rank:05d}.yaml";

int comm_id = flow::Workspace::default_mpi_comm();
MPI_Comm mpi_comm = MPI_Comm_f2c(comm_id);
int comm_size = 1;
MPI_Comm_size(mpi_comm, &comm_size);
ASCENT_LOG_OPEN_RANK( file_pattern, m_rank );
ASCENT_LOG_DEBUG(conduit_fmt::format("mpi info: rank={}, size={}",
m_rank,
comm_size));
#else
std::string file_pattern = action.has_path("file_pattern") ?
action["file_pattern"].as_string() : "ascent_log_output.yaml";
ASCENT_LOG_OPEN(file_pattern);
ASCENT_LOG_DEBUG("MPI not enabled");
#endif
}
else if(action_name == "flush_log")
{
// Flush Current Log Streams to Disk
// This is so they can be seen before ascent is closed out
ASCENT_LOG_FLUSH();
}
else if(action_name == "set_log_threshold")
{
// Change the logging level
if (action.has_path("log_threshold"))
{
ascent::Logger::instance().set_log_threshold(action["log_threshold"].as_string());
}
else
{
ASCENT_WARN("No Log Threshold level given. No changes to logging behavior made.");
}
}
else if(action_name == "set_echo_threshold")
{
// Change the echo to standard output level
if (action.has_path("echo_threshold"))
{
ascent::Logger::instance().set_echo_threshold(action["echo_threshold"].as_string());
}
else
{
ASCENT_WARN("No Echo Threshold level given. No changes to echo output behavior made.");
}
}
else if(action_name == "close_log")
{
// Closes current log stream
// This stops logging
ASCENT_LOG_CLOSE();
}
else
{
ASCENT_ERROR("Unknown action ' "<<action_name<<"'");
Expand Down
163 changes: 162 additions & 1 deletion src/tests/ascent/t_ascent_logging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,165 @@ TEST(ascent_logging, test_logging_options)
// check that the log file exists
EXPECT_TRUE(conduit::utils::is_file(log_file));

}
}

//-----------------------------------------------------------------------------
TEST(ascent_logging, test_logging_actions)
{
Node n;
ascent::about(n);
// only run this test if ascent was built with vtkm support
if(n["runtimes/ascent/vtkm/status"].as_string() == "disabled")
{
ASCENT_INFO("Ascent vtkm support disabled, skipping test");
return;
}

//
// Create an example mesh.
//
Node data, verify_info;
conduit::blueprint::mesh::examples::braid("hexs",
5,
5,
5,
data);
EXPECT_TRUE(conduit::blueprint::mesh::verify(data,verify_info));


string output_path = prepare_output_dir();
string output_file = conduit::utils::join_file_path(output_path,"tout_logging_render3");
string log_file = conduit::utils::join_file_path(output_path,"ascent_action_log.yaml");

// remove old images/log files before rendering
remove_test_image(output_file);
conduit::utils::remove_path_if_exists(log_file);
EXPECT_FALSE(conduit::utils::is_file(log_file));

conduit::Node actions;
conduit::Node &add_scenes= actions.append();
add_scenes["action"] = "add_scenes";
conduit::Node &scenes = add_scenes["scenes"];
scenes["s1/plots/p1/type"] = "pseudocolor";
scenes["s1/plots/p1/field"] = "braid";
scenes["s1/image_prefix"] = output_file;

conduit::Node actions_begin_logs;
conduit::Node &begin_logs= actions_begin_logs.append();
begin_logs["action"] = "open_log";
begin_logs["file_pattern"] = log_file;

conduit::Node actions_flush_logs;
conduit::Node &flush_logs= actions_flush_logs.append();
flush_logs["action"] = "flush_log";

conduit::Node actions_close_logs;
conduit::Node &close_logs= actions_close_logs.append();
close_logs["action"] = "close_log";

//
// Run Ascent
//

Ascent ascent;

ascent.open();
ascent.publish(data);
ascent.execute(actions_begin_logs);
ascent.execute(actions);
ascent.execute(actions_flush_logs);
ascent.execute(actions_close_logs);
ascent.close();

// check that the log file exists
EXPECT_TRUE(conduit::utils::is_file(log_file));

// check that the log file has the expected number of logs in it (1 open, 3 execution, 1 close)
conduit::Node log_file_contents;
log_file_contents.load(log_file);
EXPECT_EQ(log_file_contents.number_of_children(), 6);
}

//-----------------------------------------------------------------------------
TEST(ascent_logging, test_logging_actions_threshold)
{
Node n;
ascent::about(n);
// only run this test if ascent was built with vtkm support
if(n["runtimes/ascent/vtkm/status"].as_string() == "disabled")
{
ASCENT_INFO("Ascent vtkm support disabled, skipping test");
return;
}

//
// Create an example mesh.
//
Node data, verify_info;
conduit::blueprint::mesh::examples::braid("hexs",
5,
5,
5,
data);
EXPECT_TRUE(conduit::blueprint::mesh::verify(data,verify_info));


string output_path = prepare_output_dir();
string output_file = conduit::utils::join_file_path(output_path,"tout_logging_render4");
string log_file = conduit::utils::join_file_path(output_path,"ascent_action_log_thresholded.yaml");

// remove old images/log files before rendering
remove_test_image(output_file);
conduit::utils::remove_path_if_exists(log_file);
EXPECT_FALSE(conduit::utils::is_file(log_file));

conduit::Node actions;
conduit::Node &add_scenes= actions.append();
add_scenes["action"] = "add_scenes";
conduit::Node &scenes = add_scenes["scenes"];
scenes["s1/plots/p1/type"] = "pseudocolor";
scenes["s1/plots/p1/field"] = "braid";
scenes["s1/image_prefix"] = output_file;

conduit::Node actions_begin_logs;
conduit::Node &begin_logs= actions_begin_logs.append();
begin_logs["action"] = "open_log";
begin_logs["file_pattern"] = log_file;
begin_logs["log_threshold"] = "all";
conduit::Node &set_threshold_logs_open= actions_begin_logs.append();
set_threshold_logs_open["action"] = "set_log_threshold";
set_threshold_logs_open["log_threshold"] = "error";

conduit::Node actions_flush_logs;
conduit::Node &flush_logs= actions_flush_logs.append();
flush_logs["action"] = "flush_log";

conduit::Node actions_close_logs;
conduit::Node &set_threshold_logs_close= actions_close_logs.append();
set_threshold_logs_close["action"] = "set_log_threshold";
set_threshold_logs_close["log_threshold"] = "debug";
conduit::Node &close_logs= actions_close_logs.append();
close_logs["action"] = "close_log";

//
// Run Ascent
//

Ascent ascent;

ascent.open();
ascent.publish(data);
ascent.execute(actions_begin_logs);
ascent.execute(actions);
ascent.execute(actions_flush_logs);
ascent.execute(actions_close_logs);
ascent.close();

// check that the log file exists
EXPECT_TRUE(conduit::utils::is_file(log_file));

// check that the log file has the expected number of logs in it (1 open, 3 execution, 1 close)
conduit::Node log_file_contents;
log_file_contents.load(log_file);
EXPECT_EQ(log_file_contents.number_of_children(), 3);
}
Loading
Loading