Skip to content

Commit 2b63943

Browse files
authored
Merge pull request #287 from autoscrape-labs/refactor/add-logging
Add logging through all codebase
2 parents dbd6983 + 3e19277 commit 2b63943

File tree

15 files changed

+505
-34
lines changed

15 files changed

+505
-34
lines changed

pydoll/browser/chromium/base.py

Lines changed: 108 additions & 2 deletions
Large diffs are not rendered by default.

pydoll/browser/chromium/chrome.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
import platform
23
from typing import Optional
34

@@ -7,6 +8,8 @@
78
from pydoll.exceptions import UnsupportedOS
89
from pydoll.utils import validate_browser_paths
910

11+
logger = logging.getLogger(__name__)
12+
1013

1114
class Chrome(Browser):
1215
"""Chrome browser implementation for CDP automation."""
@@ -39,6 +42,7 @@ def _get_default_binary_location():
3942
ValueError: If executable not found at default location.
4043
"""
4144
os_name = platform.system()
45+
logger.debug(f'Resolving default Chrome binary for OS: {os_name}')
4246

4347
browser_paths = {
4448
'Windows': [
@@ -57,6 +61,9 @@ def _get_default_binary_location():
5761
browser_path = browser_paths.get(os_name)
5862

5963
if not browser_path:
64+
logger.error(f'Unsupported OS: {os_name}')
6065
raise UnsupportedOS(f'Unsupported OS: {os_name}')
6166

62-
return validate_browser_paths(browser_path)
67+
path = validate_browser_paths(browser_path)
68+
logger.debug(f'Using Chrome binary: {path}')
69+
return path

pydoll/browser/chromium/edge.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
import platform
23
from typing import Optional
34

@@ -7,6 +8,8 @@
78
from pydoll.exceptions import UnsupportedOS
89
from pydoll.utils import validate_browser_paths
910

11+
logger = logging.getLogger(__name__)
12+
1013

1114
class Edge(Browser):
1215
"""Edge browser implementation for CDP automation."""
@@ -39,6 +42,7 @@ def _get_default_binary_location():
3942
ValueError: If executable not found at default location.
4043
"""
4144
os_name = platform.system()
45+
logger.debug(f'Resolving default Edge binary for OS: {os_name}')
4246

