diff --git a/qase-behave/README.md b/qase-behave/README.md index 82bbae78..3eedc199 100644 --- a/qase-behave/README.md +++ b/qase-behave/README.md @@ -95,6 +95,10 @@ Configuration options are described in the } } }, + "logging": { + "console": true, + "file": false + }, "environment": "local" } ``` diff --git a/qase-behave/changelog.md b/qase-behave/changelog.md index 2571281d..31bbb52d 100644 --- a/qase-behave/changelog.md +++ b/qase-behave/changelog.md @@ -1,3 +1,9 @@ +# qase-behave 2.0.2 + +## What's new + +- Added support for logging configuration. More information about logging configuration can be found in the [docs](../qase-python-commons/docs/LOGGING.md). + # qase-behave 2.0.1 ## What's new diff --git a/qase-behave/docs/CONFIGURATION.md b/qase-behave/docs/CONFIGURATION.md index 3d48ac2d..82822be8 100644 --- a/qase-behave/docs/CONFIGURATION.md +++ b/qase-behave/docs/CONFIGURATION.md @@ -21,6 +21,9 @@ and command line options override both other values. | Root suite | `rootSuite` | `QASE_ROOT_SUITE` | `qase-root-suite` | | No | Any string | | Debug logs | `debug` | `QASE_DEBUG` | `qase-debug` | `False` | No | `True`, `False` | | Exclude parameters from test results | `excludeParams` | `QASE_EXCLUDE_PARAMS` | `qase-exclude-params` | None, don't exclude any parameters | No | Comma-separated list of parameter names | +| **Logging configuration** | +| Enable/disable console logging output | `logging.console` | `QASE_LOGGING_CONSOLE` | `qase-logging-console` | `true` | No | `true`, `false` | +| Enable/disable file logging output | `logging.file` | `QASE_LOGGING_FILE` | `qase-logging-file` | `false` (true when debug=true) | No | `true`, `false` | | **Qase TestOps mode configuration** | | Qase project code | `testops.project` | `QASE_TESTOPS_PROJECT` | `qase-testops-project` | | Yes | Any string | | Qase API token | `testops.api.token` | `QASE_TESTOPS_API_TOKEN` | `qase-testops-api-token` | | Yes | Any string | @@ -52,6 +55,10 @@ and command line options override both other values. "fallback": "report", "debug": false, "environment": "local", + "logging": { + "console": true, + "file": false + }, "report": { "driver": "local", "connection": { diff --git a/qase-behave/pyproject.toml b/qase-behave/pyproject.toml index 4c1d43ce..5117d0fe 100644 --- a/qase-behave/pyproject.toml +++ b/qase-behave/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "qase-behave" -version = "2.0.1" +version = "2.0.2" description = "Qase Behave Plugin for Qase TestOps and Qase Report" readme = "README.md" keywords = ["qase", "behave", "plugin", "testops", "report", "qase reporting", "test observability"] @@ -28,7 +28,7 @@ classifiers = [ ] requires-python = ">=3.9" dependencies = [ - "qase-python-commons~=4.0.1", + "qase-python-commons~=4.1.0", "behave>=1.2.6", "more_itertools", ] diff --git a/qase-behave/src/qase/behave/formatter.py b/qase-behave/src/qase/behave/formatter.py index b38c1833..77c3689a 100644 --- a/qase-behave/src/qase/behave/formatter.py +++ b/qase-behave/src/qase/behave/formatter.py @@ -199,4 +199,18 @@ def __parse_config(userdata) -> ConfigManager: cfg_mgr.config.report.connection.set_format( userdata['qase-report-connection-format']) + if 'qase-logging-console' in userdata: + cfg_mgr.config.logging.set_console(userdata['qase-logging-console']) + + if 'qase-logging-file' in userdata: + cfg_mgr.config.logging.set_file(userdata['qase-logging-file']) + + # Update logger with final logging options after all options are processed + from qase.commons.logger import LoggingOptions + logging_options = LoggingOptions( + console=cfg_mgr.config.logging.console if cfg_mgr.config.logging.console is not None else True, + file=cfg_mgr.config.logging.file if cfg_mgr.config.logging.file is not None else cfg_mgr.config.debug + ) + cfg_mgr.logger = cfg_mgr.logger.__class__(debug=cfg_mgr.config.debug, logging_options=logging_options) + return cfg_mgr diff --git a/qase-pytest/README.md b/qase-pytest/README.md index 5bf7ac05..734bd747 100644 --- a/qase-pytest/README.md +++ b/qase-pytest/README.md @@ -63,6 +63,10 @@ Configuration options are described in the "captureLogs": true } }, + "logging": { + "console": true, + "file": false + }, "environment": "local" } ``` diff --git a/qase-pytest/changelog.md b/qase-pytest/changelog.md index 5455b329..38b051d6 100644 --- a/qase-pytest/changelog.md +++ b/qase-pytest/changelog.md @@ -1,3 +1,9 @@ +# qase-pytest 7.0.3 + +## What's new + +- Added support for logging configuration. More information about logging configuration can be found in the [docs](../qase-python-commons/docs/LOGGING.md). + # qase-pytest 7.0.2 ## What's new diff --git a/qase-pytest/docs/CONFIGURATION.md b/qase-pytest/docs/CONFIGURATION.md index d4da1b99..aab27531 100644 --- a/qase-pytest/docs/CONFIGURATION.md +++ b/qase-pytest/docs/CONFIGURATION.md @@ -21,6 +21,9 @@ and command line options override both other values. | Root suite | `rootSuite` | `QASE_ROOT_SUITE` | `--qase-root-suite` | | No | Any string | | Debug logs | `debug` | `QASE_DEBUG` | `--qase-debug` | false | No | `true`, `false` | | Exclude parameters from test results | `excludeParams` | `QASE_EXCLUDE_PARAMS` | `--qase-exclude-params` | None, don't exclude any parameters | No | Comma-separated list of parameter names | +| **Logging configuration** | +| Enable/disable console logging output | `logging.console` | `QASE_LOGGING_CONSOLE` | `--qase-logging-console` | `true` | No | `true`, `false` | +| Enable/disable file logging output | `logging.file` | `QASE_LOGGING_FILE` | `--qase-logging-file` | `false` (true when debug=true) | No | `true`, `false` | | **Qase TestOps mode configuration** | | Qase project code | `testops.project` | `QASE_TESTOPS_PROJECT` | `--qase-testops-project` | | Yes | Any string | | Qase API token | `testops.api.token` | `QASE_TESTOPS_API_TOKEN` | `--qase-testops-api-token` | | Yes | Any string | @@ -61,6 +64,10 @@ and command line options override both other values. "fallback": "report", "debug": false, "environment": "local", + "logging": { + "console": true, + "file": false + }, "report": { "driver": "local", "connection": { diff --git a/qase-pytest/pyproject.toml b/qase-pytest/pyproject.toml index 809ea5a7..eb8831a7 100644 --- a/qase-pytest/pyproject.toml +++ b/qase-pytest/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "qase-pytest" -version = "7.0.2" +version = "7.0.3" description = "Qase Pytest Plugin for Qase TestOps and Qase Report" readme = "README.md" keywords = ["qase", "pytest", "plugin", "testops", "report", "qase reporting", "test observability"] @@ -28,7 +28,7 @@ classifiers = [ ] requires-python = ">=3.9" dependencies = [ - "qase-python-commons~=4.0.1", + "qase-python-commons~=4.1.0", "pytest>=7.4.4", "filelock~=3.12.2", "more_itertools", diff --git a/qase-pytest/src/qase/pytest/conftest.py b/qase-pytest/src/qase/pytest/conftest.py index a00f1146..efab9803 100644 --- a/qase-pytest/src/qase/pytest/conftest.py +++ b/qase-pytest/src/qase/pytest/conftest.py @@ -214,6 +214,20 @@ def setup_config_manager(config): config_manager.config.testops.run.external_link = ExternalLinkConfig() config_manager.config.testops.run.external_link.set_link(config.option.__dict__[option]) + if option == "qase_logging_console" and config.option.__dict__[option] is not None: + config_manager.config.logging.set_console(config.option.__dict__[option]) + + if option == "qase_logging_file" and config.option.__dict__[option] is not None: + config_manager.config.logging.set_file(config.option.__dict__[option]) + + # Update logger with final logging options after all CLI options are processed + from qase.commons.logger import LoggingOptions + logging_options = LoggingOptions( + console=config_manager.config.logging.console if config_manager.config.logging.console is not None else True, + file=config_manager.config.logging.file if config_manager.config.logging.file is not None else config_manager.config.debug + ) + config_manager.logger = config_manager.logger.__class__(debug=config_manager.config.debug, logging_options=logging_options) + return config_manager diff --git a/qase-pytest/src/qase/pytest/options.py b/qase-pytest/src/qase/pytest/options.py index 54891c11..c4a31f6a 100644 --- a/qase-pytest/src/qase/pytest/options.py +++ b/qase-pytest/src/qase/pytest/options.py @@ -256,6 +256,24 @@ def addoptions(parser, group): help="Define xpass status for passed tests. Default: `passed`" ) + QasePytestOptions.add_option( + parser, + group, + "--qase-logging-console", + dest="qase_logging_console", + type="bool", + help="Enable/disable console logging output" + ) + + QasePytestOptions.add_option( + parser, + group, + "--qase-logging-file", + dest="qase_logging_file", + type="bool", + help="Enable/disable file logging output" + ) + @staticmethod def add_option(parser, group, option, dest, default=None, type=None, **kwargs): # We are going to add options that were not added before through the manager diff --git a/qase-robotframework/README.md b/qase-robotframework/README.md index 5f745247..7638ed02 100644 --- a/qase-robotframework/README.md +++ b/qase-robotframework/README.md @@ -54,6 +54,10 @@ Configuration options are described in the } } }, + "logging": { + "console": true, + "file": false + }, "environment": "local" } ``` diff --git a/qase-robotframework/changelog.md b/qase-robotframework/changelog.md index 052ec9bb..6fe58232 100644 --- a/qase-robotframework/changelog.md +++ b/qase-robotframework/changelog.md @@ -1,3 +1,9 @@ +# qase-robotframework 4.0.2 + +## What's new + +- Added support for logging configuration. More information about logging configuration can be found in the [docs](../qase-python-commons/docs/LOGGING.md). + # qase-robotframework 4.0.1 ## What's new diff --git a/qase-robotframework/docs/CONFIGURATION.md b/qase-robotframework/docs/CONFIGURATION.md index 5ce340f8..a45c811d 100644 --- a/qase-robotframework/docs/CONFIGURATION.md +++ b/qase-robotframework/docs/CONFIGURATION.md @@ -17,7 +17,11 @@ Environment variables override the values given in the config file. | Execution plan path | `executionPlan.path` | `QASE_EXECUTION_PLAN_PATH` | `./build/qase-execution-plan.json` | No | Any string | | Qase environment | `environment` | `QASE_ENVIRONMENT` | `local` | No | Any string | | Root suite | `rootSuite` | `QASE_ROOT_SUITE` | | No | Any string | +| Debug logs | `debug` | `QASE_DEBUG` | `False` | No | `True`, `False` | | Exclude parameters from test results | `excludeParams` | `QASE_EXCLUDE_PARAMS` | None, don't exclude any parameters | No | Comma-separated list of parameter names | +| **Logging configuration** | +| Enable/disable console logging output | `logging.console` | `QASE_LOGGING_CONSOLE` | `true` | No | `true`, `false` | +| Enable/disable file logging output | `logging.file` | `QASE_LOGGING_FILE` | `false` (true when debug=true) | No | `true`, `false` | | **Qase TestOps mode configuration** | | Qase project code | `testops.project` | `QASE_TESTOPS_PROJECT` | | Yes | Any string | | Qase API token | `testops.api.token` | `QASE_TESTOPS_API_TOKEN` | | Yes | Any string | @@ -48,6 +52,10 @@ Environment variables override the values given in the config file. "fallback": "report", "debug": false, "environment": "local", + "logging": { + "console": true, + "file": false + }, "report": { "driver": "local", "connection": { diff --git a/qase-robotframework/pyproject.toml b/qase-robotframework/pyproject.toml index a3bdfe8b..f331b52e 100644 --- a/qase-robotframework/pyproject.toml +++ b/qase-robotframework/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "qase-robotframework" -version = "4.0.1" +version = "4.0.2" description = "Qase Robot Framework Plugin" readme = "README.md" authors = [{name = "Qase Team", email = "support@qase.io"}] @@ -24,7 +24,7 @@ classifiers = [ urls = {"Homepage" = "https://github.com/qase-tms/qase-python/tree/main/qase-robotframework"} requires-python = ">=3.9" dependencies = [ - "qase-python-commons~=4.0.1", + "qase-python-commons~=4.1.0", "filelock~=3.12.2", ] diff --git a/qase-robotframework/src/qase/robotframework/listener.py b/qase-robotframework/src/qase/robotframework/listener.py index 9568578f..4ce2482d 100644 --- a/qase-robotframework/src/qase/robotframework/listener.py +++ b/qase-robotframework/src/qase/robotframework/listener.py @@ -17,8 +17,6 @@ from .types import STATUSES from .models import * -logger = logging.getLogger("qase-robotframework") - def get_pool_id(): return BuiltIn().get_variable_value('${PABOTQUEUEINDEX}', None) @@ -41,15 +39,9 @@ def __init__(self): self.tests = {} self.pabot_index = None self.last_level_flag = None - - if config.config.debug: - logger.setLevel(logging.DEBUG) - ch = logging.StreamHandler() - formatter = logging.Formatter( - "%(asctime)s - %(name)s - %(levelname)s - %(message)s" - ) - ch.setFormatter(formatter) - logger.addHandler(ch) + + # Use centralized logger from config + self.logger = config.logger def start_suite(self, suite, result): self.pabot_index = get_pool_id() @@ -68,7 +60,7 @@ def start_suite(self, suite, result): self.__load_run_from_lock() break except RuntimeError: - logger.error("Failed to create or read lock file") + self.logger.log_error("Failed to create or read lock file") else: self.reporter.start_run() @@ -80,15 +72,15 @@ def start_suite(self, suite, result): self.tests.update(self.__extract_tests_with_suites(suite)) def start_test(self, test, result): - logger.debug("Starting test '%s'", test.name) + self.logger.log_debug(f"Starting test '{test.name}'") self.runtime.result = Result(title=test.name, signature=test.name) self.runtime.steps = {} def end_user_keyword(self, data, implementation, result): - logger.debug("Ending user keyword '%s'", data.name) + self.logger.log_debug(f"Ending user keyword '{data.name}'") - test_metadata = TagParser.parse_tags(result.tags) + test_metadata = TagParser.parse_tags(result.tags, self.logger) if test_metadata.params: # Get argument names from the implementation @@ -105,12 +97,12 @@ def end_user_keyword(self, data, implementation, result): self.runtime.result.add_field(Field(key, value)) def end_test(self, test, result): - logger.debug("Finishing test '%s'", test.name) + self.logger.log_debug(f"Finishing test '{test.name}'") - test_metadata = TagParser.parse_tags(test.tags) + test_metadata = TagParser.parse_tags(test.tags, self.logger) if test_metadata.ignore: - logger.info("Test '%s' is ignored", test.name) + self.logger.log_info(f"Test '{test.name}' is ignored") return if test_metadata.qase_ids: @@ -163,10 +155,8 @@ def end_test(self, test, result): self.reporter.add_result(self.runtime.result) - logger.info( - "Finished case result: %s, error: %s", - result.status, - hasattr(result, "message") and result.message or None, + self.logger.log_info( + f"Finished case result: {result.status}, error: {hasattr(result, 'message') and result.message or None}" ) def close(self): @@ -177,7 +167,7 @@ def close(self): self.reporter.complete_worker() if not Listener.meta_run_file.exists(): - logger.info("complete run executing") + self.logger.log_info("complete run executing") self.reporter.complete_run() def __extract_tests_with_suites(self, suite, parent_suites=None): diff --git a/qase-robotframework/src/qase/robotframework/tag_parser.py b/qase-robotframework/src/qase/robotframework/tag_parser.py index 82dc8ee2..f8967519 100644 --- a/qase-robotframework/src/qase/robotframework/tag_parser.py +++ b/qase-robotframework/src/qase/robotframework/tag_parser.py @@ -1,15 +1,12 @@ import json -import logging import re from .models import TestMetadata class TagParser: - __logger = logging.getLogger("qase-robotframework") - @staticmethod - def parse_tags(tags: list[str]) -> TestMetadata: + def parse_tags(tags: list[str], logger=None) -> TestMetadata: metadata = TestMetadata() for tag in tags: if tag.lower().startswith("q-"): @@ -21,10 +18,10 @@ def parse_tags(tags: list[str]) -> TestMetadata: metadata.ignore = True if tag.lower().startswith("qase.fields"): - metadata.fields = TagParser.__extract_fields(tag) + metadata.fields = TagParser.__extract_fields(tag, logger) if tag.lower().startswith("qase.params"): - metadata.params = TagParser.__extract_params(tag) + metadata.params = TagParser.__extract_params(tag, logger) return metadata @@ -37,16 +34,20 @@ def __extract_ids(tag: str) -> int or None: return None @staticmethod - def __extract_fields(tag: str) -> dict: + def __extract_fields(tag: str, logger=None) -> dict: value = tag.split(':', 1)[-1].strip() try: return json.loads(value) except ValueError as e: - TagParser.__logger.error(f"Error parsing fields from tag '{tag}': {e}") + # Use logger if available, otherwise fallback to print for critical errors + if logger: + logger.log_error(f"Error parsing fields from tag '{tag}': {e}") + else: + print(f"CRITICAL: Error parsing fields from tag '{tag}': {e}") return {} @staticmethod - def __extract_params(tag: str) -> list[str]: + def __extract_params(tag: str, logger=None) -> list[str]: value = tag.split(':', 1)[-1].strip() try: # Remove square brackets and split by comma @@ -57,5 +58,9 @@ def __extract_params(tag: str) -> list[str]: # Handle case without brackets return [item.strip() for item in value.split(",") if item.strip()] except (ValueError, IndexError) as e: - TagParser.__logger.error(f"Error parsing params from tag '{tag}': {e}") + # Use logger if available, otherwise fallback to print for critical errors + if logger: + logger.log_error(f"Error parsing params from tag '{tag}': {e}") + else: + print(f"CRITICAL: Error parsing params from tag '{tag}': {e}") return [] diff --git a/qase-tavern/README.md b/qase-tavern/README.md index 1e3ab766..62e45de1 100644 --- a/qase-tavern/README.md +++ b/qase-tavern/README.md @@ -90,6 +90,10 @@ Configuration options are described in the } } }, + "logging": { + "console": true, + "file": false + }, "environment": "local" } ``` diff --git a/qase-tavern/changelog.md b/qase-tavern/changelog.md index e13769b8..11bb5dbb 100644 --- a/qase-tavern/changelog.md +++ b/qase-tavern/changelog.md @@ -1,3 +1,9 @@ +# qase-tavern 2.0.2 + +## What's new + +- Added support for logging configuration. More information about logging configuration can be found in the [docs](../qase-python-commons/docs/LOGGING.md). + # qase-tavern 2.0.1 ## What's new diff --git a/qase-tavern/docs/CONFIGURATION.md b/qase-tavern/docs/CONFIGURATION.md index 0d9c8f61..554dd34a 100644 --- a/qase-tavern/docs/CONFIGURATION.md +++ b/qase-tavern/docs/CONFIGURATION.md @@ -21,6 +21,9 @@ and command line options override both other values. | Root suite | `rootSuite` | `QASE_ROOT_SUITE` | `--qase-root-suite` | | No | Any string | | Debug logs | `debug` | `QASE_DEBUG` | `--qase-debug` | false | No | `true`, `false` | | Exclude parameters from test results | `excludeParams` | `QASE_EXCLUDE_PARAMS` | `--qase-exclude-params` | None | No | Comma-separated list of parameter names | +| **Logging configuration** | +| Enable/disable console logging output | `logging.console` | `QASE_LOGGING_CONSOLE` | `--qase-logging-console` | `true` | No | `true`, `false` | +| Enable/disable file logging output | `logging.file` | `QASE_LOGGING_FILE` | `--qase-logging-file` | `false` (true when debug=true) | No | `true`, `false` | | **Qase TestOps mode configuration** | | Qase project code | `testops.project` | `QASE_TESTOPS_PROJECT` | `--qase-testops-project` | | Yes | Any string | | Qase API token | `testops.api.token` | `QASE_TESTOPS_API_TOKEN` | `--qase-testops-api-token` | | Yes | Any string | @@ -52,6 +55,10 @@ and command line options override both other values. "fallback": "report", "debug": false, "environment": "local", + "logging": { + "console": true, + "file": false + }, "report": { "driver": "local", "connection": { diff --git a/qase-tavern/pyproject.toml b/qase-tavern/pyproject.toml index fb212d66..f8628bc3 100644 --- a/qase-tavern/pyproject.toml +++ b/qase-tavern/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "qase-tavern" -version = "2.0.1" +version = "2.0.2" description = "Qase Tavern Plugin for Qase TestOps and Qase Report" readme = "README.md" keywords = ["qase", "tavern", "plugin", "testops", "report", "qase reporting", "test observability"] @@ -28,7 +28,7 @@ classifiers = [ ] requires-python = ">=3.9" dependencies = [ - "qase-python-commons~=4.0.1", + "qase-python-commons~=4.1.0", "pytest>=7,<7.3", "filelock~=3.12.2", "more_itertools", diff --git a/qase-tavern/src/qase/tavern/conftest.py b/qase-tavern/src/qase/tavern/conftest.py index 64199a91..7fc67f18 100644 --- a/qase-tavern/src/qase/tavern/conftest.py +++ b/qase-tavern/src/qase/tavern/conftest.py @@ -174,4 +174,18 @@ def setup_config_manager(config): if option == "qase_pytest_capture_logs" and config.option.__dict__[option] is not None: config_manager.config.framework.pytest.set_capture_logs(config.option.__dict__[option]) + if option == "qase_logging_console" and config.option.__dict__[option] is not None: + config_manager.config.logging.set_console(config.option.__dict__[option]) + + if option == "qase_logging_file" and config.option.__dict__[option] is not None: + config_manager.config.logging.set_file(config.option.__dict__[option]) + + # Update logger with final logging options after all CLI options are processed + from qase.commons.logger import LoggingOptions + logging_options = LoggingOptions( + console=config_manager.config.logging.console if config_manager.config.logging.console is not None else True, + file=config_manager.config.logging.file if config_manager.config.logging.file is not None else config_manager.config.debug + ) + config_manager.logger = config_manager.logger.__class__(debug=config_manager.config.debug, logging_options=logging_options) + return config_manager diff --git a/qase-tavern/src/qase/tavern/options.py b/qase-tavern/src/qase/tavern/options.py index 1115f387..5cdf75fb 100644 --- a/qase-tavern/src/qase/tavern/options.py +++ b/qase-tavern/src/qase/tavern/options.py @@ -240,6 +240,24 @@ def addoptions(parser, group): help="Capture logs from pytest" ) + QasePytestOptions.add_option( + parser, + group, + "--qase-logging-console", + dest="qase_logging_console", + type="bool", + help="Enable/disable console logging output" + ) + + QasePytestOptions.add_option( + parser, + group, + "--qase-logging-file", + dest="qase_logging_file", + type="bool", + help="Enable/disable file logging output" + ) + @staticmethod def add_option(parser, group, option, dest, default=None, type=None, **kwargs): # We are going to add options that were not added before through the manager