secploy 0.2.4__tar.gz → 0.2.6__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.
Files changed (30) hide show
  1. {secploy-0.2.4 → secploy-0.2.6}/PKG-INFO +154 -31
  2. secploy-0.2.4/secploy.egg-info/PKG-INFO → secploy-0.2.6/README.md +130 -37
  3. secploy-0.2.6/secploy/__init__.py +47 -0
  4. secploy-0.2.6/secploy/client.py +166 -0
  5. {secploy-0.2.4 → secploy-0.2.6}/secploy/enums.py +2 -1
  6. secploy-0.2.6/secploy/events.py +40 -0
  7. secploy-0.2.6/secploy/lib/__init__.py +11 -0
  8. secploy-0.2.6/secploy/lib/config.py +204 -0
  9. secploy-0.2.6/secploy/lib/secploy_logger.py +45 -0
  10. secploy-0.2.6/secploy/log_capture.py +169 -0
  11. secploy-0.2.6/secploy/processor.py +120 -0
  12. secploy-0.2.6/secploy/schemas.py +49 -0
  13. secploy-0.2.4/README.md → secploy-0.2.6/secploy.egg-info/PKG-INFO +160 -4
  14. {secploy-0.2.4 → secploy-0.2.6}/secploy.egg-info/SOURCES.txt +9 -11
  15. secploy-0.2.6/secploy.egg-info/entry_points.txt +2 -0
  16. secploy-0.2.6/secploy.egg-info/requires.txt +3 -0
  17. secploy-0.2.6/setup.py +33 -0
  18. secploy-0.2.4/pyproject.toml +0 -19
  19. secploy-0.2.4/secploy/__init__.py +0 -7
  20. secploy-0.2.4/secploy/client.py +0 -210
  21. secploy-0.2.4/secploy/schema.py +0 -0
  22. secploy-0.2.4/secploy/schemas.py +0 -20
  23. secploy-0.2.4/secploy/utils.py +0 -5
  24. secploy-0.2.4/secploy.egg-info/requires.txt +0 -1
  25. {secploy-0.2.4 → secploy-0.2.6}/LICENSE +0 -0
  26. {secploy-0.2.4 → secploy-0.2.6}/MANIFEST.in +0 -0
  27. /secploy-0.2.4/secploy/exceptions.py → /secploy-0.2.6/secploy/utils.py +0 -0
  28. {secploy-0.2.4 → secploy-0.2.6}/secploy.egg-info/dependency_links.txt +0 -0
  29. {secploy-0.2.4 → secploy-0.2.6}/secploy.egg-info/top_level.txt +0 -0
  30. {secploy-0.2.4 → secploy-0.2.6}/setup.cfg +0 -0
@@ -1,35 +1,32 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: secploy
3
- Version: 0.2.4
4
- Summary: Python SDK for Secploy security monitoring and event tracking
5
- Author-email: Abdulsamad Abdulganiyu <agastronics@gmail.com>
6
- License: MIT License
7
-
8
- Copyright (c) 2025 AGASTRONICS
9
-
10
- Permission is hereby granted, free of charge, to any person obtaining a copy
11
- of this software and associated documentation files (the "Software"), to deal
12
- in the Software without restriction, including without limitation the rights
13
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- copies of the Software, and to permit persons to whom the Software is
15
- furnished to do so, subject to the following conditions:
16
-
17
- The above copyright notice and this permission notice shall be included in all
18
- copies or substantial portions of the Software.
19
-
20
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- SOFTWARE.
27
-
28
- Requires-Python: >=3.7
3
+ Version: 0.2.6
4
+ Summary: Event tracking and monitoring SDK for Python applications
5
+ Home-page: https://github.com/agastronics/secploy-python-sdk
6
+ Author: Agastronics
7
+ Author-email: support@agastronics.com
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.8
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
29
16
  Description-Content-Type: text/markdown
30
17
  License-File: LICENSE
