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

fix: remove API secrets from web3.py loggers [APE-1486] #1715

Merged
merged 5 commits into from
Oct 31, 2023
Merged
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
17 changes: 14 additions & 3 deletions src/ape/api/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
TransactionNotFoundError,
VirtualMachineError,
)
from ape.logging import LogLevel, logger
from ape.logging import LogLevel, logger, sanitize_url
from ape.types import (
AddressType,
AutoGasLimit,
Expand Down Expand Up @@ -745,6 +745,17 @@ def _increment_call_func_coverage_hit_count(self, txn: TransactionAPI):
self._test_runner.coverage_tracker.hit_function(contract_src, method)


def _sanitize_web3_url(msg: str) -> str:
if "URI: " not in msg:
return msg

parts = msg.split("URI: ")
prefix = parts[0].strip()
rest = parts[1].split(" ")
sanitized_url = sanitize_url(rest[0])
return f"{prefix} URI: {sanitized_url} {' '.join(rest[1:])}"


class Web3Provider(ProviderAPI, ABC):
"""
A base provider mixin class that uses the
Expand All @@ -755,8 +766,8 @@ class Web3Provider(ProviderAPI, ABC):
_client_version: Optional[str] = None

def __init__(self, *args, **kwargs):
logger.create_logger("web3.RequestManager")
logger.create_logger("web3.providers.HTTPProvider")
logger.create_logger("web3.RequestManager", handlers=(_sanitize_web3_url,))
logger.create_logger("web3.providers.HTTPProvider", handlers=(_sanitize_web3_url,))
super().__init__(*args, **kwargs)

@property
Expand Down
38 changes: 30 additions & 8 deletions src/ape/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
import traceback
from enum import IntEnum
from pathlib import Path
from typing import IO, Any, Dict, Optional, Union
from typing import IO, Any, Callable, Dict, Optional, Sequence, Union

import click
from yarl import URL


class LogLevel(IntEnum):
Expand Down Expand Up @@ -86,13 +87,19 @@ def format(self, record):


class ClickHandler(logging.Handler):
def __init__(self, echo_kwargs):
def __init__(
self, echo_kwargs: Dict, handlers: Optional[Sequence[Callable[[str], str]]] = None
):
super().__init__()
self.echo_kwargs = echo_kwargs
self.handlers = handlers or []

def emit(self, record):
try:
msg = self.format(record)
for handler in self.handlers:
msg = handler(msg)

level = record.levelname.lower()
if self.echo_kwargs.get(level):
click.echo(msg, **self.echo_kwargs[level])
Expand Down Expand Up @@ -212,15 +219,19 @@ def log_debug_stack_trace(self):
stack_trace = traceback.format_exc()
self._logger.debug(stack_trace)

def create_logger(self, new_name: str) -> logging.Logger:
_logger = get_logger(new_name, self.fmt)
def create_logger(
self, new_name: str, handlers: Optional[Sequence[Callable[[str], str]]] = None
) -> logging.Logger:
_logger = get_logger(new_name, fmt=self.fmt, handlers=handlers)
_logger.setLevel(self.level)
self._extra_loggers[new_name] = _logger
return _logger


def _format_logger(_logger: logging.Logger, fmt: str):
handler = ClickHandler(echo_kwargs=CLICK_ECHO_KWARGS)
def _format_logger(
_logger: logging.Logger, fmt: str, handlers: Optional[Sequence[Callable[[str], str]]] = None
):
handler = ClickHandler(echo_kwargs=CLICK_ECHO_KWARGS, handlers=handlers)
formatter = ApeColorFormatter(fmt=fmt)
handler.setFormatter(formatter)

Expand All @@ -232,20 +243,23 @@ def _format_logger(_logger: logging.Logger, fmt: str):
_logger.addHandler(handler)


def get_logger(name: str, fmt: Optional[str] = None) -> logging.Logger:
def get_logger(
name: str, fmt: Optional[str] = None, handlers: Optional[Sequence[Callable[[str], str]]] = None
) -> logging.Logger:
"""
Get a logger with the given ``name`` and configure it for usage with Ape.

Args:
name (str): The name of the logger.
fmt (Optional[str]): The format of the logger. Defaults to the Ape
logger's default format: ``"%(levelname)s%(plugin)s: %(message)s"``.
handlers (Optional[Sequence[Callable[[str], str]]]): Additional log message handlers.

Returns:
``logging.Logger``
"""
_logger = logging.getLogger(name)
_format_logger(_logger, fmt=fmt or DEFAULT_LOG_FORMAT)
_format_logger(_logger, fmt=fmt or DEFAULT_LOG_FORMAT, handlers=handlers)
return _logger


Expand All @@ -258,6 +272,14 @@ def _get_level(level: Optional[Union[str, int]] = None) -> str:
return level


def sanitize_url(url: str) -> str:
url_obj = URL(url).with_user(None).with_password(None)

# If there is a path, hide it but show that you are hiding it.
# Use string interpolation to prevent URL-character encoding.
return f"{url_obj.with_path('')}/[hidden]" if url_obj.path else f"{url}"


logger = ApeLogger.create()

# TODO: Can remove this type alias after 0.7
Expand Down
7 changes: 2 additions & 5 deletions src/ape_geth/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
ContractNotFoundError,
ProviderError,
)
from ape.logging import LogLevel, logger
from ape.logging import LogLevel, logger, sanitize_url
from ape.types import AddressType, CallTreeNode, SnapshotID, SourceTraceback, TraceFrame
from ape.utils import (
DEFAULT_NUMBER_OF_TEST_ACCOUNTS,
Expand Down Expand Up @@ -277,10 +277,7 @@ def uri(self) -> str:

@property
def _clean_uri(self) -> str:
url = URL(self.uri).with_user(None).with_password(None)
# If there is a path, hide it but show that you are hiding it.
# Use string interpolation to prevent URL-character encoding.
return f"{url.with_path('')}/[hidden]" if url.path else f"{url}"
return sanitize_url(self.uri)

@property
def ipc_path(self) -> Path:
Expand Down
Loading