kavach-logger 0.0.1__tar.gz
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.
- kavach_logger-0.0.1/PKG-INFO +190 -0
- kavach_logger-0.0.1/README.md +171 -0
- kavach_logger-0.0.1/kavach_logger/__init__.py +6 -0
- kavach_logger-0.0.1/kavach_logger/base_logger.py +12 -0
- kavach_logger-0.0.1/kavach_logger/default_logger.py +66 -0
- kavach_logger-0.0.1/kavach_logger/logger_manager.py +51 -0
- kavach_logger-0.0.1/kavach_logger/setup.py +45 -0
- kavach_logger-0.0.1/kavach_logger.egg-info/PKG-INFO +190 -0
- kavach_logger-0.0.1/kavach_logger.egg-info/SOURCES.txt +11 -0
- kavach_logger-0.0.1/kavach_logger.egg-info/dependency_links.txt +1 -0
- kavach_logger-0.0.1/kavach_logger.egg-info/top_level.txt +1 -0
- kavach_logger-0.0.1/setup.cfg +4 -0
- kavach_logger-0.0.1/setup.py +19 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kavach-logger
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Centralized logging and masking for Kavach security suite
|
|
5
|
+
Home-page: https://github.com/shivamnamdeo0101/kavach-agent-ecosystem
|
|
6
|
+
Author: Shivam Namdeo
|
|
7
|
+
Author-email: shivamnamdeo0101@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Requires-Python: >=3.7
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Dynamic: author
|
|
12
|
+
Dynamic: author-email
|
|
13
|
+
Dynamic: description
|
|
14
|
+
Dynamic: description-content-type
|
|
15
|
+
Dynamic: home-page
|
|
16
|
+
Dynamic: license
|
|
17
|
+
Dynamic: requires-python
|
|
18
|
+
Dynamic: summary
|
|
19
|
+
|
|
20
|
+
# Kavach Logger
|
|
21
|
+
|
|
22
|
+
Centralized logging with automatic sensitive data masking for security-critical applications.
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
✅ **Automatic Data Masking** - Detects and redacts API keys, tokens, PII, passwords, and other sensitive information
|
|
27
|
+
✅ **Pluggable Implementations** - Switch between masked/plain loggers or implement custom backends
|
|
28
|
+
✅ **Structured Logging** - JSON-compatible log output with **kwargs support
|
|
29
|
+
✅ **Singleton Logger Manager** - Unified logger lifecycle management
|
|
30
|
+
✅ **Zero Dependencies** - No external requirements
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install kavach-logger
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
### Basic Usage - Auto-Masking
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from kavach_logger import get_logger
|
|
44
|
+
|
|
45
|
+
# Creates a masked logger (auto-masks sensitive data)
|
|
46
|
+
logger = get_logger("myapp")
|
|
47
|
+
logger.info("API Key: sk-1234567890")
|
|
48
|
+
# Output: API Key: sk-***
|
|
49
|
+
logger.error("Password: secret123")
|
|
50
|
+
# Output: Password: ***
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Plain Logger (No Masking)
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from kavach_logger import get_logger
|
|
57
|
+
|
|
58
|
+
logger = get_logger("myapp", masked=False)
|
|
59
|
+
logger.info("Debug: token=abc123")
|
|
60
|
+
# Output: Debug: token=abc123 (unmodified)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Manual Data Masking
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from kavach_logger import mask_sensitive_data
|
|
67
|
+
|
|
68
|
+
data = "credit_card=4532123456789012"
|
|
69
|
+
masked = mask_sensitive_data(data)
|
|
70
|
+
print(masked) # credit_card=****
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Custom Logger Implementation
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from kavach_logger import BaseLogger, DefaultLogger
|
|
77
|
+
|
|
78
|
+
class CustomLogger(DefaultLogger):
|
|
79
|
+
def info(self, msg, **kwargs):
|
|
80
|
+
msg = f"[CUSTOM] {msg}"
|
|
81
|
+
super().info(msg, **kwargs)
|
|
82
|
+
|
|
83
|
+
custom = CustomLogger()
|
|
84
|
+
custom.info("Custom implementation!")
|
|
85
|
+
# Output: [CUSTOM] Custom implementation!
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Logger Manager (Singleton)
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from kavach_logger import LoggerManager
|
|
92
|
+
|
|
93
|
+
# Get or create logger
|
|
94
|
+
logger1 = LoggerManager.get_logger("app", masked=True)
|
|
95
|
+
logger2 = LoggerManager.get_logger("app") # Returns same instance
|
|
96
|
+
|
|
97
|
+
# Control all loggers
|
|
98
|
+
LoggerManager.enable_all()
|
|
99
|
+
LoggerManager.disable_all()
|
|
100
|
+
LoggerManager.enable_masking() # Enable masking globally
|
|
101
|
+
LoggerManager.disable_masking() # Disable masking globally
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## API Reference
|
|
105
|
+
|
|
106
|
+
### `get_logger(name: str, masked: bool = True) -> BaseLogger`
|
|
107
|
+
Creates or retrieves a logger instance.
|
|
108
|
+
|
|
109
|
+
**Parameters:**
|
|
110
|
+
- `name` (str): Logger identifier
|
|
111
|
+
- `masked` (bool): Enable automatic masking (default: True)
|
|
112
|
+
|
|
113
|
+
**Returns:** `BaseLogger` instance
|
|
114
|
+
|
|
115
|
+
### `mask_sensitive_data(text: str) -> str`
|
|
116
|
+
Manually masks sensitive patterns in text.
|
|
117
|
+
|
|
118
|
+
**Patterns Masked:**
|
|
119
|
+
- API keys (sk-*, pk-*)
|
|
120
|
+
- Bearer tokens
|
|
121
|
+
- AWS credentials
|
|
122
|
+
- Passwords
|
|
123
|
+
- Credit card numbers
|
|
124
|
+
- Social security numbers
|
|
125
|
+
- Email addresses (partial)
|
|
126
|
+
|
|
127
|
+
### Logger Methods
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
logger.info(msg, **kwargs) # Info level
|
|
131
|
+
logger.error(msg, **kwargs) # Error level
|
|
132
|
+
logger.debug(msg, **kwargs) # Debug level
|
|
133
|
+
logger.warning(msg, **kwargs) # Warning level
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Configuration
|
|
137
|
+
|
|
138
|
+
### Global Masking Control
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from kavach_logger import LoggerManager
|
|
142
|
+
|
|
143
|
+
# Disable masking for all loggers
|
|
144
|
+
LoggerManager.disable_masking()
|
|
145
|
+
|
|
146
|
+
# Re-enable masking
|
|
147
|
+
LoggerManager.enable_masking()
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Examples
|
|
151
|
+
|
|
152
|
+
### Logging with Structured Data
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
logger = get_logger("security")
|
|
156
|
+
|
|
157
|
+
logger.info(
|
|
158
|
+
"Security event detected",
|
|
159
|
+
event_type="login",
|
|
160
|
+
user_id="user123",
|
|
161
|
+
token="sk-abc123xyz"
|
|
162
|
+
)
|
|
163
|
+
# Automatically masks the token
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Processing Sensitive Logs
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
from kavach_logger import mask_sensitive_data
|
|
170
|
+
|
|
171
|
+
logs = [
|
|
172
|
+
"User created with password: MyPass123!",
|
|
173
|
+
"API call to https://api.example.com?token=abc123"
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
for log in logs:
|
|
177
|
+
safe_log = mask_sensitive_data(log)
|
|
178
|
+
print(safe_log) # Safe to output/store
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Use Cases
|
|
182
|
+
|
|
183
|
+
- **Security Auditing** - Track security events without exposing credentials
|
|
184
|
+
- **PCI/HIPAA Compliance** - Automatic redaction for sensitive logs
|
|
185
|
+
- **Agent Logging** - Mask AI-generated content containing API keys/tokens
|
|
186
|
+
- **Production Debugging** - Safe log output in production environments
|
|
187
|
+
|
|
188
|
+
## License
|
|
189
|
+
|
|
190
|
+
MIT License
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Kavach Logger
|
|
2
|
+
|
|
3
|
+
Centralized logging with automatic sensitive data masking for security-critical applications.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
✅ **Automatic Data Masking** - Detects and redacts API keys, tokens, PII, passwords, and other sensitive information
|
|
8
|
+
✅ **Pluggable Implementations** - Switch between masked/plain loggers or implement custom backends
|
|
9
|
+
✅ **Structured Logging** - JSON-compatible log output with **kwargs support
|
|
10
|
+
✅ **Singleton Logger Manager** - Unified logger lifecycle management
|
|
11
|
+
✅ **Zero Dependencies** - No external requirements
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install kavach-logger
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
### Basic Usage - Auto-Masking
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from kavach_logger import get_logger
|
|
25
|
+
|
|
26
|
+
# Creates a masked logger (auto-masks sensitive data)
|
|
27
|
+
logger = get_logger("myapp")
|
|
28
|
+
logger.info("API Key: sk-1234567890")
|
|
29
|
+
# Output: API Key: sk-***
|
|
30
|
+
logger.error("Password: secret123")
|
|
31
|
+
# Output: Password: ***
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Plain Logger (No Masking)
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from kavach_logger import get_logger
|
|
38
|
+
|
|
39
|
+
logger = get_logger("myapp", masked=False)
|
|
40
|
+
logger.info("Debug: token=abc123")
|
|
41
|
+
# Output: Debug: token=abc123 (unmodified)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Manual Data Masking
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from kavach_logger import mask_sensitive_data
|
|
48
|
+
|
|
49
|
+
data = "credit_card=4532123456789012"
|
|
50
|
+
masked = mask_sensitive_data(data)
|
|
51
|
+
print(masked) # credit_card=****
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Custom Logger Implementation
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from kavach_logger import BaseLogger, DefaultLogger
|
|
58
|
+
|
|
59
|
+
class CustomLogger(DefaultLogger):
|
|
60
|
+
def info(self, msg, **kwargs):
|
|
61
|
+
msg = f"[CUSTOM] {msg}"
|
|
62
|
+
super().info(msg, **kwargs)
|
|
63
|
+
|
|
64
|
+
custom = CustomLogger()
|
|
65
|
+
custom.info("Custom implementation!")
|
|
66
|
+
# Output: [CUSTOM] Custom implementation!
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Logger Manager (Singleton)
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from kavach_logger import LoggerManager
|
|
73
|
+
|
|
74
|
+
# Get or create logger
|
|
75
|
+
logger1 = LoggerManager.get_logger("app", masked=True)
|
|
76
|
+
logger2 = LoggerManager.get_logger("app") # Returns same instance
|
|
77
|
+
|
|
78
|
+
# Control all loggers
|
|
79
|
+
LoggerManager.enable_all()
|
|
80
|
+
LoggerManager.disable_all()
|
|
81
|
+
LoggerManager.enable_masking() # Enable masking globally
|
|
82
|
+
LoggerManager.disable_masking() # Disable masking globally
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## API Reference
|
|
86
|
+
|
|
87
|
+
### `get_logger(name: str, masked: bool = True) -> BaseLogger`
|
|
88
|
+
Creates or retrieves a logger instance.
|
|
89
|
+
|
|
90
|
+
**Parameters:**
|
|
91
|
+
- `name` (str): Logger identifier
|
|
92
|
+
- `masked` (bool): Enable automatic masking (default: True)
|
|
93
|
+
|
|
94
|
+
**Returns:** `BaseLogger` instance
|
|
95
|
+
|
|
96
|
+
### `mask_sensitive_data(text: str) -> str`
|
|
97
|
+
Manually masks sensitive patterns in text.
|
|
98
|
+
|
|
99
|
+
**Patterns Masked:**
|
|
100
|
+
- API keys (sk-*, pk-*)
|
|
101
|
+
- Bearer tokens
|
|
102
|
+
- AWS credentials
|
|
103
|
+
- Passwords
|
|
104
|
+
- Credit card numbers
|
|
105
|
+
- Social security numbers
|
|
106
|
+
- Email addresses (partial)
|
|
107
|
+
|
|
108
|
+
### Logger Methods
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
logger.info(msg, **kwargs) # Info level
|
|
112
|
+
logger.error(msg, **kwargs) # Error level
|
|
113
|
+
logger.debug(msg, **kwargs) # Debug level
|
|
114
|
+
logger.warning(msg, **kwargs) # Warning level
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Configuration
|
|
118
|
+
|
|
119
|
+
### Global Masking Control
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from kavach_logger import LoggerManager
|
|
123
|
+
|
|
124
|
+
# Disable masking for all loggers
|
|
125
|
+
LoggerManager.disable_masking()
|
|
126
|
+
|
|
127
|
+
# Re-enable masking
|
|
128
|
+
LoggerManager.enable_masking()
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Examples
|
|
132
|
+
|
|
133
|
+
### Logging with Structured Data
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
logger = get_logger("security")
|
|
137
|
+
|
|
138
|
+
logger.info(
|
|
139
|
+
"Security event detected",
|
|
140
|
+
event_type="login",
|
|
141
|
+
user_id="user123",
|
|
142
|
+
token="sk-abc123xyz"
|
|
143
|
+
)
|
|
144
|
+
# Automatically masks the token
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Processing Sensitive Logs
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from kavach_logger import mask_sensitive_data
|
|
151
|
+
|
|
152
|
+
logs = [
|
|
153
|
+
"User created with password: MyPass123!",
|
|
154
|
+
"API call to https://api.example.com?token=abc123"
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
for log in logs:
|
|
158
|
+
safe_log = mask_sensitive_data(log)
|
|
159
|
+
print(safe_log) # Safe to output/store
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Use Cases
|
|
163
|
+
|
|
164
|
+
- **Security Auditing** - Track security events without exposing credentials
|
|
165
|
+
- **PCI/HIPAA Compliance** - Automatic redaction for sensitive logs
|
|
166
|
+
- **Agent Logging** - Mask AI-generated content containing API keys/tokens
|
|
167
|
+
- **Production Debugging** - Safe log output in production environments
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
MIT License
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
from .base_logger import BaseLogger
|
|
2
|
+
from .default_logger import DefaultLogger, MaskedLogger
|
|
3
|
+
from .logger_manager import LoggerManager, get_logger, set_custom_logger, mask_sensitive_data
|
|
4
|
+
|
|
5
|
+
__version__ = "0.1.0"
|
|
6
|
+
__all__ = ["BaseLogger", "DefaultLogger", "MaskedLogger", "LoggerManager", "get_logger", "set_custom_logger", "mask_sensitive_data"]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class BaseLogger:
|
|
2
|
+
def info(self, msg, **kwargs):
|
|
3
|
+
raise NotImplementedError
|
|
4
|
+
|
|
5
|
+
def error(self, msg, **kwargs):
|
|
6
|
+
raise NotImplementedError
|
|
7
|
+
|
|
8
|
+
def debug(self, msg, **kwargs):
|
|
9
|
+
raise NotImplementedError
|
|
10
|
+
|
|
11
|
+
def warning(self, msg, **kwargs):
|
|
12
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import re
|
|
3
|
+
from .base_logger import BaseLogger
|
|
4
|
+
|
|
5
|
+
class DefaultLogger(BaseLogger):
|
|
6
|
+
def __init__(self, name="kavach", level=logging.INFO):
|
|
7
|
+
self.logger = logging.getLogger(name)
|
|
8
|
+
self.logger.setLevel(level)
|
|
9
|
+
self.logger.propagate = False
|
|
10
|
+
|
|
11
|
+
if not self.logger.handlers:
|
|
12
|
+
handler = logging.StreamHandler()
|
|
13
|
+
formatter = logging.Formatter("[%(levelname)s] %(asctime)s | %(message)s", datefmt="%H:%M:%S")
|
|
14
|
+
handler.setFormatter(formatter)
|
|
15
|
+
self.logger.addHandler(handler)
|
|
16
|
+
|
|
17
|
+
def info(self, msg, **kwargs):
|
|
18
|
+
if kwargs:
|
|
19
|
+
msg = f"{msg} | {kwargs}"
|
|
20
|
+
self.logger.info(msg)
|
|
21
|
+
|
|
22
|
+
def error(self, msg, **kwargs):
|
|
23
|
+
if kwargs:
|
|
24
|
+
msg = f"{msg} | {kwargs}"
|
|
25
|
+
self.logger.error(msg)
|
|
26
|
+
|
|
27
|
+
def debug(self, msg, **kwargs):
|
|
28
|
+
if kwargs:
|
|
29
|
+
msg = f"{msg} | {kwargs}"
|
|
30
|
+
self.logger.debug(msg)
|
|
31
|
+
|
|
32
|
+
def warning(self, msg, **kwargs):
|
|
33
|
+
if kwargs:
|
|
34
|
+
msg = f"{msg} | {kwargs}"
|
|
35
|
+
self.logger.warning(msg)
|
|
36
|
+
|
|
37
|
+
class MaskedLogger(DefaultLogger):
|
|
38
|
+
def __init__(self, name="kavach", level=logging.INFO, enable_masking=True):
|
|
39
|
+
super().__init__(name, level)
|
|
40
|
+
self.enable_masking = enable_masking
|
|
41
|
+
|
|
42
|
+
def _mask_sensitive(self, text: str) -> str:
|
|
43
|
+
if not self.enable_masking or not isinstance(text, str):
|
|
44
|
+
return text
|
|
45
|
+
text = re.sub(r'(AKIA|sk-|api[_-]?key)[^\s]{10,}', r'\1***', text, flags=re.I)
|
|
46
|
+
text = re.sub(r'(bearer|token)[=:\s]+[^\s]{10,}', r'\1 ***', text, flags=re.I)
|
|
47
|
+
text = re.sub(r'\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b', '****-****-****-****', text)
|
|
48
|
+
text = re.sub(r'(password|passwd)[=:\s]+[^\s,}]+', r'\1=***', text, flags=re.I)
|
|
49
|
+
text = re.sub(r'(access_key|secret)[=:\s]+[^\s,}]+', r'\1=***', text, flags=re.I)
|
|
50
|
+
return text
|
|
51
|
+
|
|
52
|
+
def info(self, msg, **kwargs):
|
|
53
|
+
msg = self._mask_sensitive(str(msg))
|
|
54
|
+
super().info(msg, **kwargs)
|
|
55
|
+
|
|
56
|
+
def error(self, msg, **kwargs):
|
|
57
|
+
msg = self._mask_sensitive(str(msg))
|
|
58
|
+
super().error(msg, **kwargs)
|
|
59
|
+
|
|
60
|
+
def debug(self, msg, **kwargs):
|
|
61
|
+
msg = self._mask_sensitive(str(msg))
|
|
62
|
+
super().debug(msg, **kwargs)
|
|
63
|
+
|
|
64
|
+
def warning(self, msg, **kwargs):
|
|
65
|
+
msg = self._mask_sensitive(str(msg))
|
|
66
|
+
super().warning(msg, **kwargs)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from .base_logger import BaseLogger
|
|
2
|
+
from .default_logger import DefaultLogger, MaskedLogger
|
|
3
|
+
|
|
4
|
+
class LoggerManager:
|
|
5
|
+
_instance = None
|
|
6
|
+
_logger: BaseLogger = None
|
|
7
|
+
|
|
8
|
+
def __new__(cls):
|
|
9
|
+
if cls._instance is None:
|
|
10
|
+
cls._instance = super(LoggerManager, cls).__new__(cls)
|
|
11
|
+
return cls._instance
|
|
12
|
+
|
|
13
|
+
def set_logger(self, logger: BaseLogger):
|
|
14
|
+
self._logger = logger
|
|
15
|
+
|
|
16
|
+
def get_logger(self, masked: bool = True):
|
|
17
|
+
if self._logger is None:
|
|
18
|
+
self._logger = MaskedLogger() if masked else DefaultLogger()
|
|
19
|
+
return self._logger
|
|
20
|
+
|
|
21
|
+
_manager = LoggerManager()
|
|
22
|
+
|
|
23
|
+
def get_logger(name: str = "kavach", masked: bool = True) -> BaseLogger:
|
|
24
|
+
"""Get logger instance. Use masked=True for automatic sensitive data masking."""
|
|
25
|
+
logger = MaskedLogger(name) if masked else DefaultLogger(name)
|
|
26
|
+
return logger
|
|
27
|
+
|
|
28
|
+
def set_custom_logger(logger: BaseLogger):
|
|
29
|
+
"""Override default logger with custom implementation."""
|
|
30
|
+
_manager.set_logger(logger)
|
|
31
|
+
|
|
32
|
+
def mask_sensitive_data(text: str) -> str:
|
|
33
|
+
"""Utility to mask sensitive data."""
|
|
34
|
+
logger = MaskedLogger()
|
|
35
|
+
return logger._mask_sensitive(text)
|
|
36
|
+
|
|
37
|
+
def info(self, msg, **kwargs):
|
|
38
|
+
msg = self._mask_sensitive(str(msg))
|
|
39
|
+
super().info(msg, **kwargs)
|
|
40
|
+
|
|
41
|
+
def error(self, msg, **kwargs):
|
|
42
|
+
msg = self._mask_sensitive(str(msg))
|
|
43
|
+
super().error(msg, **kwargs)
|
|
44
|
+
|
|
45
|
+
def debug(self, msg, **kwargs):
|
|
46
|
+
msg = self._mask_sensitive(str(msg))
|
|
47
|
+
super().debug(msg, **kwargs)
|
|
48
|
+
|
|
49
|
+
def warning(self, msg, **kwargs):
|
|
50
|
+
msg = self._mask_sensitive(str(msg))
|
|
51
|
+
super().warning(msg, **kwargs)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
_logging_enabled = True
|
|
5
|
+
_masking_enabled = True
|
|
6
|
+
|
|
7
|
+
class LoggingFilter(logging.Filter):
|
|
8
|
+
def filter(self, record):
|
|
9
|
+
return _logging_enabled
|
|
10
|
+
|
|
11
|
+
def enable_logging(enabled: bool = True):
|
|
12
|
+
global _logging_enabled
|
|
13
|
+
_logging_enabled = enabled
|
|
14
|
+
|
|
15
|
+
def enable_masking(enabled: bool = True):
|
|
16
|
+
global _masking_enabled
|
|
17
|
+
_masking_enabled = enabled
|
|
18
|
+
|
|
19
|
+
def is_logging_enabled() -> bool:
|
|
20
|
+
return _logging_enabled
|
|
21
|
+
|
|
22
|
+
def is_masking_enabled() -> bool:
|
|
23
|
+
return _masking_enabled
|
|
24
|
+
|
|
25
|
+
def mask_sensitive_data(text: str) -> str:
|
|
26
|
+
if not _masking_enabled or not isinstance(text, str):
|
|
27
|
+
return text
|
|
28
|
+
text = re.sub(r'(AKIA|sk-|api[_-]?key)[^\s]{10,}', r'\1***', text, flags=re.I)
|
|
29
|
+
text = re.sub(r'(bearer|token)[=:\s]+[^\s]{10,}', r'\1 ***', text, flags=re.I)
|
|
30
|
+
text = re.sub(r'\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b', '****-****-****-****', text)
|
|
31
|
+
text = re.sub(r'(password|passwd)[=:\s]+[^\s,}]+', r'\1=***', text, flags=re.I)
|
|
32
|
+
text = re.sub(r'(access_key|secret)[=:\s]+[^\s,}]+', r'\1=***', text, flags=re.I)
|
|
33
|
+
return text
|
|
34
|
+
|
|
35
|
+
def get_logger(name: str = "kavach") -> logging.Logger:
|
|
36
|
+
logger = logging.getLogger(name)
|
|
37
|
+
if not logger.handlers:
|
|
38
|
+
logger.setLevel(logging.DEBUG)
|
|
39
|
+
logger.propagate = False
|
|
40
|
+
handler = logging.StreamHandler()
|
|
41
|
+
handler.addFilter(LoggingFilter())
|
|
42
|
+
formatter = logging.Formatter("[%(levelname)s] %(asctime)s | %(message)s", datefmt="%H:%M:%S")
|
|
43
|
+
handler.setFormatter(formatter)
|
|
44
|
+
logger.addHandler(handler)
|
|
45
|
+
return logger
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kavach-logger
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Centralized logging and masking for Kavach security suite
|
|
5
|
+
Home-page: https://github.com/shivamnamdeo0101/kavach-agent-ecosystem
|
|
6
|
+
Author: Shivam Namdeo
|
|
7
|
+
Author-email: shivamnamdeo0101@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Requires-Python: >=3.7
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Dynamic: author
|
|
12
|
+
Dynamic: author-email
|
|
13
|
+
Dynamic: description
|
|
14
|
+
Dynamic: description-content-type
|
|
15
|
+
Dynamic: home-page
|
|
16
|
+
Dynamic: license
|
|
17
|
+
Dynamic: requires-python
|
|
18
|
+
Dynamic: summary
|
|
19
|
+
|
|
20
|
+
# Kavach Logger
|
|
21
|
+
|
|
22
|
+
Centralized logging with automatic sensitive data masking for security-critical applications.
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
✅ **Automatic Data Masking** - Detects and redacts API keys, tokens, PII, passwords, and other sensitive information
|
|
27
|
+
✅ **Pluggable Implementations** - Switch between masked/plain loggers or implement custom backends
|
|
28
|
+
✅ **Structured Logging** - JSON-compatible log output with **kwargs support
|
|
29
|
+
✅ **Singleton Logger Manager** - Unified logger lifecycle management
|
|
30
|
+
✅ **Zero Dependencies** - No external requirements
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install kavach-logger
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
### Basic Usage - Auto-Masking
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from kavach_logger import get_logger
|
|
44
|
+
|
|
45
|
+
# Creates a masked logger (auto-masks sensitive data)
|
|
46
|
+
logger = get_logger("myapp")
|
|
47
|
+
logger.info("API Key: sk-1234567890")
|
|
48
|
+
# Output: API Key: sk-***
|
|
49
|
+
logger.error("Password: secret123")
|
|
50
|
+
# Output: Password: ***
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Plain Logger (No Masking)
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from kavach_logger import get_logger
|
|
57
|
+
|
|
58
|
+
logger = get_logger("myapp", masked=False)
|
|
59
|
+
logger.info("Debug: token=abc123")
|
|
60
|
+
# Output: Debug: token=abc123 (unmodified)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Manual Data Masking
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from kavach_logger import mask_sensitive_data
|
|
67
|
+
|
|
68
|
+
data = "credit_card=4532123456789012"
|
|
69
|
+
masked = mask_sensitive_data(data)
|
|
70
|
+
print(masked) # credit_card=****
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Custom Logger Implementation
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from kavach_logger import BaseLogger, DefaultLogger
|
|
77
|
+
|
|
78
|
+
class CustomLogger(DefaultLogger):
|
|
79
|
+
def info(self, msg, **kwargs):
|
|
80
|
+
msg = f"[CUSTOM] {msg}"
|
|
81
|
+
super().info(msg, **kwargs)
|
|
82
|
+
|
|
83
|
+
custom = CustomLogger()
|
|
84
|
+
custom.info("Custom implementation!")
|
|
85
|
+
# Output: [CUSTOM] Custom implementation!
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Logger Manager (Singleton)
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from kavach_logger import LoggerManager
|
|
92
|
+
|
|
93
|
+
# Get or create logger
|
|
94
|
+
logger1 = LoggerManager.get_logger("app", masked=True)
|
|
95
|
+
logger2 = LoggerManager.get_logger("app") # Returns same instance
|
|
96
|
+
|
|
97
|
+
# Control all loggers
|
|
98
|
+
LoggerManager.enable_all()
|
|
99
|
+
LoggerManager.disable_all()
|
|
100
|
+
LoggerManager.enable_masking() # Enable masking globally
|
|
101
|
+
LoggerManager.disable_masking() # Disable masking globally
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## API Reference
|
|
105
|
+
|
|
106
|
+
### `get_logger(name: str, masked: bool = True) -> BaseLogger`
|
|
107
|
+
Creates or retrieves a logger instance.
|
|
108
|
+
|
|
109
|
+
**Parameters:**
|
|
110
|
+
- `name` (str): Logger identifier
|
|
111
|
+
- `masked` (bool): Enable automatic masking (default: True)
|
|
112
|
+
|
|
113
|
+
**Returns:** `BaseLogger` instance
|
|
114
|
+
|
|
115
|
+
### `mask_sensitive_data(text: str) -> str`
|
|
116
|
+
Manually masks sensitive patterns in text.
|
|
117
|
+
|
|
118
|
+
**Patterns Masked:**
|
|
119
|
+
- API keys (sk-*, pk-*)
|
|
120
|
+
- Bearer tokens
|
|
121
|
+
- AWS credentials
|
|
122
|
+
- Passwords
|
|
123
|
+
- Credit card numbers
|
|
124
|
+
- Social security numbers
|
|
125
|
+
- Email addresses (partial)
|
|
126
|
+
|
|
127
|
+
### Logger Methods
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
logger.info(msg, **kwargs) # Info level
|
|
131
|
+
logger.error(msg, **kwargs) # Error level
|
|
132
|
+
logger.debug(msg, **kwargs) # Debug level
|
|
133
|
+
logger.warning(msg, **kwargs) # Warning level
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Configuration
|
|
137
|
+
|
|
138
|
+
### Global Masking Control
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from kavach_logger import LoggerManager
|
|
142
|
+
|
|
143
|
+
# Disable masking for all loggers
|
|
144
|
+
LoggerManager.disable_masking()
|
|
145
|
+
|
|
146
|
+
# Re-enable masking
|
|
147
|
+
LoggerManager.enable_masking()
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Examples
|
|
151
|
+
|
|
152
|
+
### Logging with Structured Data
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
logger = get_logger("security")
|
|
156
|
+
|
|
157
|
+
logger.info(
|
|
158
|
+
"Security event detected",
|
|
159
|
+
event_type="login",
|
|
160
|
+
user_id="user123",
|
|
161
|
+
token="sk-abc123xyz"
|
|
162
|
+
)
|
|
163
|
+
# Automatically masks the token
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Processing Sensitive Logs
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
from kavach_logger import mask_sensitive_data
|
|
170
|
+
|
|
171
|
+
logs = [
|
|
172
|
+
"User created with password: MyPass123!",
|
|
173
|
+
"API call to https://api.example.com?token=abc123"
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
for log in logs:
|
|
177
|
+
safe_log = mask_sensitive_data(log)
|
|
178
|
+
print(safe_log) # Safe to output/store
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Use Cases
|
|
182
|
+
|
|
183
|
+
- **Security Auditing** - Track security events without exposing credentials
|
|
184
|
+
- **PCI/HIPAA Compliance** - Automatic redaction for sensitive logs
|
|
185
|
+
- **Agent Logging** - Mask AI-generated content containing API keys/tokens
|
|
186
|
+
- **Production Debugging** - Safe log output in production environments
|
|
187
|
+
|
|
188
|
+
## License
|
|
189
|
+
|
|
190
|
+
MIT License
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
kavach_logger/__init__.py
|
|
4
|
+
kavach_logger/base_logger.py
|
|
5
|
+
kavach_logger/default_logger.py
|
|
6
|
+
kavach_logger/logger_manager.py
|
|
7
|
+
kavach_logger/setup.py
|
|
8
|
+
kavach_logger.egg-info/PKG-INFO
|
|
9
|
+
kavach_logger.egg-info/SOURCES.txt
|
|
10
|
+
kavach_logger.egg-info/dependency_links.txt
|
|
11
|
+
kavach_logger.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
kavach_logger
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="kavach-logger",
|
|
8
|
+
version="0.0.1",
|
|
9
|
+
description="Centralized logging and masking for Kavach security suite",
|
|
10
|
+
long_description=long_description,
|
|
11
|
+
long_description_content_type="text/markdown",
|
|
12
|
+
author="Shivam Namdeo",
|
|
13
|
+
author_email="shivamnamdeo0101@gmail.com",
|
|
14
|
+
url="https://github.com/shivamnamdeo0101/kavach-agent-ecosystem",
|
|
15
|
+
license="MIT",
|
|
16
|
+
packages=find_packages(),
|
|
17
|
+
python_requires=">=3.7",
|
|
18
|
+
install_requires=[],
|
|
19
|
+
)
|