31
- Requires-Dist: requests>=2.20.0
18
+ Requires-Dist: requests>=2.25.0
19
+ Requires-Dist: pyyaml>=5.1
20
+ Requires-Dist: pydantic>=2.0.0
21
+ Dynamic: author
22
+ Dynamic: author-email
23
+ Dynamic: classifier
24
+ Dynamic: description
25
+ Dynamic: description-content-type
26
+ Dynamic: home-page
32
27
  Dynamic: license-file
28
+ Dynamic: requires-dist
29
+ Dynamic: summary
33
30
 
34
31
  <p align="center">
35
32
  <img src="https://secploy.vercel.app/logo.png" alt="Secploy Logo" width="180">
@@ -59,26 +56,31 @@ The Secploy SDK can be configured in multiple ways, providing flexibility for di
59
56
  client = SecployClient()
60
57
 
61
58
  config = SecployConfig(
62
- api_key="your-key",
59
+ api_key="your-project-key",
60
+ environment_key="your-key"
61
+ organization_id="your-organization-id",
63
62
  environment="production",
64
63
  log_level=LogLevel.INFO,
65
64
  batch_size=100
66
65
  )
67
66
 
68
67
  client = SecployClient(config=config)
69
- ```
68
+ ```
70
69
 
71
70
  2. **Configuration file** (.secploy or project-name.secploy)
72
71
 
73
72
  ```yaml
74
- api_key: your-api-key
73
+ api_key: your-project-api-key
74
+ environment_key: key
75
+ organization_id: "your-organization-id",
75
76
  environment: production
76
77
  debug: true
77
- ````
78
+ ```
78
79
 
79
80
  3. **Environment variables**
80
81
  ```bash
81
82
  export SECPLOY_API_KEY=your-api-key
83
+ export SECPLOY_ORGANIZATION_ID=your-organization-id
82
84
  export SECPLOY_ENVIRONMENT=production
83
85
  export SECPLOY_DEBUG=true
84
86
  ```
@@ -88,6 +90,7 @@ debug: true
88
90
  | Option | Type | Default | Description |
89
91
  | -------------------- | ---------------- | --------------------------- | ----------------------------------------------------- |
90
92
  | `api_key` | `str` | Required | Your Secploy project API key |
93
+ | `environment_key` | `str` | Required | Your Secploy environment API key |
91
94
  | `environment` | `str` | `"development"` | Environment name (e.g., production, staging) |
92
95
  | `ingest_url` | `str` | `"https://api.secploy.com"` | Secploy API endpoint |
93
96
  | `heartbeat_interval` | `int` | `30` | Seconds between heartbeat signals |
