-
Notifications
You must be signed in to change notification settings - Fork 14.1k
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
feat: add denylist to stats logger #25118
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,8 +14,9 @@ | |
# KIND, either express or implied. See the License for the | ||
# specific language governing permissions and limitations | ||
# under the License. | ||
from __future__ import annotations | ||
|
||
import logging | ||
from typing import Optional | ||
|
||
from colorama import Fore, Style | ||
|
||
|
@@ -25,8 +26,19 @@ | |
class BaseStatsLogger: | ||
"""Base class for logging realtime events""" | ||
|
||
def __init__(self, prefix: str = "superset") -> None: | ||
prefix: str | ||
metric_denylist: set[str] | ||
|
||
def should_log(self, key: str) -> bool: | ||
return key not in self.metric_denylist | ||
|
||
def __init__( | ||
self, | ||
prefix: str = "superset", | ||
metric_denylist: set[str] | None = None, | ||
) -> None: | ||
self.prefix = prefix | ||
self.metric_denylist = metric_denylist or set() | ||
|
||
def key(self, key: str) -> str: | ||
if self.prefix: | ||
|
@@ -51,24 +63,30 @@ def gauge(self, key: str, value: float) -> None: | |
|
||
class DummyStatsLogger(BaseStatsLogger): | ||
def incr(self, key: str) -> None: | ||
logger.debug(Fore.CYAN + "[stats_logger] (incr) " + key + Style.RESET_ALL) | ||
if self.should_log(key): | ||
logger.debug(Fore.CYAN + "[stats_logger] (incr) " + key + Style.RESET_ALL) | ||
|
||
def decr(self, key: str) -> None: | ||
logger.debug(Fore.CYAN + "[stats_logger] (decr) " + key + Style.RESET_ALL) | ||
if self.should_log(key): | ||
logger.debug(Fore.CYAN + "[stats_logger] (decr) " + key + Style.RESET_ALL) | ||
|
||
def timing(self, key: str, value: float) -> None: | ||
logger.debug( | ||
Fore.CYAN + f"[stats_logger] (timing) {key} | {value} " + Style.RESET_ALL | ||
) | ||
if self.should_log(key): | ||
logger.debug( | ||
Fore.CYAN | ||
+ f"[stats_logger] (timing) {key} | {value} " | ||
+ Style.RESET_ALL | ||
) | ||
|
||
def gauge(self, key: str, value: float) -> None: | ||
logger.debug( | ||
Fore.CYAN | ||
+ "[stats_logger] (gauge) " | ||
+ f"{key}" | ||
+ f"{value}" | ||
+ Style.RESET_ALL | ||
) | ||
if self.should_log(key): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @villebro so anyone who wants to use this denylist is going to have to implement the functionality in their own statslogger if they don't use the dummy. Should we put something in UPDATING to explain how to do this or do you think it's evident enough when reading this local example? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, maybe we should just add it to StatsdStatsLogger, and remove it from BaseStatsLogger. This will cover the vanilla StatsD use case, and should serve as an example for anyone who wants similar functionality in their own custom logger class. Thoughts @eschutho There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that sounds like a good idea. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 to comments above. But that's just a minor preference and current solution is fine by me as well |
||
logger.debug( | ||
Fore.CYAN | ||
+ "[stats_logger] (gauge) " | ||
+ f"{key}" | ||
+ f"{value}" | ||
+ Style.RESET_ALL | ||
) | ||
|
||
|
||
try: | ||
|
@@ -80,30 +98,36 @@ def __init__( # pylint: disable=super-init-not-called | |
host: str = "localhost", | ||
port: int = 8125, | ||
prefix: str = "superset", | ||
statsd_client: Optional[StatsClient] = None, | ||
statsd_client: StatsClient | None = None, | ||
metric_denylist: set[str] | None = None, | ||
) -> None: | ||
""" | ||
Initializes from either params or a supplied, pre-constructed statsd client. | ||
|
||
If statsd_client argument is given, all other arguments are ignored and the | ||
supplied client will be used to emit metrics. | ||
""" | ||
super().__init__(metric_denylist=metric_denylist) | ||
if statsd_client: | ||
self.client = statsd_client | ||
else: | ||
self.client = StatsClient(host=host, port=port, prefix=prefix) | ||
|
||
def incr(self, key: str) -> None: | ||
self.client.incr(key) | ||
if self.should_log(key): | ||
self.client.incr(key) | ||
|
||
def decr(self, key: str) -> None: | ||
self.client.decr(key) | ||
if self.should_log(key): | ||
self.client.decr(key) | ||
|
||
def timing(self, key: str, value: float) -> None: | ||
self.client.timing(key, value) | ||
if self.should_log(key): | ||
self.client.timing(key, value) | ||
|
||
def gauge(self, key: str, value: float) -> None: | ||
self.client.gauge(key, value) | ||
if self.should_log(key): | ||
self.client.gauge(key, value) | ||
|
||
except Exception: # pylint: disable=broad-except | ||
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it's better to promote
metrics_denylist
to be a config that can be overridden.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
something like
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't that be the same as just overwriting the STATS_LOGGER with different arguments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zephyring or @craig-rueda mentioned a good point that there's no guarantee that a metric name might not change. What do you all think about having an enum of strings that we can reference instead? It will have to be maintained and updated of course, but at least then we can export it and refer to the enum in the config rather than the string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If promoting to be a config, we can just override the config and use the default
StatsdStatsLogger
logger.If later on there's any default in the denylist that will be easier to reference and merge/override also