0
# Logging and Debugging
1
2
Comprehensive logging system with color support and control tree enumeration for debugging automation scripts and understanding application structure. These tools help developers troubleshoot automation issues and analyze UI hierarchies.
3
4
## Capabilities
5
6
### Logger Class
7
8
Main logging class providing various output methods with color support.
9
10
```python { .api }
11
class Logger:
12
"""Comprehensive logging system for automation debugging."""
13
14
def Write(self, text: str) -> None:
15
"""
16
Write text to log without newline.
17
18
Args:
19
text: Text to write
20
"""
21
22
def WriteLine(self, text: str) -> None:
23
"""
24
Write text to log with newline.
25
26
Args:
27
text: Text to write
28
"""
29
30
def ColorfulWrite(self, text: str, color: int) -> None:
31
"""
32
Write colored text to log without newline.
33
34
Args:
35
text: Text to write
36
color: Console color constant
37
"""
38
39
def ColorfulWriteLine(self, text: str, color: int) -> None:
40
"""
41
Write colored text to log with newline.
42
43
Args:
44
text: Text to write
45
color: Console color constant
46
"""
47
48
def Log(self, message: str) -> None:
49
"""
50
Log message with timestamp.
51
52
Args:
53
message: Message to log
54
"""
55
56
def ColorfulLog(self, message: str, color: int) -> None:
57
"""
58
Log colored message with timestamp.
59
60
Args:
61
message: Message to log
62
color: Console color constant
63
"""
64
65
def SetLogFile(self, filename: str) -> None:
66
"""
67
Set output log file.
68
69
Args:
70
filename: Path to log file
71
"""
72
73
def Close(self) -> None:
74
"""Close log file."""
75
```
76
77
### Console Colors
78
79
```python { .api }
80
class ConsoleColor:
81
"""Console color constants for colored logging."""
82
83
# Standard colors
84
Black: int = 0
85
DarkBlue: int = 1
86
DarkGreen: int = 2
87
DarkCyan: int = 3
88
DarkRed: int = 4
89
DarkMagenta: int = 5
90
DarkYellow: int = 6
91
Gray: int = 7
92
DarkGray: int = 8
93
Blue: int = 9
94
Green: int = 10
95
Cyan: int = 11
96
Red: int = 12
97
Magenta: int = 13
98
Yellow: int = 14
99
White: int = 15
100
101
class Logger:
102
# Color name to value mapping
103
ColorName2Value: dict = {
104
'Black': 0,
105
'DarkBlue': 1,
106
'DarkGreen': 2,
107
'DarkCyan': 3,
108
'DarkRed': 4,
109
'DarkMagenta': 5,
110
'DarkYellow': 6,
111
'Gray': 7,
112
'DarkGray': 8,
113
'Blue': 9,
114
'Green': 10,
115
'Cyan': 11,
116
'Red': 12,
117
'Magenta': 13,
118
'Yellow': 14,
119
'White': 15
120
}
121
```
122
123
### Control Logging Functions
124
125
Global functions for logging control information and hierarchies.
126
127
```python { .api }
128
def LogControl(control: Control) -> None:
129
"""
130
Log detailed information about a control.
131
132
Args:
133
control: Control to log information for
134
"""
135
136
def EnumAndLogControl(control: Control, depth: int = 1, showAllControls: bool = True) -> None:
137
"""
138
Enumerate and log control hierarchy.
139
140
Args:
141
control: Root control to start enumeration from
142
depth: Maximum depth to enumerate (-1 for unlimited)
143
showAllControls: Whether to show all controls or just visible ones
144
"""
145
146
def EnumAndLogControlAncestors(control: Control) -> None:
147
"""
148
Log all ancestor controls of the given control.
149
150
Args:
151
control: Control to log ancestors for
152
"""
153
```
154
155
### System Utilities
156
157
```python { .api }
158
def ShowDesktop(waitTime: float = 1) -> None:
159
"""
160
Show the desktop (minimize all windows).
161
162
Args:
163
waitTime: Time to wait after showing desktop
164
"""
165
166
def RunWithHotKey(func: callable, hotkey: str) -> None:
167
"""
168
Run a function when a hotkey is pressed.
169
170
Args:
171
func: Function to execute
172
hotkey: Hotkey combination (e.g., 'ctrl+f1')
173
"""
174
175
def WaitHotKeyReleased(hotkey: str, timeout: float = 15) -> bool:
176
"""
177
Wait for a hotkey to be released.
178
179
Args:
180
hotkey: Hotkey combination
181
timeout: Maximum wait time in seconds
182
183
Returns:
184
bool: True if hotkey was released, False if timeout
185
"""
186
```
187
188
### Debug Configuration
189
190
Global debug settings for controlling logging behavior.
191
192
```python { .api }
193
# Debug flags
194
DEBUG_SEARCH_TIME: bool = False # Log search timing information
195
DEBUG_EXIST_DISAPPEAR: bool = False # Log control existence checking
196
197
# Configuration functions
198
def SetDebugSearchTime(enabled: bool) -> None:
199
"""Enable/disable search time debugging."""
200
201
def SetDebugExistDisappear(enabled: bool) -> None:
202
"""Enable/disable existence checking debugging."""
203
```
204
205
## Usage Examples
206
207
### Basic Logging
208
209
```python
210
import uiautomation
211
212
# Create logger instance
213
logger = uiautomation.Logger()
214
215
# Basic text logging
216
logger.WriteLine("Starting automation script")
217
logger.Write("Processing... ")
218
logger.WriteLine("Done")
219
220
# Colored logging
221
logger.ColorfulWriteLine("Success!", uiautomation.ConsoleColor.Green)
222
logger.ColorfulWriteLine("Warning: Check configuration", uiautomation.ConsoleColor.Yellow)
223
logger.ColorfulWriteLine("Error: Failed to connect", uiautomation.ConsoleColor.Red)
224
225
# Timestamped logging
226
logger.Log("Script execution started")
227
logger.ColorfulLog("Critical error occurred", uiautomation.ConsoleColor.Red)
228
```
229
230
### File Logging
231
232
```python
233
# Set up file logging
234
logger = uiautomation.Logger()
235
logger.SetLogFile("automation_log.txt")
236
237
# Log to file
238
logger.WriteLine("This will be written to the file")
239
logger.ColorfulWriteLine("Colored text in file", uiautomation.ConsoleColor.Blue)
240
241
# Close file when done
242
logger.Close()
243
```
244
245
### Control Information Logging
246
247
```python
248
# Log detailed information about a specific control
249
button = uiautomation.ButtonControl(Name='Submit')
250
if button.Exists():
251
uiautomation.LogControl(button)
252
253
# Log information about the focused control
254
focused = uiautomation.GetFocusedControl()
255
if focused:
256
uiautomation.LogControl(focused)
257
```
258
259
### Control Hierarchy Enumeration
260
261
```python
262
# Enumerate and log entire application window
263
app_window = uiautomation.WindowControl(Name='Calculator')
264
if app_window.Exists():
265
# Log all controls in the window (unlimited depth)
266
uiautomation.EnumAndLogControl(app_window, depth=-1)
267
268
# Enumerate with limited depth
269
desktop = uiautomation.GetRootControl()
270
uiautomation.EnumAndLogControl(desktop, depth=2) # Only 2 levels deep
271
272
# Show only visible controls
273
visible_only = False # Set to True to show only visible controls
274
uiautomation.EnumAndLogControl(app_window, depth=3, showAllControls=visible_only)
275
```
276
277
### Ancestor Logging
278
279
```python
280
# Find a specific control and log its ancestry
281
text_field = uiautomation.EditControl(Name='Username')
282
if text_field.Exists():
283
uiautomation.EnumAndLogControlAncestors(text_field)
284
# This will show: Desktop -> Window -> Pane -> Group -> EditControl
285
```
286
287
### Debug Mode Configuration
288
289
```python
290
# Enable debug logging for performance analysis
291
uiautomation.SetDebugSearchTime(True)
292
uiautomation.SetDebugExistDisappear(True)
293
294
# Now control searches will log timing information
295
button = uiautomation.ButtonControl(Name='Click Me')
296
button.Click() # This will log search time and existence checks
297
298
# Disable debug logging
299
uiautomation.SetDebugSearchTime(False)
300
uiautomation.SetDebugExistDisappear(False)
301
```
302
303
### Automation Script Debugging
304
305
```python
306
def debug_automation_step(step_name, func, *args, **kwargs):
307
"""Wrapper function to debug automation steps."""
308
logger = uiautomation.Logger()
309
310
logger.ColorfulWriteLine(f"Starting step: {step_name}", uiautomation.ConsoleColor.Cyan)
311
312
try:
313
start_time = time.time()
314
result = func(*args, **kwargs)
315
end_time = time.time()
316
317
logger.ColorfulWriteLine(
318
f"Step completed in {end_time - start_time:.2f}s: {step_name}",
319
uiautomation.ConsoleColor.Green
320
)
321
return result
322
323
except Exception as e:
324
logger.ColorfulWriteLine(
325
f"Step failed: {step_name} - {str(e)}",
326
uiautomation.ConsoleColor.Red
327
)
328
raise
329
330
# Use the debug wrapper
331
def click_submit_button():
332
button = uiautomation.ButtonControl(Name='Submit')
333
button.Click()
334
335
debug_automation_step("Click Submit Button", click_submit_button)
336
```
337
338
### Control Search Debugging
339
340
```python
341
def debug_control_search(control_type, **search_criteria):
342
"""Debug control search operations."""
343
logger = uiautomation.Logger()
344
345
# Log search criteria
346
criteria_str = ", ".join([f"{k}='{v}'" for k, v in search_criteria.items()])
347
logger.ColorfulWriteLine(f"Searching for {control_type.__name__} with {criteria_str}",
348
uiautomation.ConsoleColor.Yellow)
349
350
# Perform search
351
control = control_type(**search_criteria)
352
353
if control.Exists():
354
logger.ColorfulWriteLine("Control found!", uiautomation.ConsoleColor.Green)
355
# Log control details
356
uiautomation.LogControl(control)
357
return control
358
else:
359
logger.ColorfulWriteLine("Control not found!", uiautomation.ConsoleColor.Red)
360
361
# Try to find similar controls for debugging
362
logger.WriteLine("Looking for similar controls...")
363
root = uiautomation.GetRootControl()
364
uiautomation.EnumAndLogControl(root, depth=5, showAllControls=True)
365
return None
366
367
# Debug a control search
368
found_button = debug_control_search(
369
uiautomation.ButtonControl,
370
Name='Submit',
371
ClassName='Button'
372
)
373
```
374
375
### Application Structure Analysis
376
377
```python
378
def analyze_application_structure(app_name):
379
"""Analyze and log the structure of an application."""
380
logger = uiautomation.Logger()
381
logger.SetLogFile(f"{app_name}_structure.log")
382
383
# Find application window
384
app_window = uiautomation.WindowControl(Name=app_name)
385
if not app_window.Exists():
386
logger.ColorfulWriteLine(f"Application '{app_name}' not found", uiautomation.ConsoleColor.Red)
387
return
388
389
logger.ColorfulWriteLine(f"Analyzing structure of '{app_name}'", uiautomation.ConsoleColor.Cyan)
390
391
# Log basic window information
392
logger.WriteLine(f"Window Handle: {app_window.Handle}")
393
logger.WriteLine(f"Process ID: {app_window.ProcessId}")
394
logger.WriteLine(f"Class Name: {app_window.ClassName}")
395
logger.WriteLine(f"Bounds: {app_window.BoundingRectangle}")
396
397
# Enumerate all controls
398
logger.WriteLine("\n=== COMPLETE CONTROL HIERARCHY ===")
399
uiautomation.EnumAndLogControl(app_window, depth=-1)
400
401
logger.Close()
402
logger.WriteLine(f"Structure analysis saved to {app_name}_structure.log")
403
404
# Analyze Calculator application
405
analyze_application_structure("Calculator")
406
```
407
408
### Hotkey Debugging Support
409
410
```python
411
def setup_debug_hotkey():
412
"""Set up hotkey for interactive debugging."""
413
def debug_current_control():
414
logger = uiautomation.Logger()
415
logger.ColorfulWriteLine("=== DEBUG HOTKEY PRESSED ===", uiautomation.ConsoleColor.Magenta)
416
417
# Get control under cursor
418
cursor_control = uiautomation.ControlFromCursor()
419
if cursor_control:
420
logger.WriteLine("Control under cursor:")
421
uiautomation.LogControl(cursor_control)
422
423
logger.WriteLine("\nControl ancestors:")
424
uiautomation.EnumAndLogControlAncestors(cursor_control)
425
else:
426
logger.ColorfulWriteLine("No control found under cursor", uiautomation.ConsoleColor.Red)
427
428
# Set up Ctrl+F12 as debug hotkey
429
uiautomation.RunWithHotKey(debug_current_control, 'ctrl+f12')
430
print("Debug hotkey (Ctrl+F12) is active. Press it while hovering over controls to debug.")
431
432
# Activate debug hotkey
433
setup_debug_hotkey()
434
```
435
436
### Log Analysis Utilities
437
438
```python
439
def parse_automation_log(log_file):
440
"""Parse and analyze automation log files."""
441
logger = uiautomation.Logger()
442
443
try:
444
with open(log_file, 'r') as f:
445
lines = f.readlines()
446
447
logger.ColorfulWriteLine(f"Analyzing log file: {log_file}", uiautomation.ConsoleColor.Cyan)
448
logger.WriteLine(f"Total lines: {len(lines)}")
449
450
# Count different types of entries
451
error_count = sum(1 for line in lines if 'error' in line.lower())
452
warning_count = sum(1 for line in lines if 'warning' in line.lower())
453
454
logger.WriteLine(f"Errors found: {error_count}")
455
logger.WriteLine(f"Warnings found: {warning_count}")
456
457
# Show errors and warnings
458
if error_count > 0:
459
logger.ColorfulWriteLine("\nErrors:", uiautomation.ConsoleColor.Red)
460
for line in lines:
461
if 'error' in line.lower():
462
logger.ColorfulWriteLine(f" {line.strip()}", uiautomation.ConsoleColor.Red)
463
464
if warning_count > 0:
465
logger.ColorfulWriteLine("\nWarnings:", uiautomation.ConsoleColor.Yellow)
466
for line in lines:
467
if 'warning' in line.lower():
468
logger.ColorfulWriteLine(f" {line.strip()}", uiautomation.ConsoleColor.Yellow)
469
470
except FileNotFoundError:
471
logger.ColorfulWriteLine(f"Log file not found: {log_file}", uiautomation.ConsoleColor.Red)
472
473
# Analyze a log file
474
parse_automation_log("automation_log.txt")
475
```