@@ -109,6 +112,7 @@ Create a `.secploy` file in your project root:
109
112
  ```yaml
110
113
  # Required settings
111
114
  api_key: your-api-key
115
+ environment_key: key
112
116
  environment: production
113
117
 
114
118
  # Event batching
@@ -139,6 +143,7 @@ All configuration options can be set via environment variables with the `SECPLOY
139
143
  ```bash
140
144
  # Required settings
141
145
  SECPLOY_API_KEY=your-api-key
146
+ SECPLOY_ENVIRONMENT_KEY=key
142
147
  SECPLOY_ENVIRONMENT=production
143
148
 
144
149
  # Event batching
@@ -286,6 +291,124 @@ Each environment has its own **API key** — use the matching key for the enviro
286
291
  | `heartbeat()` | Send a heartbeat signal |
287
292
  | `listen_status()` | Stream live project status |
288
293
  | `set_environment(env_code)` | Switch environment dynamically |
294
+ | `capture_logs(loggers, level)` | Start capturing logs |
295
+ | `stop_capturing_logs(loggers)` | Stop capturing specific logs |
296
+
297
+ ## 📝 Structured Logging
298
+
299
+ Secploy provides powerful structured logging capabilities that automatically format and send your logs with rich context.
300
+
301
+ ### Basic Log Capture
302
+
303
+ ```python
304
+ import logging
305
+ from secploy import SecployClient
306
+
307
+ # Initialize client
308
+ client = SecployClient()
309
+ client.start()
310
+
311
+ # Start capturing logs
312
+ client.capture_logs(['your_app'], level=logging.INFO)
313
+
314
+ # Your regular logging calls will now be captured
315
+ logger = logging.getLogger('your_app')
316
+ logger.info("User logged in", extra={
317
+ 'user_id': 'user123',
318
+ 'login_method': 'oauth'
319
+ })
320
+ ```
321
+
322
+ ### Log Schema
323
+
324
+ All captured logs are automatically structured in a consistent format:
325
+
326
+ ```json
327
+ {
328
+ "timestamp": "2025-09-13T16:45:00Z",
329
+ "type": "error",
330
+ "message": "Unhandled exception in payment processor",
331
+ "context": {
332
+ "user_id": "usr_12345",
333
+ "session_id": "sess_abcd",
334
+ "http_method": "POST",
335
+ "http_url": "/api/payments/charge",
336
+ "http_status": 500,
337
+ "stacktrace": [
338
+ "File \"payment_service.py\", line 42, in process_charge",
339
+ "File \"stripe_gateway.py\", line 87, in create_charge",
340
+ "Exception: Card declined"
341
+ ],
342
+ "tags": {
343
+ "environment": "production",
344
+ "service": "payments",
345
+ "region": "us-east-1"
346
+ }
347
+ }
348
+ }
349
+ ```
350
+
351
+ ### Example with Flask Application
352
+
353
+ ```python
354
+ import logging
355
+ from flask import Flask, request
356
+ from secploy import SecployClient
357
+
358
+ # Set up logging
359
+ logger = logging.getLogger(__name__)
360
+
361
+ # Initialize Flask and Secploy
362
+ app = Flask(__name__)
363
+ client = SecployClient()
364
+ client.start()
365
+
366
+ # Capture logs from all components
367
+ client.capture_logs([
368
+ 'flask.app', # Flask framework logs
369
+ __name__, # Main application logs
370
+ 'payment_processor' # Component-specific logs
371
+ ], level=logging.INFO)
372
+
373
+ @app.route('/api/payment', methods=['POST'])
374
+ def process_payment():
375
+ try:
376
+ data = request.json
377
+ logger.info("Processing payment", extra={
378
+ 'user_id': data.get('user_id'),
379
+ 'http_method': request.method,
380
+ 'http_url': request.path,
381
+ 'amount': data.get('amount')
382
+ })
383
+ # Process payment...
384
+ return {"status": "success"}, 200
385
+ except Exception as e:
386
+ logger.error(
387
+ "Payment failed",
388
+ exc_info=True, # This captures the stack trace
389
+ extra={
390
+ 'user_id': data.get('user_id'),
391
+ 'http_method': request.method,
392
+ 'http_url': request.path,
393
+ 'http_status': 500
394
+ }
395
+ )
396
+ return {"error": str(e)}, 500
397
+
398
+ if __name__ == '__main__':
399
+ try:
400
+ app.run()
401
+ finally:
402
+ client.stop()
403
+ ```
404
+
405
+ ### Best Practices for Logging
406
+
407
+ 1. **Add Context**: Always include relevant context using the `extra` parameter
408
+ 2. **Use Proper Log Levels**: Choose appropriate levels (DEBUG, INFO, WARNING, ERROR)
409
+ 3. **Include Stack Traces**: Use `exc_info=True` when logging exceptions
410
+ 4. **Capture All Components**: Include all relevant loggers in your capture list
411
+ 5. **Start Early, Stop Late**: Initialize logging before your app starts and stop it in a finally block
289
412
 
290
413
  ---
291
414
 
@@ -1,36 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: secploy
3
- Version: 0.2.4
4
- Summary: Python SDK for Secploy security monitoring and event tracking
5
- Author-email: Abdulsamad Abdulganiyu <agastronics@gmail.com>
6
- License: MIT License
7
-
8
- Copyright (c) 2025 AGASTRONICS
9
-
10
- Permission is hereby granted, free of charge, to any person obtaining a copy
11
- of this software and associated documentation files (the "Software"), to deal
12
- in the Software without restriction, including without limitation the rights
13
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- copies of the Software, and to permit persons to whom the Software is
15
- furnished to do so, subject to the following conditions:
16
-
17
- The above copyright notice and this permission notice shall be included in all
18
- copies or substantial portions of the Software.
19
-
20
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- SOFTWARE.
27
-
28
- Requires-Python: >=3.7
29
- Description-Content-Type: text/markdown
30
- License-File: LICENSE
31
- Requires-Dist: requests>=2.20.0
32
- Dynamic: license-file
33
-
34
1
  <p align="center">
35
2
  <img src="https://secploy.vercel.app/logo.png" alt="Secploy Logo" width="180">
36
3
  </p>
@@ -59,26 +26,31 @@ The Secploy SDK can be configured in multiple ways, providing flexibility for di
59
26
  client = SecployClient()
60
27
 
61
28
  config = SecployConfig(
62
- api_key="your-key",
29
+ api_key="your-project-key",
30
+ environment_key="your-key"
31
+ organization_id="your-organization-id",
63
32
  environment="production",
64
33
  log_level=LogLevel.INFO,
65
34
  batch_size=100
66
35
  )
67
36
 
68
37
  client = SecployClient(config=config)
69
- ```
38
+ ```
70
39
 
71
40
  2. **Configuration file** (.secploy or project-name.secploy)
72
41
 
73
42
  ```yaml
