Skip to content
Open
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 doc/changelog.d/1569.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add wbtrace option for logger - embedding
2 changes: 1 addition & 1 deletion src/ansys/mechanical/core/embedding/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ class App:
Create App with Mechanical project file and version:

>>> from ansys.mechanical.core import App
>>> app = App(db_file="path/to/file.mechdat", version=252)
>>> app = App(db_file="path/to/file.mechdat", version=261)

Disable copying the user profile when private appdata is enabled

Expand Down
52 changes: 51 additions & 1 deletion src/ansys/mechanical/core/embedding/logger/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import logging
import os
import typing
import warnings

from ansys.mechanical.core.embedding import initializer
from ansys.mechanical.core.embedding.logger import environ, linux_api, sinks, windows_api
Expand Down Expand Up @@ -90,7 +91,14 @@ class Configuration:
"""Configures logger for Mechanical embedding."""

@classmethod
def configure(cls, level=logging.WARNING, directory=None, base_directory=None, to_stdout=True):
def configure(
cls,
level=logging.WARNING,
directory=None,
base_directory=None,
to_stdout=True,
wbtracing=None,
):
"""Configure the logger for PyMechanical embedding.

Parameters
Expand All @@ -108,6 +116,13 @@ def configure(cls, level=logging.WARNING, directory=None, base_directory=None, t
to_stdout : bool, optional
Whether to write log messages to the standard output, which is the
command line. The default is ``True``.
wbtracing : bool, optional
Whether to enable WBTRACING for COM-level diagnostic output.
The default is ``None``, which preserves the current setting.
When enabled, trace messages from Mechanical's internal COM
implementation are written to stdout. Setting this after
Mechanical is initialized will have no effect on the running
instance but will persist in the environment.
"""
# Set up the global log configuration.
cls.set_log_directory(directory)
Expand All @@ -122,6 +137,10 @@ def configure(cls, level=logging.WARNING, directory=None, base_directory=None, t
cls._commit_enabled_configuration()
cls.set_log_level(level)

# Configure WBTRACING if specified.
if wbtracing is not None:
cls.set_wbtracing(wbtracing)

@classmethod
def set_log_to_stdout(cls, value: bool) -> None:
"""Configure logging to write to the standard output."""
Expand Down Expand Up @@ -165,6 +184,37 @@ def _commit_enabled_configuration(cls) -> None:
for sink in LOGGING_SINKS:
_get_backend().enable(sink)

@classmethod
def set_wbtracing(cls, enabled: bool) -> None:
"""Enable or disable WBTRACING for COM-level diagnostic output.

WBTRACING enables trace-level diagnostic output from Mechanical's
internal COM implementation. When enabled, trace messages are
written to stdout.

.. note::
Setting this after Mechanical has been initialized will have no
effect on the running instance. The env var is set for completeness
(e.g. for a future instance in the same process), but a warning
is issued.

Parameters
----------
enabled : bool
Whether to enable WBTRACING.
"""
if initializer.INITIALIZED_VERSION is not None:
warnings.warn(
"WBTRACING was set after Mechanical is already initialized. "
"It will have no effect on the current instance.",
UserWarning,
stacklevel=2,
)
if enabled:
os.environ["WBTRACING"] = "1"
else:
os.environ.pop("WBTRACING", None)

@classmethod
def _store_stdout_sink_enabled(cls, value: bool) -> None:
if value:
Expand Down
60 changes: 51 additions & 9 deletions tests/embedding/test_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def _unset_var(env, var) -> None:
_unset_var(env, "ANSYS_WORKBENCH_LOGGING_CONSOLE")
_unset_var(env, "ANSYS_WORKBENCH_LOGGING_AUTO_FLUSH")
_unset_var(env, "ANSYS_WORKBENCH_LOGGING_DIRECTORY")
_unset_var(env, "WBTRACING")
return env


Expand All @@ -52,8 +53,8 @@ def _run_embedding_log_test(
pytestconfig,
testname: str,
pass_expected: bool = True,
) -> tuple[bytes, bytes]:
"""Run the process and returns it after it finishes."""
) -> tuple[str, str]:
"""Run the process and returns (stdout, stderr) after it finishes."""
version = pytestconfig.getoption("ansys_version")
embedded_py = Path(rootdir) / "tests" / "scripts" / "embedding_log_test.py"

Expand All @@ -68,11 +69,11 @@ def _run_embedding_log_test(
subprocess_pass_expected,
)

stdout = stdout.decode()
if not subprocess_pass_expected:
stdout = stdout.decode()
_assert_success(stdout, pass_expected)
stderr = stderr.decode()
return stderr
return stdout, stderr