4347
browser_paths = {
4448
'Windows': [
@@ -62,6 +66,9 @@ def _get_default_binary_location():
6266
browser_path = browser_paths.get(os_name)
6367

6468
if not browser_path:
69+
logger.error(f'Unsupported OS: {os_name}')
6570
raise UnsupportedOS()
6671

67-
return validate_browser_paths(browser_path)
72+
path = validate_browser_paths(browser_path)
73+
logger.debug(f'Using Edge binary: {path}')
74+
return path

pydoll/browser/managers/browser_options_manager.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import logging
12
from typing import Optional
23

34
from pydoll.browser.interfaces import BrowserOptionsManager, Options
45
from pydoll.browser.options import ChromiumOptions
56
from pydoll.exceptions import InvalidOptionsObject
67

8+
logger = logging.getLogger(__name__)
9+
710

811
class ChromiumOptionsManager(BrowserOptionsManager):
912
"""
@@ -15,6 +18,10 @@ class ChromiumOptionsManager(BrowserOptionsManager):
1518

1619
def __init__(self, options: Optional[Options] = None):
1720
self.options = options
21+
logger.debug(
22+
f'ChromiumOptionsManager initialized with options='
23+
f'{type(options).__name__ if options is not None else "None"}'
24+
)
1825

1926
def initialize_options(
2027
self,
@@ -33,14 +40,18 @@ def initialize_options(
3340
"""
3441
if self.options is None:
3542
self.options = ChromiumOptions()
43+
logger.debug('No options provided; created default ChromiumOptions')
3644

3745
if not isinstance(self.options, ChromiumOptions):
46+
logger.error(f'Invalid options type: {type(self.options)}; expected ChromiumOptions')
3847
raise InvalidOptionsObject(f'Expected ChromiumOptions, got {type(self.options)}')
3948

4049
self.add_default_arguments()
50+
logger.debug('Options initialized and default arguments applied')
4151
return self.options
4252

4353
def add_default_arguments(self):
4454
"""Add default arguments required for CDP integration."""
55+
logger.debug('Adding default arguments for Chromium-based browsers')
4556
self.options.add_argument('--no-first-run')
4657
self.options.add_argument('--no-default-browser-check')

pydoll/browser/managers/browser_process_manager.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import logging
12
import subprocess
23
from typing import Callable, Optional
34

5+
logger = logging.getLogger(__name__)
6+
47

58
class BrowserProcessManager:
69
"""
@@ -24,6 +27,9 @@ def __init__(
2427
"""
2528
self._process_creator = process_creator or self._default_process_creator
2629
self._process: Optional[subprocess.Popen] = None
30+
logger.debug(
31+
f'BrowserProcessManager initialized; custom process_creator={bool(process_creator)}'
32+
)
2733

2834
def start_browser_process(
2935
self,
@@ -45,16 +51,23 @@ def start_browser_process(
4551
Note:
4652
Automatically adds --remote-debugging-port argument.
4753
"""
48-
self._process = self._process_creator([
54+
logger.info(f'Starting browser process: {binary_location} on port {port}')
55+
command = [
4956
binary_location,
5057
f'--remote-debugging-port={port}',
5158
*arguments,
52-
])
59+
]
60+
logger.debug(f'Command: {command}')
61+
self._process = self._process_creator(command)
62+
logger.debug(
63+
f'Browser process started: pid={self._process.pid if self._process else "unknown"}'
64+
)
5365
return self._process
5466

5567
@staticmethod
5668
def _default_process_creator(command: list[str]) -> subprocess.Popen:
5769
"""Create browser process with output capture to prevent console clutter."""
70+
logger.debug(f'Creating process: {command}')
5871
return subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
5972

6073
def stop_process(self):
@@ -65,8 +78,12 @@ def stop_process(self):
6578
Safe to call even if no process is running.
6679
"""
6780
if self._process:
81+
logger.info(f'Stopping browser process pid={self._process.pid}')
6882
self._process.terminate()
6983
try:
7084
self._process.wait(timeout=15)
85+
logger.debug('Process terminated gracefully')
7186
except subprocess.TimeoutExpired:
87+
logger.warning('Process did not terminate in 15s; sending SIGKILL')
7288
self._process.kill()
89+
logger.debug('Process killed')

pydoll/browser/managers/proxy_manager.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import logging
12
from typing import Optional
23

34
from pydoll.browser.options import Options
45

6+
logger = logging.getLogger(__name__)
7+
58

69
class ProxyManager:
710
"""
@@ -20,6 +23,7 @@ def __init__(self, options: Options):
2023
Will be modified if credentials are found.
2124
"""
2225
self.options = options
26+
logger.debug('ProxyManager initialized with options')
2327

2428
def get_proxy_credentials(self) -> tuple[bool, tuple[Optional[str], Optional[str]]]:
2529
"""
@@ -44,6 +48,11 @@ def get_proxy_credentials(self) -> tuple[bool, tuple[Optional[str], Optional[str
4448
self._update_proxy_argument(index, clean_proxy)
4549
private_proxy = True
4650
credentials = (username, password)
51+
logger.debug(
52+
f'Proxy credentials extracted (user_set={bool(username)}); argument sanitized'
53+
)
54+
else:
55+
logger.debug('Proxy configured without embedded credentials')
4756

4857
return private_proxy, credentials
4958

@@ -56,7 +65,9 @@ def _find_proxy_argument(self) -> Optional[tuple[int, str]]:
5665
"""
5766
for index, arg in enumerate(self.options.arguments):
5867
if arg.startswith('--proxy-server='):
59-
return index, arg.split('=', 1)[1]
68+
value = arg.split('=', 1)[1]
69+
logger.debug(f'Found proxy argument at index {index}: {value}')
70+
return index, value
6071
return None
6172

6273
@staticmethod
@@ -83,11 +94,12 @@ def _parse_proxy(proxy_value: str) -> tuple[bool, Optional[str], Optional[str],
8394
creds_part, server_part = proxy_value.split('@', 1)
8495
username, password = creds_part.split(':', 1)
8596

86-
clean_proxy = f"{scheme}://{server_part}" if has_scheme else server_part
97+
clean_proxy = f'{scheme}://{server_part}' if has_scheme else server_part
8798
return True, username, password, clean_proxy
8899
except ValueError:
89100
return False, None, None, proxy_value
90101

91102
def _update_proxy_argument(self, index: int, clean_proxy: str) -> None:
92103
"""Replace proxy argument with credential-free version."""
93104
self.options.arguments[index] = f'--proxy-server={clean_proxy}'
105+
logger.debug(f'Proxy argument updated at index {index}: {clean_proxy}')

pydoll/browser/managers/temp_dir_manager.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import logging
12
import shutil
23
import time
34
from pathlib import Path
45
from tempfile import TemporaryDirectory
56
from typing import Callable
67

8+
logger = logging.getLogger(__name__)
9+
710

811
class TempDirectoryManager:
912
"""
@@ -23,6 +26,7 @@ def __init__(self, temp_dir_factory: Callable[[], TemporaryDirectory] = Temporar
2326
"""
2427
self._temp_dir_factory = temp_dir_factory
2528
self._temp_dirs: list[TemporaryDirectory] = []
29+
logger.debug('TempDirectoryManager initialized')
2630

2731
def create_temp_dir(self) -> TemporaryDirectory:
2832
"""
@@ -33,6 +37,7 @@ def create_temp_dir(self) -> TemporaryDirectory:
3337
"""
3438
temp_dir = self._temp_dir_factory()
3539
self._temp_dirs.append(temp_dir)
40+
logger.debug(f'Created temp directory: {temp_dir.name}')
3641
return temp_dir
3742

3843
@staticmethod
@@ -56,6 +61,9 @@ def retry_process_file(func: Callable[[str], None], path: str, retry_times: int
5661
break
5762
except PermissionError:
5863
time.sleep(0.1)
64+
logger.debug(
65+
f'Retrying file operation due to PermissionError (attempt {retry_time})'
66+
)
5967
else:
6068
raise PermissionError()
6169

@@ -80,6 +88,7 @@ def handle_cleanup_error(self, func: Callable[[str], None], path: str, exc_info:
8088
self.retry_process_file(func, path)
8189
return
8290
except PermissionError:
91+
logger.warning(f'Failed retrying cleanup for locked file: {path}')
8392
raise exc_value
8493
elif exc_type is OSError:
8594
return
@@ -93,4 +102,5 @@ def cleanup(self):
93102
Continues cleanup even if some files resist deletion.
94103
"""
95104
for temp_dir in self._temp_dirs:
105+
logger.info(f'Cleaning up temp directory: {temp_dir.name}')
96106
shutil.rmtree(temp_dir.name, onerror=self.handle_cleanup_error)

0 commit comments

Comments
 (0)