74
- api_key: your-api-key
43
+ api_key: your-project-api-key
44
+ environment_key: key
45
+ organization_id: "your-organization-id",
75
46
  environment: production
76
47
  debug: true
77
- ````
48
+ ```
78
49
 
79
50
  3. **Environment variables**
80
51
  ```bash
81
52
  export SECPLOY_API_KEY=your-api-key
53
+ export SECPLOY_ORGANIZATION_ID=your-organization-id
82
54
  export SECPLOY_ENVIRONMENT=production
83
55
  export SECPLOY_DEBUG=true
84
56
  ```
@@ -88,6 +60,7 @@ debug: true
88
60
  | Option | Type | Default | Description |
89
61
  | -------------------- | ---------------- | --------------------------- | ----------------------------------------------------- |
90
62
  | `api_key` | `str` | Required | Your Secploy project API key |
63
+ | `environment_key` | `str` | Required | Your Secploy environment API key |
91
64
  | `environment` | `str` | `"development"` | Environment name (e.g., production, staging) |
92
65
  | `ingest_url` | `str` | `"https://api.secploy.com"` | Secploy API endpoint |
93
66
  | `heartbeat_interval` | `int` | `30` | Seconds between heartbeat signals |
@@ -109,6 +82,7 @@ Create a `.secploy` file in your project root:
109
82
  ```yaml
110
83
  # Required settings
111
84
  api_key: your-api-key
85
+ environment_key: key
112
86
  environment: production
113
87
 
114
88
  # Event batching
@@ -139,6 +113,7 @@ All configuration options can be set via environment variables with the `SECPLOY
139
113
  ```bash
140
114
  # Required settings
141
115
  SECPLOY_API_KEY=your-api-key
116
+ SECPLOY_ENVIRONMENT_KEY=key
142
117
  SECPLOY_ENVIRONMENT=production
143
118
 
144
119
  # Event batching
@@ -286,6 +261,124 @@ Each environment has its own **API key** — use the matching key for the enviro
286
261
  | `heartbeat()` | Send a heartbeat signal |
287
262
  | `listen_status()` | Stream live project status |
288
263
  | `set_environment(env_code)` | Switch environment dynamically |