def _assert_success(stdout: str, pass_expected: bool) -> int:
Expand All @@ -93,7 +94,7 @@ def _assert_success(stdout: str, pass_expected: bool) -> int:
@pytest.mark.embedding_logging
def test_logging_write_log_before_init(rootdir, run_subprocess, pytestconfig):
"""Test that an error is thrown when trying to log before initializing."""
stderr = _run_embedding_log_test(
_, stderr = _run_embedding_log_test(
run_subprocess, rootdir, pytestconfig, "log_before_initialize", False
)
assert "Can't log to the embedding logger until Mechanical is initialized" in stderr
Expand All @@ -105,7 +106,7 @@ def test_logging_write_info_after_initialize_with_error_level(
rootdir, run_subprocess, pytestconfig
):
"""Test that no output is written when an info is logged when configured at the error level."""
stderr = _run_embedding_log_test(
_, stderr = _run_embedding_log_test(
run_subprocess,
rootdir,
pytestconfig,
Expand All @@ -119,7 +120,7 @@ def test_logging_write_info_after_initialize_with_error_level(
@pytest.mark.embedding_logging
def test_addin_configuration(rootdir, run_subprocess, pytestconfig, addin_configuration):
"""Test that mechanical can start with both the Mechanical and WorkBench configuration."""
stderr = _run_embedding_log_test(
_, stderr = _run_embedding_log_test(
run_subprocess,
rootdir,
pytestconfig,
Expand All @@ -134,7 +135,7 @@ def test_logging_write_error_after_initialize_with_info_level(
rootdir, run_subprocess, pytestconfig
):
"""Test that output is written when an error is logged when configured at the info level."""
stderr = _run_embedding_log_test(
_, stderr = _run_embedding_log_test(
run_subprocess, rootdir, pytestconfig, "log_error_after_initialize_with_info_level"
)
assert "Will no one rid me of this turbulent priest?" in stderr
Expand All @@ -151,7 +152,48 @@ def test_logging_level_before_and_after_initialization(rootdir, run_subprocess,
@pytest.mark.embedding_logging
def test_logging_all_level(rootdir, run_subprocess, pytestconfig):
"""Test all logging level after initialization."""
stderr = _run_embedding_log_test(
_, stderr = _run_embedding_log_test(
run_subprocess, rootdir, pytestconfig, "log_check_all_log_level"
)
assert all(keyword in stderr for keyword in ["debug", "warning", "info", "error", "fatal"])


@pytest.mark.embedding_logging
def test_wbtracing_configuration(monkeypatch, pytestconfig):
"""Test WBTRACING environment variable configuration and post-init warning."""
from ansys.mechanical.core.embedding import initializer
from ansys.mechanical.core.embedding.logger import Configuration

version = pytestconfig.getoption("ansys_version")
monkeypatch.delenv("WBTRACING", raising=False)

# set_wbtracing directly
Configuration.set_wbtracing(True)
assert os.environ.get("WBTRACING") == "1"
Configuration.set_wbtracing(False)
assert "WBTRACING" not in os.environ

# via configure()
Configuration.configure(wbtracing=None, to_stdout=True)
assert "WBTRACING" not in os.environ
Configuration.configure(wbtracing=True, to_stdout=True)
assert os.environ.get("WBTRACING") == "1"
Configuration.configure(wbtracing=False, to_stdout=True)
assert "WBTRACING" not in os.environ

# warns when called after init, but still sets the env var
monkeypatch.setattr(initializer, "INITIALIZED_VERSION", version)
with pytest.warns(UserWarning, match="no effect on the current instance"):
Configuration.set_wbtracing(True)
assert os.environ.get("WBTRACING") == "1"


@pytest.mark.embedding_scripts
@pytest.mark.embedding_logging
def test_logging_with_wbtracing(rootdir, run_subprocess, pytestconfig):
"""Test that WBTRACING can be enabled through the logger configuration."""
stdout, stderr = _run_embedding_log_test(
run_subprocess, rootdir, pytestconfig, "log_with_wbtracing"
)
assert "wbtracing_enabled" in stderr
assert "Looking for GUID" in stdout
11 changes: 11 additions & 0 deletions tests/scripts/embedding_log_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"""Test cases for embedding logging."""

import logging
import os
import sys

import ansys.mechanical.core as mech
Expand Down Expand Up @@ -92,6 +93,15 @@ def log_check_all_log_level(version):
Logger.fatal("fatal")


def log_with_wbtracing(version):
"""Enable WBTRACING via Configuration and verify logging works."""
Configuration.configure(level=logging.ERROR, to_stdout=True)
Configuration.set_wbtracing(True)
assert os.environ.get("WBTRACING") == "1"
_ = mech.App(version=version)
Logger.error("wbtracing_enabled")


if __name__ == "__main__":
version = sys.argv[1]
test_name = sys.argv[2]
Expand All @@ -103,6 +113,7 @@ def log_check_all_log_level(version):
"log_configuration_Mechanical": log_configuration_mechanical,
"log_configuration_WorkBench": log_configuration_workbench,
"log_check_all_log_level": log_check_all_log_level,
"log_with_wbtracing": log_with_wbtracing,
}
tests[test_name](int(version))
print("@@success@@")
Loading