engforge 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- engforge/__init__.py +26 -0
- engforge/_testing_components.py +864 -0
- engforge/analysis.py +257 -0
- engforge/attr_dynamics.py +222 -0
- engforge/attr_plotting.py +811 -0
- engforge/attr_signals.py +116 -0
- engforge/attr_slots.py +211 -0
- engforge/attr_solver.py +443 -0
- engforge/attributes.py +326 -0
- engforge/common.py +76 -0
- engforge/component_collections.py +276 -0
- engforge/components.py +55 -0
- engforge/configuration.py +673 -0
- engforge/dataframe.py +185 -0
- engforge/datastores/__init__.py +116 -0
- engforge/datastores/data.py +519 -0
- engforge/datastores/gdocs.py +2650 -0
- engforge/datastores/reporting.py +935 -0
- engforge/datastores/secrets.py +549 -0
- engforge/dynamics.py +662 -0
- engforge/eng/__init__.py +0 -0
- engforge/eng/costs.py +1459 -0
- engforge/eng/fluid_material.py +279 -0
- engforge/eng/geometry.py +1060 -0
- engforge/eng/pipes.py +1211 -0
- engforge/eng/prediction.py +366 -0
- engforge/eng/solid_materials.py +445 -0
- engforge/eng/structure.py +2228 -0
- engforge/eng/structure_beams.py +821 -0
- engforge/eng/thermodynamics.py +271 -0
- engforge/engforge_attributes.py +380 -0
- engforge/env_var.py +214 -0
- engforge/locations.py +18 -0
- engforge/logging.py +290 -0
- engforge/patterns.py +449 -0
- engforge/problem_context.py +2251 -0
- engforge/properties.py +501 -0
- engforge/reporting.py +595 -0
- engforge/solveable.py +964 -0
- engforge/solver.py +316 -0
- engforge/solver_utils.py +726 -0
- engforge/system.py +143 -0
- engforge/system_reference.py +299 -0
- engforge/tabulation.py +288 -0
- engforge/test/__init__.py +2 -0
- engforge/test/_pre_test_structures.py +221 -0
- engforge/test/report_testing.py +158 -0
- engforge/test/test_airfilter.py +91 -0
- engforge/test/test_analysis.py +3 -0
- engforge/test/test_comp_iter.py +196 -0
- engforge/test/test_composition.py +139 -0
- engforge/test/test_costs.py +338 -0
- engforge/test/test_dynamics.py +109 -0
- engforge/test/test_dynamics_spaces.py +39 -0
- engforge/test/test_four_bar.py +97 -0
- engforge/test/test_modules.py +72 -0
- engforge/test/test_performance.py +93 -0
- engforge/test/test_pipes.py +49 -0
- engforge/test/test_problem.py +411 -0
- engforge/test/test_problem_deepscoping.py +68 -0
- engforge/test/test_slider_crank.py +51 -0
- engforge/test/test_solver.py +343 -0
- engforge/test/test_tabulation.py +233 -0
- engforge/typing.py +92 -0
- engforge-0.3.0.dist-info/METADATA +392 -0
- engforge-0.3.0.dist-info/RECORD +69 -0
- engforge-0.3.0.dist-info/WHEEL +5 -0
- engforge-0.3.0.dist-info/licenses/LICENSE +7 -0
- engforge-0.3.0.dist-info/top_level.txt +1 -0
engforge/env_var.py
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"""Defines a class called `EnvVariable` that defines an interface for env variables with an option to obscure and convert variables, as well as provide a default option.
|
|
2
|
+
|
|
3
|
+
A global record of variables is kept for informational purposes in keeping track of progam variables
|
|
4
|
+
|
|
5
|
+
To prevent storage of env vars in program memory, access to the os env variables is provided on access of the `secret` variable. It is advisable to use the result of this as directly as possible when dealing with actual secrets.
|
|
6
|
+
|
|
7
|
+
For example add: `db_driver(DB_HOST.secret,DB_PASSWORD.secret,...)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
from engforge.logging import LoggingMixin
|
|
12
|
+
from typing import Any
|
|
13
|
+
import socket
|
|
14
|
+
import inspect
|
|
15
|
+
|
|
16
|
+
global warned
|
|
17
|
+
warned = set() # a nice global variable to hold any warnings
|
|
18
|
+
|
|
19
|
+
FALSE_VALUES = (False, "false", "no", "n")
|
|
20
|
+
TRUE_VALUES = (True, "checked", "true", "yes", "y")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def parse_bool(input: str):
|
|
24
|
+
if isinstance(input, str):
|
|
25
|
+
input = input.lower()
|
|
26
|
+
|
|
27
|
+
if not input:
|
|
28
|
+
return False
|
|
29
|
+
elif input in TRUE_VALUES:
|
|
30
|
+
return True
|
|
31
|
+
elif input in FALSE_VALUES:
|
|
32
|
+
return False
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
DEFAULT_CONVERTERS = {bool: parse_bool}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class EnvVariable(LoggingMixin):
|
|
40
|
+
"""A method to wrap SECRETS and in application with a way to get the value using self.secret
|
|
41
|
+
Do not store values from self.secret to ensure security
|
|
42
|
+
|
|
43
|
+
You can override the secret with _override"""
|
|
44
|
+
|
|
45
|
+
var_name: str = None
|
|
46
|
+
type_conv: Any = None
|
|
47
|
+
default: Any = None
|
|
48
|
+
obscure: bool = True
|
|
49
|
+
_override: str
|
|
50
|
+
_secrets = {} # its class based so like a singleton
|
|
51
|
+
_replaced = set()
|
|
52
|
+
fail_on_missing: bool
|
|
53
|
+
desc: str = None
|
|
54
|
+
_upgrd_warn: bool = False
|
|
55
|
+
_dontovrride: bool = False
|
|
56
|
+
|
|
57
|
+
def __init__(
|
|
58
|
+
self,
|
|
59
|
+
secret_var_name,
|
|
60
|
+
type_conv=None,
|
|
61
|
+
default=None,
|
|
62
|
+
obscure=False,
|
|
63
|
+
fail_on_missing=False,
|
|
64
|
+
desc: str = None,
|
|
65
|
+
dontovrride=False,
|
|
66
|
+
):
|
|
67
|
+
"""pass arguments to SecretVariable to have it look up information at runtime from envargs, but not store it in memory.
|
|
68
|
+
:param secret_var_name: the enviornmental variable
|
|
69
|
+
:param type_conv: the data from env vars will be converted with this function
|
|
70
|
+
:param default: the value to use if the secret_var_name doesn't exist in enviornmental variables
|
|
71
|
+
:param obscure: default True, will prevent the result being printed by str(self)
|
|
72
|
+
:param fail_on_missing: if the secret env variable is not found, and default is None
|
|
73
|
+
:param desc: a description of the purpose of the variable
|
|
74
|
+
"""
|
|
75
|
+
self.var_name = secret_var_name
|
|
76
|
+
self.type_conv = (
|
|
77
|
+
type_conv
|
|
78
|
+
if type_conv not in DEFAULT_CONVERTERS
|
|
79
|
+
else DEFAULT_CONVERTERS[type_conv]
|
|
80
|
+
)
|
|
81
|
+
self._dontovrride = dontovrride
|
|
82
|
+
|
|
83
|
+
if default is not None:
|
|
84
|
+
self.default = default
|
|
85
|
+
self.obscure = obscure
|
|
86
|
+
# UserString.__init__(self,f'[SECRET:{secret_var_name}]')
|
|
87
|
+
|
|
88
|
+
self.fail_on_missing = fail_on_missing
|
|
89
|
+
|
|
90
|
+
# record env vars
|
|
91
|
+
if secret_var_name in self.__class__._secrets:
|
|
92
|
+
cur = self.__class__._secrets[secret_var_name]
|
|
93
|
+
if dontovrride:
|
|
94
|
+
self.debug(f"not replacing: {cur}->{self}")
|
|
95
|
+
self.__dict__ = cur.__dict__
|
|
96
|
+
else:
|
|
97
|
+
self.info(f"replacing {cur}->{self}")
|
|
98
|
+
self._replaced.add(cur)
|
|
99
|
+
self.__class__._secrets[secret_var_name] = self
|
|
100
|
+
else:
|
|
101
|
+
self.__class__._secrets[secret_var_name] = self
|
|
102
|
+
|
|
103
|
+
# FIXME: prevent engforge var from replacing other module instnace
|
|
104
|
+
# not possible to locate where other instances
|
|
105
|
+
# if secret_var_name in self.__class__._secrets:
|
|
106
|
+
# cur = self.__class__._secrets[secret_var_name]
|
|
107
|
+
# if cur != self and self not in self._replaced:
|
|
108
|
+
# self._replaced.add(cur)
|
|
109
|
+
# self.info(f'replacing {cur}->{self}')
|
|
110
|
+
# self.__class__._secrets[secret_var_name] = self
|
|
111
|
+
# elif self in self._replaced:
|
|
112
|
+
# self.info(f'skipping replaced readd {self}')
|
|
113
|
+
# #self.__class__._secrets[secret_var_name] = self
|
|
114
|
+
# else:
|
|
115
|
+
# self.__class__._secrets[secret_var_name] = self
|
|
116
|
+
|
|
117
|
+
def __str__(self):
|
|
118
|
+
if self.obscure:
|
|
119
|
+
return f"{self.obscured_name:<40} = XXXXXX"
|
|
120
|
+
return f"{self.obscured_name:<40} = {self.secret}"
|
|
121
|
+
|
|
122
|
+
def __add__(self, other) -> str:
|
|
123
|
+
return str(str.__add__(str(self), other))
|
|
124
|
+
|
|
125
|
+
def __radd__(self, other) -> str:
|
|
126
|
+
return str(str.__add__(other, str(self)))
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def obscured_name(self) -> str:
|
|
130
|
+
if hasattr(self, "_override"):
|
|
131
|
+
return f"SECRETS[OVERRIDE]"
|
|
132
|
+
return f"SECRETS[{self.var_name}]"
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def secret(self):
|
|
136
|
+
# Check if this secret is the one in the secrets registry
|
|
137
|
+
sec = self.__class__._secrets[self.var_name]
|
|
138
|
+
if sec is not self and not sec._dontovrride:
|
|
139
|
+
# Provide warning that the secret is being replaced
|
|
140
|
+
if not self._upgrd_warn:
|
|
141
|
+
self._upgrd_warn = True
|
|
142
|
+
self.info(f"upgrading: {self.var_name} from {id(self)}->{id(sec)}")
|
|
143
|
+
|
|
144
|
+
# Monkeypatch dictionary
|
|
145
|
+
self.__dict__ = sec.__dict__
|
|
146
|
+
|
|
147
|
+
if hasattr(self, "_override"):
|
|
148
|
+
return self._override
|
|
149
|
+
|
|
150
|
+
if self.var_name in os.environ:
|
|
151
|
+
secval = os.environ[self.var_name]
|
|
152
|
+
elif self.default is not None:
|
|
153
|
+
if self.var_name not in warned:
|
|
154
|
+
if self.obscure:
|
|
155
|
+
dflt = "XXXXXXX"
|
|
156
|
+
else:
|
|
157
|
+
dflt = self.default
|
|
158
|
+
|
|
159
|
+
self.debug(f"Env Var: {self.var_name} Not Found! Using: {dflt}")
|
|
160
|
+
warned.add(self.var_name)
|
|
161
|
+
|
|
162
|
+
secval = self.default
|
|
163
|
+
else:
|
|
164
|
+
if self.fail_on_missing:
|
|
165
|
+
raise FileNotFoundError(f"Could Not Find Env Variable {self.var_name}")
|
|
166
|
+
else:
|
|
167
|
+
if self.var_name not in warned:
|
|
168
|
+
self.debug(f"Env Var: {self.var_name} Not Found!")
|
|
169
|
+
warned.add(self.var_name)
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
if self.type_conv is None:
|
|
173
|
+
return secval
|
|
174
|
+
else:
|
|
175
|
+
return self.type_conv(secval)
|
|
176
|
+
|
|
177
|
+
@property
|
|
178
|
+
def in_env(self):
|
|
179
|
+
return self.var_name in os.environ
|
|
180
|
+
|
|
181
|
+
def remove(self):
|
|
182
|
+
"""removes this secret from the record"""
|
|
183
|
+
if self in self.__class__._secrets:
|
|
184
|
+
self.__class__._secrets.remove(self)
|
|
185
|
+
|
|
186
|
+
@classmethod
|
|
187
|
+
def load_env_vars(self):
|
|
188
|
+
for s in EnvVariable._secrets.values():
|
|
189
|
+
str(s)
|
|
190
|
+
|
|
191
|
+
@classmethod
|
|
192
|
+
def print_env_vars(cls):
|
|
193
|
+
"""prints env vars in memory"""
|
|
194
|
+
# preload
|
|
195
|
+
cls.load_env_vars()
|
|
196
|
+
for var, s in sorted(
|
|
197
|
+
EnvVariable._secrets.items(), key=lambda kv: kv[1].var_name
|
|
198
|
+
):
|
|
199
|
+
print(f"{s.var_name:<40}|{s}")
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
# DEFAULT ENV VARIABLES
|
|
203
|
+
try:
|
|
204
|
+
# This should always work unless we don't have privideges (rare assumed)
|
|
205
|
+
host = socket.gethostname().upper()
|
|
206
|
+
except:
|
|
207
|
+
host = "MASTER"
|
|
208
|
+
|
|
209
|
+
global HOSTNAME, SLACK_WEBHOOK
|
|
210
|
+
|
|
211
|
+
HOSTNAME = EnvVariable("FORGE_HOSTNAME", default=host, obscure=False, dontovrride=True)
|
|
212
|
+
SLACK_WEBHOOK = EnvVariable(
|
|
213
|
+
"FORGE_SLACK_LOG_WEBHOOK", default=None, obscure=False, dontovrride=True
|
|
214
|
+
)
|
engforge/locations.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from engforge.env_var import EnvVariable
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
FORGE_ROOT_VAR = EnvVariable(
|
|
5
|
+
"FORGE_ROOT", default=None, dontovrride=True, type_conv=os.path.expanduser
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def client_path(alternate_path=None, **kw):
|
|
10
|
+
path = FORGE_ROOT_VAR.secret
|
|
11
|
+
if path is None:
|
|
12
|
+
if alternate_path is None:
|
|
13
|
+
raise KeyError(
|
|
14
|
+
f"no `FORGE_ROOT` set and no alternate path in client_path call"
|
|
15
|
+
)
|
|
16
|
+
return alternate_path
|
|
17
|
+
else:
|
|
18
|
+
return path
|
engforge/logging.py
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import logging
|
|
3
|
+
import traceback
|
|
4
|
+
import sys, os
|
|
5
|
+
from pyee import EventEmitter
|
|
6
|
+
from termcolor import colored
|
|
7
|
+
import requests
|
|
8
|
+
import json
|
|
9
|
+
import uuid
|
|
10
|
+
|
|
11
|
+
global log_change_emitter
|
|
12
|
+
log_change_emitter = EventEmitter()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
BASIC_LOG_FMT = "[%(name)-24s]%(message)s"
|
|
16
|
+
|
|
17
|
+
global LOG_LEVEL
|
|
18
|
+
LOG_LEVEL = logging.INFO
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def change_all_log_levels(new_log_level: int = 20, inst=None, check_function=None):
|
|
22
|
+
"""Changes All Log Levels With pyee broadcast before reactor is running
|
|
23
|
+
:param new_log_level: int - changes unit level log level (10-msg,20-debug,30-info,40-warning,50-error,60-crit)
|
|
24
|
+
:param check_function: callable -> bool - (optional) if provided if check_function(unit) is true then the new_log_level is applied
|
|
25
|
+
"""
|
|
26
|
+
if isinstance(new_log_level, float):
|
|
27
|
+
new_log_level = int(new_log_level) # Float Case Is Handled
|
|
28
|
+
|
|
29
|
+
assert (
|
|
30
|
+
isinstance(new_log_level, int) and new_log_level >= 1 and new_log_level <= 100
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
global LOG_LEVEL
|
|
34
|
+
LOG_LEVEL = new_log_level
|
|
35
|
+
|
|
36
|
+
if LoggingMixin.log_level != new_log_level:
|
|
37
|
+
print(f"changing log levels to {new_log_level}...")
|
|
38
|
+
log.info(f"Changing All Logging Units To Level {new_log_level}")
|
|
39
|
+
log_change_emitter.emit("change_level", new_log_level, check_function)
|
|
40
|
+
LoggingMixin.log_level = new_log_level
|
|
41
|
+
if inst:
|
|
42
|
+
inst.log_level = new_log_level
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class LoggingMixin(logging.Filter):
|
|
46
|
+
"""Class to include easy formatting in subclasses"""
|
|
47
|
+
|
|
48
|
+
log_level = LOG_LEVEL
|
|
49
|
+
_log = None
|
|
50
|
+
|
|
51
|
+
log_on = True
|
|
52
|
+
|
|
53
|
+
log_fmt = "[%(name)-24s]%(message)s"
|
|
54
|
+
|
|
55
|
+
slack_webhook_url = None
|
|
56
|
+
# log_silo = False
|
|
57
|
+
|
|
58
|
+
change_all_log_lvl = lambda s, *a, **kw: change_all_log_levels(*a, inst=s, **kw)
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def logger(self):
|
|
62
|
+
global LOG_LEVEL
|
|
63
|
+
if self._log is None:
|
|
64
|
+
inst_log_name = "engforgelog_" + self.identity + "_" + str(uuid.uuid4())
|
|
65
|
+
self._log = logging.getLogger(inst_log_name)
|
|
66
|
+
self._log.setLevel(level=LOG_LEVEL)
|
|
67
|
+
|
|
68
|
+
# Apply Filter Info
|
|
69
|
+
self._log.addFilter(self)
|
|
70
|
+
self.installSTDLogger()
|
|
71
|
+
from engforge.env_var import EnvVariable, SLACK_WEBHOOK
|
|
72
|
+
|
|
73
|
+
# Hot Patch Class (EnvVar is logging mixin... soo... here we are)
|
|
74
|
+
if LoggingMixin.slack_webhook_url is None:
|
|
75
|
+
# Do this on the fly since we SecretVariable is a log component
|
|
76
|
+
LoggingMixin.slack_webhook_url = SLACK_WEBHOOK
|
|
77
|
+
|
|
78
|
+
if not hasattr(self, "_f_change_log"):
|
|
79
|
+
# change log level listener
|
|
80
|
+
def _change_log(new_level, check_function=None):
|
|
81
|
+
if new_level != self.log_level:
|
|
82
|
+
if check_function is None or check_function(self):
|
|
83
|
+
msg = f"changing {self.identity} log level: {self.log_level} -> {new_level}"
|
|
84
|
+
self.__class__.log_level = new_level
|
|
85
|
+
self.info(msg)
|
|
86
|
+
self._log.setLevel(new_level)
|
|
87
|
+
self.log_level = new_level
|
|
88
|
+
self.resetLog()
|
|
89
|
+
|
|
90
|
+
# our emitter gets set with a callback
|
|
91
|
+
log_change_emitter.add_listener("change_level", _change_log)
|
|
92
|
+
|
|
93
|
+
self._f_change_log = _change_log
|
|
94
|
+
|
|
95
|
+
return self._log
|
|
96
|
+
|
|
97
|
+
def resetLog(self):
|
|
98
|
+
"""reset log"""
|
|
99
|
+
self._log = None
|
|
100
|
+
self.debug(f"reset!")
|
|
101
|
+
|
|
102
|
+
def resetSystemLogs(self, reseted=None):
|
|
103
|
+
"""resets log on all internal instance LoggingMixins"""
|
|
104
|
+
self.resetLog()
|
|
105
|
+
self.debug(f"reset!")
|
|
106
|
+
if reseted is None:
|
|
107
|
+
reseted = set()
|
|
108
|
+
for k, v in self.__dict__.items():
|
|
109
|
+
if isinstance(v, LoggingMixin) and id(v) not in reseted:
|
|
110
|
+
reseted.add(id(v))
|
|
111
|
+
v.resetSystemLogs(reseted)
|
|
112
|
+
|
|
113
|
+
def installSTDLogger(self):
|
|
114
|
+
"""We only want std logging to start"""
|
|
115
|
+
sh = logging.StreamHandler(sys.stdout)
|
|
116
|
+
peerlog = logging.Formatter(self.log_fmt)
|
|
117
|
+
sh.setFormatter(peerlog)
|
|
118
|
+
self._log.addHandler(sh)
|
|
119
|
+
|
|
120
|
+
def add_fields(self, record):
|
|
121
|
+
"""Overwrite this to modify logging fields"""
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
def filter(self, record):
|
|
125
|
+
"""This acts as the interface for `logging.Filter`
|
|
126
|
+
Don't overwrite this, use `add_fields` instead."""
|
|
127
|
+
record.name = self.identity.lower()[:24]
|
|
128
|
+
self.add_fields(record)
|
|
129
|
+
return True
|
|
130
|
+
|
|
131
|
+
def msg(self, *args, lvl=5):
|
|
132
|
+
"""Writes to log... this should be for raw data or something... least priorty"""
|
|
133
|
+
if self.log_on:
|
|
134
|
+
self.logger.log(
|
|
135
|
+
lvl,
|
|
136
|
+
self.message_with_identiy(self.extract_message(args), "blue"),
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
def debug(self, *args):
|
|
140
|
+
"""Writes at a low level to the log file... usually this should
|
|
141
|
+
be detailed messages about what exactly is going on"""
|
|
142
|
+
if self.log_on:
|
|
143
|
+
self.logger.debug(
|
|
144
|
+
self.message_with_identiy(self.extract_message(args), "cyan")
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
def info(self, *args):
|
|
148
|
+
"""Writes to log but with info category, these are important typically
|
|
149
|
+
and inform about progress of process in general"""
|
|
150
|
+
if self.log_on:
|
|
151
|
+
self.logger.info(
|
|
152
|
+
self.message_with_identiy(self.extract_message(args), "white")
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
def warning(self, *args):
|
|
156
|
+
"""Writes to log as a warning"""
|
|
157
|
+
self.logger.warning(
|
|
158
|
+
self.message_with_identiy("WARN: " + self.extract_message(args), "yellow")
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
def error(self, error, msg=""):
|
|
162
|
+
"""Writes to log as a error"""
|
|
163
|
+
|
|
164
|
+
# fmt = 'ERROR: {msg!r}|{err!r}'
|
|
165
|
+
|
|
166
|
+
tb = error.__traceback__
|
|
167
|
+
fmt = "ERROR:{msg}->{err}"
|
|
168
|
+
|
|
169
|
+
tb = "\n".join(traceback.format_exception(error, value=error, tb=tb))
|
|
170
|
+
msgfmt = ("\n" + " " * 51 + "|").join(str(msg).split("\n"))
|
|
171
|
+
|
|
172
|
+
# tbcl = colored(tb, "red")
|
|
173
|
+
# self.logger.exception( fmt.format(msg=msgfmt,err=tbcl))
|
|
174
|
+
# self.logger.exception( msgfmt)
|
|
175
|
+
|
|
176
|
+
m = colored(fmt.format(msg=msgfmt, err=tb), "red")
|
|
177
|
+
self.logger.error(m)
|
|
178
|
+
|
|
179
|
+
def critical(self, *args):
|
|
180
|
+
"""A routine to communicate to the root of the server network that there is an issue"""
|
|
181
|
+
msg = self.extract_message(args)
|
|
182
|
+
msg = self.message_with_identiy(msg, "magenta")
|
|
183
|
+
self.logger.critical(msg)
|
|
184
|
+
|
|
185
|
+
# FIXME: setup slack notificatinos with env var
|
|
186
|
+
self.slack_notification(self.identity.title(), msg)
|
|
187
|
+
|
|
188
|
+
def slack_notification(self, category, message):
|
|
189
|
+
from engforge.env_var import SLACK_WEBHOOK, HOSTNAME
|
|
190
|
+
|
|
191
|
+
if SLACK_WEBHOOK.var_name in os.environ:
|
|
192
|
+
self.info("getting slack webhook")
|
|
193
|
+
url = SLACK_WEBHOOK.secret
|
|
194
|
+
else:
|
|
195
|
+
return
|
|
196
|
+
stage = HOSTNAME.secret
|
|
197
|
+
headers = {"Content-type": "application/json"}
|
|
198
|
+
data = {
|
|
199
|
+
"text": "{category} on {stage}:\n```{message}```".format(
|
|
200
|
+
category=category.upper(), stage=stage, message=message
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
self.info(f"Slack Notification : {url}:{category},{message}")
|
|
204
|
+
slack_note = requests.post(
|
|
205
|
+
url, data=json.dumps(data).encode("ascii"), headers=headers
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
def message_with_identiy(self, message: str, color=None):
|
|
209
|
+
"""converts to color and string via the termcolor library
|
|
210
|
+
:param message: a string convertable entity
|
|
211
|
+
:param color: a color in [grey,red,green,yellow,blue,magenta,cyan,white]
|
|
212
|
+
"""
|
|
213
|
+
if color != None:
|
|
214
|
+
return colored(str(message), color)
|
|
215
|
+
return str(message)
|
|
216
|
+
|
|
217
|
+
def extract_message(self, args):
|
|
218
|
+
for arg in args:
|
|
219
|
+
if type(arg) is str:
|
|
220
|
+
return arg
|
|
221
|
+
if self.log_level < 0:
|
|
222
|
+
print(f"no string found for {args}")
|
|
223
|
+
return ""
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def identity(self):
|
|
227
|
+
return type(self).__name__
|
|
228
|
+
|
|
229
|
+
def __getstate__(self):
|
|
230
|
+
d = dict(self.__dict__)
|
|
231
|
+
d["_f_change_log"] = None
|
|
232
|
+
return d
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class Log(LoggingMixin):
|
|
236
|
+
pass
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
log = Log()
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
# try:
|
|
243
|
+
# logging.getLogger('parso.cache').disabled=True
|
|
244
|
+
# logging.getLogger('parso.cache.pickle').disabled=True
|
|
245
|
+
# logging.getLogger('parso.python.diff').disabled=True
|
|
246
|
+
#
|
|
247
|
+
# except Exception as e:
|
|
248
|
+
# log.warning(f'could not diable parso {e}')
|
|
249
|
+
# def installGELFLogger():
|
|
250
|
+
# '''Installs GELF Logger'''
|
|
251
|
+
# # self.gelf = graypy.GELFTLSHandler(GELF_HOST,GELF_PORT, validate=True,\
|
|
252
|
+
# # ca_certs=credfile('graylog-clients-ca.crt'),\
|
|
253
|
+
# # certfile = credfile('test-client.crt'),
|
|
254
|
+
# # keyfile = credfile('test-client.key')
|
|
255
|
+
# # )
|
|
256
|
+
# log = logging.getLogger('')
|
|
257
|
+
# gelf = graypy.GELFUDPHandler(host=GELF_HOST,port=12203, extra_fields=True)
|
|
258
|
+
# log.addHandler(gelf)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
# def installSTDLogger(fmt = BASIC_LOG_FMT):
|
|
262
|
+
# '''We only want std logging to start'''
|
|
263
|
+
# log = logging.getLogger('')
|
|
264
|
+
# sh = logging.StreamHandler(sys.stdout)
|
|
265
|
+
# peerlog = logging.Formatter()
|
|
266
|
+
# sh.setFormatter(peerlog)
|
|
267
|
+
# log.addHandler( sh )
|
|
268
|
+
#
|
|
269
|
+
#
|
|
270
|
+
# def set_all_loggers_to(level,set_stdout=False,all_loggers=False):
|
|
271
|
+
# global LOG_LEVEL
|
|
272
|
+
# LOG_LEVEL = level
|
|
273
|
+
#
|
|
274
|
+
# if set_stdout: installSTDLogger()
|
|
275
|
+
#
|
|
276
|
+
# logging.basicConfig(level = LOG_LEVEL) #basic config
|
|
277
|
+
#
|
|
278
|
+
# log = logging.getLogger()
|
|
279
|
+
# log.setLevel(LOG_LEVEL)# Set Root Logger
|
|
280
|
+
#
|
|
281
|
+
# log.setLevel(level) #root
|
|
282
|
+
#
|
|
283
|
+
# loggers = [logging.getLogger(name) for name in logging.root.manager.loggerDict]
|
|
284
|
+
# for logger in loggers:
|
|
285
|
+
# if logger.__class__.__name__.lower().startswith('engforge'):
|
|
286
|
+
# logger.log(LOG_LEVEL,'setting log level: {}'.format(LOG_LEVEL))
|
|
287
|
+
# logger.setLevel(LOG_LEVEL)
|
|
288
|
+
# elif all_loggers:
|
|
289
|
+
# logger.log(LOG_LEVEL,'setting log level: {}'.format(LOG_LEVEL))
|
|
290
|
+
# logger.setLevel(LOG_LEVEL)
|