264
+ | `capture_logs(loggers, level)` | Start capturing logs |
265
+ | `stop_capturing_logs(loggers)` | Stop capturing specific logs |
266
+
267
+ ## 📝 Structured Logging
268
+
269
+ Secploy provides powerful structured logging capabilities that automatically format and send your logs with rich context.
270
+
271
+ ### Basic Log Capture
272
+
273
+ ```python
274
+ import logging
275
+ from secploy import SecployClient
276
+
277
+ # Initialize client
278
+ client = SecployClient()
279
+ client.start()
280
+
281
+ # Start capturing logs
282
+ client.capture_logs(['your_app'], level=logging.INFO)
283
+
284
+ # Your regular logging calls will now be captured
285
+ logger = logging.getLogger('your_app')
286
+ logger.info("User logged in", extra={
287
+ 'user_id': 'user123',
288
+ 'login_method': 'oauth'
289
+ })
290
+ ```
291
+
292
+ ### Log Schema
293
+
294
+ All captured logs are automatically structured in a consistent format:
295
+
296
+ ```json
297
+ {
298
+ "timestamp": "2025-09-13T16:45:00Z",
299
+ "type": "error",
300
+ "message": "Unhandled exception in payment processor",
301
+ "context": {
302
+ "user_id": "usr_12345",
303
+ "session_id": "sess_abcd",
304
+ "http_method": "POST",
305
+ "http_url": "/api/payments/charge",
306
+ "http_status": 500,
307
+ "stacktrace": [
308
+ "File \"payment_service.py\", line 42, in process_charge",
309
+ "File \"stripe_gateway.py\", line 87, in create_charge",
310
+ "Exception: Card declined"
311
+ ],
312
+ "tags": {
313
+ "environment": "production",
314
+ "service": "payments",
315
+ "region": "us-east-1"
316
+ }
317
+ }
318
+ }
319
+ ```
320
+
321
+ ### Example with Flask Application
322
+
323
+ ```python
324
+ import logging
325
+ from flask import Flask, request
326
+ from secploy import SecployClient
327
+
328
+ # Set up logging
329
+ logger = logging.getLogger(__name__)
330
+
331
+ # Initialize Flask and Secploy
332
+ app = Flask(__name__)
333
+ client = SecployClient()
334
+ client.start()
335
+
336
+ # Capture logs from all components
337
+ client.capture_logs([
338
+ 'flask.app', # Flask framework logs
339
+ __name__, # Main application logs
340
+ 'payment_processor' # Component-specific logs
341
+ ], level=logging.INFO)
342
+
343
+ @app.route('/api/payment', methods=['POST'])
344
+ def process_payment():
345
+ try:
346
+ data = request.json
347
+ logger.info("Processing payment", extra={
348
+ 'user_id': data.get('user_id'),
349
+ 'http_method': request.method,
350
+ 'http_url': request.path,
351
+ 'amount': data.get('amount')
352
+ })
353
+ # Process payment...
354
+ return {"status": "success"}, 200
355
+ except Exception as e:
356
+ logger.error(
357
+ "Payment failed",
358
+ exc_info=True, # This captures the stack trace
359
+ extra={
360
+ 'user_id': data.get('user_id'),
361
+ 'http_method': request.method,
362
+ 'http_url': request.path,
363
+ 'http_status': 500
364
+ }
365
+ )
366
+ return {"error": str(e)}, 500
367
+
368
+ if __name__ == '__main__':
369
+ try:
370
+ app.run()
371
+ finally:
372
+ client.stop()
373
+ ```
374
+
375
+ ### Best Practices for Logging
376
+
377
+ 1. **Add Context**: Always include relevant context using the `extra` parameter
378
+ 2. **Use Proper Log Levels**: Choose appropriate levels (DEBUG, INFO, WARNING, ERROR)
379
+ 3. **Include Stack Traces**: Use `exc_info=True` when logging exceptions
380
+ 4. **Capture All Components**: Include all relevant loggers in your capture list
381
+ 5. **Start Early, Stop Late**: Initialize logging before your app starts and stop it in a finally block
289
382
 
290
383
  ---
291
384
 
