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 logger modules #268

Merged
merged 23 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from 17 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
11 changes: 10 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,14 @@
"python.testing.pytestArgs": ["tests"],
"python.testing.pytestEnabled": true,
"python.testing.unittestEnabled": false,
"rust-analyzer.linkedProjects": ["./src/secrets/Cargo.toml"],
"rust-analyzer.linkedProjects": [
"./src/secrets/Cargo.toml"
],
"python.analysis.extraPaths": [
"./src/core",
"./src/zos_console",
"./src/zos_files",
"./src/zos_jobs",
"./src/zosmf"
t1m0thyj marked this conversation as resolved.
Show resolved Hide resolved
],
}
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

All notable changes to the Zowe Client Python SDK will be documented in this file.

## Recent Changes

### Enhancements

- Added logger class to core SDK [#185](https://github.com/zowe/zowe-client-python-sdk/issues/185)

## `1.0.0-dev15`

### Bug Fixes
Expand Down
1 change: 1 addition & 0 deletions src/core/zowe/core_for_zowe_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
from .session import Session
from .session_constants import *
from .zosmf_profile import ZosmfProfile
from .logger import Log
39 changes: 21 additions & 18 deletions src/core/zowe/core_for_zowe_sdk/config_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import commentjson
import requests

import logging

from .credential_manager import CredentialManager
from .custom_warnings import ProfileNotFoundWarning, ProfileParsingWarning
from .exceptions import ProfileNotFound
Expand Down Expand Up @@ -71,6 +73,8 @@
jsonc: Optional[dict] = None
_missing_secure_props: list = field(default_factory=list)

__logger = logging.getLogger(__name__)

@property
def filename(self) -> str:
if self.type == TEAM_CONFIG:
Expand All @@ -92,20 +96,18 @@
def location(self) -> Optional[str]:
return self._location

@property
def schema_path(self) -> Optional[str]:
return self.schema_property

@location.setter
def location(self, dirname: str) -> None:
if os.path.isdir(dirname):
self._location = dirname
else:
self.__logger.error(f"given path {dirname} is not valid")
raise FileNotFoundError(f"given path {dirname} is not valid")

def init_from_file(
self,
validate_schema: Optional[bool] = True,
suppress_config_file_warnings: Optional[bool] = True,
) -> None:
"""
Initializes the class variable after
Expand All @@ -118,7 +120,9 @@
pass

if self.filepath is None or not os.path.isfile(self.filepath):
warnings.warn(f"Config file does not exist at {self.filepath}")
if not suppress_config_file_warnings:
t1m0thyj marked this conversation as resolved.
Show resolved Hide resolved
self.__logger.warning(f"Config file does not exist at {self.filepath}")
warnings.warn(f"Config file does not exist at {self.filepath}")

Check warning on line 125 in src/core/zowe/core_for_zowe_sdk/config_file.py

View check run for this annotation

Codecov / codecov/patch

src/core/zowe/core_for_zowe_sdk/config_file.py#L124-L125

Added lines #L124 - L125 were not covered by tests
return

with open(self.filepath, encoding="UTF-8", mode="r") as fileobj:
Expand All @@ -129,7 +133,7 @@
self.defaults = profile_jsonc.get("defaults", {})
self.jsonc = profile_jsonc

if self.schema_property and validate_schema:
if validate_schema:
self.validate_schema()

CredentialManager.load_secure_props()
Expand All @@ -143,16 +147,11 @@
-------
file_path to the $schema property
"""

path_schema_json = None

path_schema_json = self.schema_path
if path_schema_json is None: # check if the $schema property is not defined
warnings.warn(f"$schema property could not found")

# validate the $schema property
if path_schema_json:
validate_config_json(self.jsonc, path_schema_json, cwd=self.location)
if self.schema_property is None: # check if the $schema property is not defined
self.__logger.warning(f"Could not find $schema property")
warnings.warn(f"Could not find $schema property")
else:
validate_config_json(self.jsonc, self.schema_property, cwd=self.location)

def schema_list(self, cwd=None) -> list:
"""
Expand Down Expand Up @@ -213,6 +212,7 @@
self.init_from_file(validate_schema)

if profile_name is None and profile_type is None:
self.__logger.error(f"Failed to load profile '{profile_name}' because Could not find profile as both profile_name and profile_type is not set")
pem70 marked this conversation as resolved.
Show resolved Hide resolved
raise ProfileNotFound(
profile_name=profile_name,
error_msg="Could not find profile as both profile_name and profile_type is not set.",
Expand Down Expand Up @@ -250,7 +250,6 @@
break

current_dir = os.path.dirname(current_dir)

raise FileNotFoundError(f"Could not find the file {self.filename}")

def get_profilename_from_profiletype(self, profile_type: str) -> str:
Expand All @@ -268,8 +267,9 @@
try:
profilename = self.defaults[profile_type]
except KeyError:
self.__logger.warn(f"Given profile type '{profile_type}' has no default profile name")
warnings.warn(
f"Given profile type '{profile_type}' has no default profilename",
f"Given profile type '{profile_type}' has no default profile name",
ProfileParsingWarning,
)
else:
Expand All @@ -282,12 +282,14 @@
if profile_type == temp_profile_type:
return key
except KeyError:
self.__logger.warning(f"Profile '{key}' has no type attribute")
warnings.warn(
f"Profile '{key}' has no type attribute",
ProfileParsingWarning,
)

# if no profile with matching type found, we raise an exception
self.__logger.error(f"No profile with matching profile_type '{profile_type}' found")
raise ProfileNotFound(
profile_name=profile_type,
error_msg=f"No profile with matching profile_type '{profile_type}' found",
Expand Down Expand Up @@ -334,6 +336,7 @@
props = {**profile.get("properties", {}), **props}
secure_fields.extend(profile.get("secure", []))
else:
self.__logger.warning(f"Profile {profile_name} not found")
warnings.warn(f"Profile {profile_name} not found", ProfileNotFoundWarning)
lst.pop()

Expand Down
5 changes: 5 additions & 0 deletions src/core/zowe/core_for_zowe_sdk/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@

Copyright Contributors to the Zowe Project.
"""

from .exceptions import MissingConnectionArgs
import logging


class ApiConnection:
Expand All @@ -28,8 +30,11 @@ class ApiConnection:
"""

def __init__(self, host_url, user, password, ssl_verification=True):
logger = logging.getLogger(__name__)

"""Construct an ApiConnection object."""
if not host_url or not user or not password:
logger.error("Missing connection argument")
raise MissingConnectionArgs()

self.host_url = host_url
Expand Down
9 changes: 8 additions & 1 deletion src/core/zowe/core_for_zowe_sdk/credential_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@

Copyright Contributors to the Zowe Project.
"""

import base64
import sys
from typing import Optional

import commentjson

import logging

from .constants import constants
from .exceptions import SecureProfileLoadFailed

Expand All @@ -27,6 +30,7 @@

class CredentialManager:
secure_props = {}
__logger = logging.getLogger(__name__)

@staticmethod
def load_secure_props() -> None:
Expand All @@ -49,6 +53,7 @@ def load_secure_props() -> None:
return

except Exception as exc:
CredentialManager.__logger.error(f"Fail to load secure profile {constants['ZoweServiceName']}")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
CredentialManager.__logger.error(f"Fail to load secure profile {constants['ZoweServiceName']}")
CredentialManager.__logger.error(f"Failed to load secure profile {constants['ZoweServiceName']}")

raise SecureProfileLoadFailed(constants["ZoweServiceName"], error_msg=str(exc)) from exc

secure_config: str
Expand All @@ -75,7 +80,9 @@ def save_secure_props() -> None:
if sys.platform == "win32":
# Delete the existing credential
CredentialManager._delete_credential(constants["ZoweServiceName"], constants["ZoweAccountName"])
CredentialManager._set_credential(constants["ZoweServiceName"], constants["ZoweAccountName"], encoded_credential)
CredentialManager._set_credential(
constants["ZoweServiceName"], constants["ZoweAccountName"], encoded_credential
)

@staticmethod
def _get_credential(service_name: str, account_name: str) -> Optional[str]:
Expand Down
26 changes: 26 additions & 0 deletions src/core/zowe/core_for_zowe_sdk/logger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import logging
import os

class Log:
"""root logger setup and a funtion to customize logger level"""
pem70 marked this conversation as resolved.
Show resolved Hide resolved

dirname = os.path.join(os.path.expanduser("~"), ".zowe/logs")
t1m0thyj marked this conversation as resolved.
Show resolved Hide resolved

os.makedirs(dirname, exist_ok=True)

logging.basicConfig(
filename=os.path.join(dirname, "python_sdk_logs.log"),
level=logging.INFO,
format="[%(asctime)s] [%(levelname)s] [%(name)s] - %(message)s",
datefmt="%m/%d/%Y %I:%M:%S %p",
)
t1m0thyj marked this conversation as resolved.
Show resolved Hide resolved

loggers = []
@staticmethod
def registerLogger(name: str):
Log.loggers.append(logging.getLogger(name))

@staticmethod
def setLoggerLevel(level: int):
for logger in Log.loggers:
logger.setLevel(level)
27 changes: 25 additions & 2 deletions src/core/zowe/core_for_zowe_sdk/profile_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
import warnings
from copy import deepcopy
from typing import Optional
import logging

import jsonschema
from deepmerge import always_merger

from .config_file import ConfigFile, Profile
from .logger import Log
from .credential_manager import CredentialManager
from .custom_warnings import (
ConfigNotFoundWarning,
Expand Down Expand Up @@ -57,10 +59,14 @@
self.project_config = ConfigFile(type=TEAM_CONFIG, name=appname)
self.project_user_config = ConfigFile(type=USER_CONFIG, name=appname)

self.__logger = logging.getLogger(__name__)
Log.registerLogger(__name__)

self.global_config = ConfigFile(type=TEAM_CONFIG, name=GLOBAL_CONFIG_NAME)
try:
self.global_config.location = GLOBAL_CONFIG_LOCATION
except Exception:
self.__logger.warning("Could not find Global Config Directory")
warnings.warn(
"Could not find Global Config Directory, please provide one.",
ConfigNotFoundWarning,
Expand All @@ -70,6 +76,7 @@
try:
self.global_user_config.location = GLOBAL_CONFIG_LOCATION
except Exception:
self.__logger.warning("Could not find Global User Config Directory")
warnings.warn(
"Could not find Global User Config Directory, please provide one.",
ConfigNotFoundWarning,
Expand Down Expand Up @@ -172,38 +179,48 @@
NamedTuple (data, name, secure_props_not_found)
"""

logger = logging.getLogger(__name__)

cfg_profile = Profile()
try:
cfg_profile = cfg.get_profile(
profile_name=profile_name, profile_type=profile_type, validate_schema=validate_schema
)
except jsonschema.exceptions.ValidationError as exc:
logger.error(f"Instance was invalid under the provided $schema property, {exc}")

Check warning on line 190 in src/core/zowe/core_for_zowe_sdk/profile_manager.py

View check run for this annotation

Codecov / codecov/patch

src/core/zowe/core_for_zowe_sdk/profile_manager.py#L190

Added line #L190 was not covered by tests
raise jsonschema.exceptions.ValidationError(
f"Instance was invalid under the provided $schema property, {exc}"
)
except jsonschema.exceptions.SchemaError as exc:
logger.error(f"The provided schema is invalid, {exc}")

Check warning on line 195 in src/core/zowe/core_for_zowe_sdk/profile_manager.py

View check run for this annotation

Codecov / codecov/patch

src/core/zowe/core_for_zowe_sdk/profile_manager.py#L195

Added line #L195 was not covered by tests
raise jsonschema.exceptions.SchemaError(f"The provided schema is invalid, {exc}")
except jsonschema.exceptions.UndefinedTypeCheck as exc:
logger.error(f"A type checker was asked to check a type it did not have registered, {exc}")

Check warning on line 198 in src/core/zowe/core_for_zowe_sdk/profile_manager.py

View check run for this annotation

Codecov / codecov/patch

src/core/zowe/core_for_zowe_sdk/profile_manager.py#L198

Added line #L198 was not covered by tests
raise jsonschema.exceptions.UndefinedTypeCheck(
f"A type checker was asked to check a type it did not have registered, {exc}"
)
except jsonschema.exceptions.UnknownType as exc:
logger.error(f"Unknown type is found in schema_json, exc")

Check warning on line 203 in src/core/zowe/core_for_zowe_sdk/profile_manager.py

View check run for this annotation

Codecov / codecov/patch

src/core/zowe/core_for_zowe_sdk/profile_manager.py#L203

Added line #L203 was not covered by tests
pem70 marked this conversation as resolved.
Show resolved Hide resolved
raise jsonschema.exceptions.UnknownType(f"Unknown type is found in schema_json, exc")
except jsonschema.exceptions.FormatError as exc:
logger.error(f"Validating a format config_json failed for schema_json, {exc}")

Check warning on line 206 in src/core/zowe/core_for_zowe_sdk/profile_manager.py

View check run for this annotation

Codecov / codecov/patch

src/core/zowe/core_for_zowe_sdk/profile_manager.py#L206

Added line #L206 was not covered by tests
raise jsonschema.exceptions.FormatError(f"Validating a format config_json failed for schema_json, {exc}")
except ProfileNotFound:
if profile_name:
logger.warning(f"Profile '{profile_name}' not found in file '{cfg.filename}'")

Check warning on line 210 in src/core/zowe/core_for_zowe_sdk/profile_manager.py

View check run for this annotation

Codecov / codecov/patch

src/core/zowe/core_for_zowe_sdk/profile_manager.py#L210

Added line #L210 was not covered by tests
warnings.warn(
f"Profile '{profile_name}' not found in file '{cfg.filename}', returning empty profile instead.",
ProfileNotFoundWarning,
)
else:
logger.warning(f"Profile of type '{profile_type}' not found in file '{cfg.filename}'")

Check warning on line 216 in src/core/zowe/core_for_zowe_sdk/profile_manager.py

View check run for this annotation

Codecov / codecov/patch

src/core/zowe/core_for_zowe_sdk/profile_manager.py#L216

Added line #L216 was not covered by tests
warnings.warn(
f"Profile of type '{profile_type}' not found in file '{cfg.filename}', returning empty profile"
f" instead.",
ProfileNotFoundWarning,
)
except Exception as exc:
logger.warning(f"Could not load '{cfg.filename}' at '{cfg.filepath}'" f"because {type(exc).__name__}'{exc}'")

Check warning on line 223 in src/core/zowe/core_for_zowe_sdk/profile_manager.py

View check run for this annotation

Codecov / codecov/patch

src/core/zowe/core_for_zowe_sdk/profile_manager.py#L223

Added line #L223 was not covered by tests
warnings.warn(
f"Could not load '{cfg.filename}' at '{cfg.filepath}'" f"because {type(exc).__name__}'{exc}'.",
ConfigNotFoundWarning,
Expand All @@ -218,6 +235,7 @@
check_missing_props: bool = True,
validate_schema: Optional[bool] = True,
override_with_env: Optional[bool] = False,
suppress_config_file_warnings: Optional[bool] = True,
) -> dict:
"""Load connection details from a team config profile.
Returns
Expand All @@ -236,7 +254,9 @@
If `profile_type` is not base, then we will load properties from both
`profile_type` and base profiles and merge them together.
"""

if profile_name is None and profile_type is None:
self.__logger.error(f"Failed to load profile as both profile_name and profile_type are not set")

Check warning on line 259 in src/core/zowe/core_for_zowe_sdk/profile_manager.py

View check run for this annotation

Codecov / codecov/patch

src/core/zowe/core_for_zowe_sdk/profile_manager.py#L259

Added line #L259 was not covered by tests
raise ProfileNotFound(
profile_name=profile_name,
error_msg="Could not find profile as both profile_name and profile_type is not set.",
Expand All @@ -254,12 +274,13 @@
cfg_name = None
cfg_schema = None
cfg_schema_dir = None

for cfg_layer in (self.project_user_config, self.project_config, self.global_user_config, self.global_config):
if cfg_layer.profiles is None:
try:
cfg_layer.init_from_file(validate_schema)
cfg_layer.init_from_file(validate_schema, suppress_config_file_warnings)
except SecureProfileLoadFailed:
self.__logger.warning(f"Could not load secure properties for {cfg_layer.filepath}")
warnings.warn(
f"Could not load secure properties for {cfg_layer.filepath}",
SecurePropsNotFoundWarning,
Expand Down Expand Up @@ -314,6 +335,7 @@
missing_props.add(item)

if len(missing_props) > 0:
self.__logger.error(f"Failed to load secure values: {missing_props}")

Check warning on line 338 in src/core/zowe/core_for_zowe_sdk/profile_manager.py

View check run for this annotation

Codecov / codecov/patch

src/core/zowe/core_for_zowe_sdk/profile_manager.py#L338

Added line #L338 was not covered by tests
raise SecureValuesNotFound(values=missing_props)

warnings.resetwarnings()
Expand Down Expand Up @@ -366,6 +388,7 @@
highest_layer = layer

if highest_layer is None:
self.__logger.error(f"Could not find a valid layer for {json_path}")

Check warning on line 391 in src/core/zowe/core_for_zowe_sdk/profile_manager.py

View check run for this annotation

Codecov / codecov/patch

src/core/zowe/core_for_zowe_sdk/profile_manager.py#L391

Added line #L391 was not covered by tests
raise FileNotFoundError(f"Could not find a valid layer for {json_path}")

return highest_layer
Expand Down
Loading
Loading