@@ -0,0 +1,47 @@
1
+ """
2
+ Secploy SDK - Event tracking and monitoring for Python applications
3
+ """
4
+
5
+ from .client import SecployClient
6
+ from .schemas import SecployConfig
7
+ from .schemas import LogLevel
8
+
9
+ __version__ = "0.2.5"
10
+ __author__ = "Agastronics"
11
+ __email__ = "support@agastronics.com"
12
+ __description__ = "Event tracking and monitoring SDK for Python applications"
13
+
14
+ __all__ = [
15
+ "SecployClient",
16
+ "SecployConfig",
17
+ "LogLevel",
18
+ ]
19
+
20
+ def cli():
21
+ """Command-line interface for the Secploy SDK."""
22
+ import argparse
23
+
24
+ parser = argparse.ArgumentParser(description=__description__)
25
+ parser.add_argument('--version', action='version', version=f'Secploy SDK v{__version__}')
26
+ parser.add_argument('--test-config', help='Test a configuration file', metavar='CONFIG_FILE')
27
+
28
+ args = parser.parse_args()
29
+
30
+ if args.test_config:
31
+ from .lib.config import load_config
32
+ try:
33
+ config = load_config(args.test_config)
34
+ print("Configuration loaded successfully:")
35
+ for key, value in config.items():
36
+ print(f" {key}: {value}")
37
+ except Exception as e:
38
+ print(f"Error loading configuration: {e}")
39
+ return 1
40
+ else:
41
+ parser.print_help()
42
+
43
+ return 0
44
+
45
+ if __name__ == "__main__":
46
+ import sys
47
+ sys.exit(cli())
@@ -0,0 +1,166 @@
1
+ import threading
2
+ import logging
3
+ from typing import Any, Dict, Optional, List, Union
4
+ import queue
5
+
6
+ from .lib import setup_logger, load_config, DEFAULT_CONFIG, secploy_logger
7
+ from .schemas import SecployConfig, LogLevel
8
+ from .log_capture import SecployLogCapturer
9
+ from .events import EventHandler
10
+ from .processor import EventProcessor
11
+
12
+ class SecployClient:
13
+ def __init__(
14
+ self,
15
+ api_key: Optional[str] = None,
16
+ environment_key: Optional[str] = None,
17
+ organization_id: Optional[str] = None,
18
+ config_file: Optional[str] = None,
19
+ config: Optional[SecployConfig] = DEFAULT_CONFIG,
20
+ log_levels: Optional[List[Union[str, int]]] = None
21
+ ):
22
+ """
23
+ Initialize the Secploy client.
24
+
25
+ Args:
26
+ api_key: Optional API key to override configuration
27
+ environment_key: Optional Environment key to override configuration
28
+ organization_id: Optional Organization ID to override configuration
29
+ config_file: Optional path to configuration file
30
+ config: Configuration object, defaults to DEFAULT_CONFIG
31
+
32
+ Raises:
33
+ ValueError: If required configuration is missing
34
+ TypeError: If configuration values have invalid types
35
+ """
36
+ # Load config from file if provided else it will load from default locations or find .secploy
37
+ config = load_config(config_file)
38
+
39
+ if config is None:
40
+ secploy_logger.error("No valid configuration found")
41
+ return
42
+
43
+ # Override api_key if provided directly
44
+ if api_key:
45
+ config.api_key = api_key
46
+ if environment_key:
47
+ config.environment_key = environment_key
48
+ if organization_id:
49
+ config.organization_id = organization_id
50
+
51
+ # Special handling for log_level if it's a string
52
+ if isinstance(config.get('log_level'), str):
53
+ try:
54
+ config['log_level'] = LogLevel(config['log_level'].upper())
55
+ except ValueError:
56
+ raise ValueError(
57
+ f"Invalid log level: {config.get('log_level')}. Must be one of: "
58
+ f"{', '.join(level.value for level in LogLevel)}"
59
+ )
60
+
61
+ # Validate required fields
62
+ if not config.get('api_key'):
63
+ raise ValueError("API key is required")
64
+ if not config.get('environment_key'):
65
+ raise ValueError("Environment key is required")
66
+ if not config.get('organization_id'):
67
+ raise ValueError("Organization ID is required")
68
+ if not config.get('ingest_url'):
69
+ raise ValueError("Ingest URL is required")
70
+
71
+ # Set instance attributes from config
72
+ self.api_key = config['api_key']
73
+ self.environment_key = config.get('environment_key')
74
+ self.organization_id = config.get('organization_id')
75
+ self.environment = config.get('environment', 'development')
76
+ self.sampling_rate = config.get('sampling_rate', 1.0)
77
+ self.ingest_url = config['ingest_url'].rstrip("/")
78
+ self.heartbeat_interval = config.get('heartbeat_interval', 60)
79
+ self.max_retry = config.get('max_retry', 5)
80
+ self.debug = config.get('debug', False)
81
+ self.log_level = config.get('log_level', 'INFO')
82
+
83
+ # Batch processing configuration
84
+ self.batch_size = config.get('batch_size', 100) # Max events per batch
85
+ self.flush_interval = config.get('flush_interval', 60) # Max seconds between flushes
86
+
87
+ # Initialize internal state
88
+ self._event_queue = queue.Queue()
89
+ self._event_handler = EventHandler(self._event_queue)
90
+
91
+ # Initialize event processor
92
+ self._event_processor = EventProcessor(
93
+ queue=self._event_queue,
94
+ ingest_url=self.ingest_url,
95
+ headers_callback=self._headers,
96
+ batch_size=self.batch_size,
97
+ flush_interval=self.flush_interval,
98
+ max_retry=self.max_retry
99
+ )
100
+
101
+ # Setup logging
102
+ if self.debug:
103
+ setup_logger(log_level=self.log_level)
104
+
105
+ # Initialize log capturer
106
+ self._log_capturer = SecployLogCapturer(self, levels=log_levels)
107
+
108
+ def capture_logs(self, loggers: Union[str, List[str], None] = None):
109
+ """
110
+ Start capturing logs from specified loggers.
111
+
112
+ Args:
113
+ loggers: Logger name(s) to capture. Can be:
114
+ - None to capture the root logger
115
+ - A string for a single logger
116
+ - A list of logger names
117
+ """
118
+ self._log_capturer.start_capture(loggers)
119
+ secploy_logger.info(f"Started capturing logs from {loggers or 'root'}")
120
+
121
+ def stop_capturing_logs(self, loggers: Union[str, List[str], None] = None):
122
+ """
123
+ Stop capturing logs from specified loggers.
124
+
125
+ Args:
126
+ loggers: Logger name(s) to stop capturing
127
+ """
128
+ self._log_capturer.stop_capture(loggers)
129
+ secploy_logger.info(f"Stopped capturing logs from {loggers or 'root'}")
130
+
131
+ def _headers(self):
132
+ return {
133
+ "X-API-Key": f"{self.api_key}",
134
+ "X-Environment-Key": f"{self.environment_key}",
135
+ "X-Organization-ID": f"{self.organization_id}",
136
+ "Content-Type": "application/json",
137
+ }
138
+
139
+ def send_event(self, event_type: str, payload: Dict[str, Any]) -> bool:
140
+ """
141
+ Queue an event for sending. Events are batched and sent periodically.
142
+
143
+ Args:
144
+ event_type: Type of the event
145
+ payload: Event payload data
146
+
147
+ Returns:
148
+ bool: True if event was queued successfully
149
+ """
150
+ return self._event_handler.send_event(event_type, payload)
151
+
152
+ def start(self):
153
+ """Start the client's event processing."""
154
+ secploy_logger.info("Starting Secploy client...")
155
+ self._event_processor.start()
156
+
157
+ def stop(self):
158
+ """Stop the client and wait for processing to finish."""
159
+ secploy_logger.info("Stopping Secploy client...")
160
+
161
+ # Stop all log capturing
162
+ if hasattr(self, '_log_capturer'):
163
+ self._log_capturer.stop_all()
164
+
165
+ # Stop event processing
166
+ self._event_processor.stop()
@@ -6,4 +6,5 @@ class LogLevel(str, Enum):
6
6
  INFO = "INFO"
7
7
  WARNING = "WARNING"
8
8
  ERROR = "ERROR"
9
- CRITICAL = "CRITICAL"
9
+ CRITICAL = "CRITICAL"
10
+ RESET = "RESET"