gl-observability-binary 0.0.0b1__cp313-cp313-win_amd64.whl
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.
- gl_observability/__init__.pyi +4 -0
- gl_observability/backend/__init__.pyi +4 -0
- gl_observability/backend/opentelemetry/__init__.pyi +0 -0
- gl_observability/backend/opentelemetry/initializer.pyi +61 -0
- gl_observability/backend/sentry/__init__.pyi +0 -0
- gl_observability/backend/sentry/initializer.pyi +39 -0
- gl_observability/initializer.pyi +24 -0
- gl_observability/logs/__init__.pyi +0 -0
- gl_observability/logs/ner_pii_logger_handler.pyi +44 -0
- gl_observability/logs/regex_pii_logger_handler.pyi +78 -0
- gl_observability/traces/__init__.pyi +0 -0
- gl_observability/traces/opentelemetry/__init__.pyi +0 -0
- gl_observability/traces/opentelemetry/instrument/__init__.pyi +4 -0
- gl_observability/traces/opentelemetry/instrument/functions.pyi +121 -0
- gl_observability/traces/opentelemetry/instrument/http.pyi +58 -0
- gl_observability.build/.gitignore +1 -0
- gl_observability.cp313-win_amd64.pyd +0 -0
- gl_observability.pyi +55 -0
- gl_observability_binary-0.0.0b1.dist-info/METADATA +217 -0
- gl_observability_binary-0.0.0b1.dist-info/RECORD +22 -0
- gl_observability_binary-0.0.0b1.dist-info/WHEEL +5 -0
- gl_observability_binary-0.0.0b1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
from gl_observability.backend import OpenTelemetryConfig as OpenTelemetryConfig, SentryConfig as SentryConfig
|
|
2
|
+
from gl_observability.initializer import TelemetryConfig as TelemetryConfig, init_telemetry as init_telemetry
|
|
3
|
+
|
|
4
|
+
__all__ = ['OpenTelemetryConfig', 'SentryConfig', 'TelemetryConfig', 'init_telemetry']
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
from gl_observability.backend.opentelemetry.initializer import FastAPIConfig as FastAPIConfig, OpenTelemetryConfig as OpenTelemetryConfig
|
|
2
|
+
from gl_observability.backend.sentry.initializer import SentryConfig as SentryConfig
|
|
3
|
+
|
|
4
|
+
__all__ = ['OpenTelemetryConfig', 'SentryConfig', 'FastAPIConfig']
|
|
File without changes
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from _typeshed import Incomplete
|
|
2
|
+
from fastapi import FastAPI as FastAPI
|
|
3
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
4
|
+
from opentelemetry.sdk.trace.sampling import Sampler as Sampler
|
|
5
|
+
|
|
6
|
+
class FastAPIConfig:
|
|
7
|
+
"""Configuration class for FastAPI application."""
|
|
8
|
+
app: Incomplete
|
|
9
|
+
def __init__(self, app: FastAPI) -> None:
|
|
10
|
+
"""Initializes FastAPIConfig with a FastAPI application.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
app (FastAPI): The FastAPI application to configure.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
class OpenTelemetryConfig:
|
|
17
|
+
"""Configuration-based initializer for OpenTelemetry with FastAPI and Langchain support."""
|
|
18
|
+
provider: TracerProvider | None
|
|
19
|
+
endpoint: Incomplete
|
|
20
|
+
trace_sampler: Incomplete
|
|
21
|
+
headers: Incomplete
|
|
22
|
+
attributes: Incomplete
|
|
23
|
+
use_grpc: Incomplete
|
|
24
|
+
fastapi_config: Incomplete
|
|
25
|
+
use_langchain: Incomplete
|
|
26
|
+
use_httpx: Incomplete
|
|
27
|
+
use_requests: Incomplete
|
|
28
|
+
disable_sentry_distributed_tracing: Incomplete
|
|
29
|
+
def __init__(self, endpoint: str = '', trace_sampler: Sampler = None, headers: dict[str, str] = None, attributes: dict[str, str] = None, use_grpc: bool = True, fastapi_config: FastAPIConfig | None = None, use_langchain: bool = False, use_httpx: bool = True, use_requests: bool = True, disable_sentry_distributed_tracing: bool = False) -> None:
|
|
30
|
+
'''Initializes OpenTelemetryConfig with optional attributes.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
endpoint (str): The OTLP endpoint. If you have port, please concat with the endpoint, e.g. "localhost:4317".
|
|
34
|
+
trace_sampler (Sampler): The sampler for traces.
|
|
35
|
+
headers (dict[str, str]): Headers with key value for connecting to the exporter.
|
|
36
|
+
attributes (dict[str, str]): Additional resource attributes.
|
|
37
|
+
use_grpc (bool): use grpc for opentelemetry exporter.
|
|
38
|
+
fastapi_config (FastAPI | None): The FastAPI fastapi_config (if using FastAPI tracing).
|
|
39
|
+
use_langchain (bool): Whether to use Langchain tracing.
|
|
40
|
+
use_httpx (bool): Whether to use httpx for tracing.
|
|
41
|
+
use_requests (bool): Whether to use requests for tracing.
|
|
42
|
+
disable_sentry_distributed_tracing (bool): Disable Sentry distributed tracing.
|
|
43
|
+
'''
|
|
44
|
+
|
|
45
|
+
def init_otel_with_external_exporter(initializer: OpenTelemetryConfig) -> None:
|
|
46
|
+
"""Initializes OpenTelemetry with an external exporter.
|
|
47
|
+
|
|
48
|
+
This method initializes OpenTelemetry with an external exporter (OTLP)
|
|
49
|
+
and instruments FastAPI and Langchain if applicable.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
initializer (OpenTelemetryConfig): The configuration for OpenTelemetry.
|
|
53
|
+
"""
|
|
54
|
+
def init_otel_sentry(initializer: OpenTelemetryConfig) -> None:
|
|
55
|
+
"""Initializes OpenTelemetry tracing.
|
|
56
|
+
|
|
57
|
+
This method initializes OpenTelemetry with Sentry and instruments FastAPI and Langchain if applicable.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
initializer (OpenTelemetryConfig): The configuration for OpenTelemetry.
|
|
61
|
+
"""
|
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from _typeshed import Incomplete
|
|
2
|
+
from gl_observability.backend.opentelemetry.initializer import OpenTelemetryConfig as OpenTelemetryConfig, init_otel_sentry as init_otel_sentry
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
class SentryConfig:
|
|
6
|
+
"""Configuration object for Sentry initialization.
|
|
7
|
+
|
|
8
|
+
this class is used to store the configuration for Sentry initialization.
|
|
9
|
+
"""
|
|
10
|
+
dsn: Incomplete
|
|
11
|
+
environment: Incomplete
|
|
12
|
+
release: Incomplete
|
|
13
|
+
profiles_sample_rate: Incomplete
|
|
14
|
+
send_default_pii: Incomplete
|
|
15
|
+
traces_sampler: Incomplete
|
|
16
|
+
open_telemetry_config: Incomplete
|
|
17
|
+
additional_options: Incomplete
|
|
18
|
+
def __init__(self, dsn: str | None = None, environment: str | None = None, release: str | None = None, profiles_sample_rate: float | None = None, send_default_pii: bool | None = None, traces_sampler=None, open_telemetry_config: OpenTelemetryConfig | None = None, **kwargs: Any) -> None:
|
|
19
|
+
"""Initializes the Sentry configuration object with the specified parameters.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
dsn (str): The Data Source Name (DSN) for the Sentry project.
|
|
23
|
+
environment (str): The environment for the Sentry project.
|
|
24
|
+
release (str): The release version for the Sentry project.
|
|
25
|
+
profiles_sample_rate (float): The sample rate for performance monitoring.
|
|
26
|
+
send_default_pii (bool): Whether to send default Personally Identifiable Information (PII).
|
|
27
|
+
traces_sampler (TracesSampler): The sampler for traces.
|
|
28
|
+
open_telemetry_config: The OpenTelemetry Config
|
|
29
|
+
**kwargs: Additional keyword arguments to pass to sentry_sdk.init
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def init_sentry(config: SentryConfig | None = None) -> None:
|
|
33
|
+
"""Initializes Sentry for error tracking and performance monitoring.
|
|
34
|
+
|
|
35
|
+
Initializes Sentry with the specified parameters.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
config (SentryConfig | None, optional): The configuration object for Sentry initialization. Defaults to None.
|
|
39
|
+
"""
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from _typeshed import Incomplete
|
|
2
|
+
from gl_observability.backend.opentelemetry.initializer import OpenTelemetryConfig as OpenTelemetryConfig, init_otel_with_external_exporter as init_otel_with_external_exporter
|
|
3
|
+
from gl_observability.backend.sentry.initializer import SentryConfig as SentryConfig, init_sentry as init_sentry
|
|
4
|
+
|
|
5
|
+
class TelemetryConfig:
|
|
6
|
+
"""Configuration class for telemetry config."""
|
|
7
|
+
sentry_config: Incomplete
|
|
8
|
+
otel_config: Incomplete
|
|
9
|
+
def __init__(self, sentry_config: SentryConfig | None = None, otel_config: OpenTelemetryConfig | None = None) -> None:
|
|
10
|
+
"""Initializes the telemetry configuration object with the specified parameters.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
sentry_config (SentryConfig): The Sentry configuration.
|
|
14
|
+
otel_config: The OpenTelemetry config.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def init_telemetry(config: TelemetryConfig) -> None:
|
|
18
|
+
"""Initializes telemetry for error tracking and performance monitoring.
|
|
19
|
+
|
|
20
|
+
Initializes telemetry with the specified parameters.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
config (TelemetryConfig): The telemetry configuration.
|
|
24
|
+
"""
|
|
File without changes
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from _typeshed import Incomplete
|
|
3
|
+
|
|
4
|
+
class NerLoggerHandler(logging.Handler):
|
|
5
|
+
"""Handler for preprocessing log messages using NER."""
|
|
6
|
+
api_url: Incomplete
|
|
7
|
+
api_field: Incomplete
|
|
8
|
+
pii_ner_process_enabled: Incomplete
|
|
9
|
+
def __init__(self, api_url: str, api_field: str, pii_ner_process_enabled: bool = False) -> None:
|
|
10
|
+
"""Initialize the handler.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
api_url (str): The URL of the NER API.
|
|
14
|
+
api_field (str): The field name for the NER API.
|
|
15
|
+
pii_ner_process_enabled (bool): Flag to enable NER processing.
|
|
16
|
+
"""
|
|
17
|
+
def process_message_using_ner(self, message: str) -> str:
|
|
18
|
+
"""Process message through NER API and return modified message.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
message (str): The log message to process.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
str: The processed message.
|
|
25
|
+
"""
|
|
26
|
+
def emit(self, record: logging.LogRecord):
|
|
27
|
+
"""Emit the log record.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
record (LogRecord): The log record to emit.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def init_ner_pii_logging_handler(logger_name: str, api_url: str, api_field: str, pii_ner_process_enabled: bool = False) -> None:
|
|
34
|
+
"""Initialize the NER PII logging handler.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
logger_name (str): The name of the logger.
|
|
38
|
+
api_url (str): The URL of the NER API.
|
|
39
|
+
api_field (str): The field name for the NER API.
|
|
40
|
+
pii_ner_process_enabled (bool): Flag to enable NER processing.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
NerLoggerHandler: The initialized NER PII logging handler.
|
|
44
|
+
"""
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from _typeshed import Incomplete
|
|
3
|
+
|
|
4
|
+
class RegexLoggerHandler(logging.Handler):
|
|
5
|
+
"""Handler for preprocessing log messages using regex."""
|
|
6
|
+
REGEX_KTP: Incomplete
|
|
7
|
+
REGEX_NPWP: Incomplete
|
|
8
|
+
REGEX_PHONE_NUMBER: Incomplete
|
|
9
|
+
REGEX_EMAIL_ADDRESS: Incomplete
|
|
10
|
+
pii_regex_process_enabled: Incomplete
|
|
11
|
+
def __init__(self, pii_regex_process_enabled: bool = False) -> None:
|
|
12
|
+
"""Initialize the handler.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
pii_regex_process_enabled (bool): Flag to enable regex processing.
|
|
16
|
+
"""
|
|
17
|
+
def process_message_using_regex(self, message: str) -> str:
|
|
18
|
+
"""Process message through regex and return modified message.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
message (str): The log message to process.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
str: The processed message.
|
|
25
|
+
"""
|
|
26
|
+
def mask_ktp_number(self, ktp_number: str) -> str:
|
|
27
|
+
"""Mask the KTP number to show only the first 2 and last 2 digits.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
ktp_number (str): The KTP number to mask.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
str: The masked KTP number.
|
|
34
|
+
"""
|
|
35
|
+
def mask_npwp_number(self, npwp_number: str) -> str:
|
|
36
|
+
"""Mask the NPWP number to show only the first 2 and last 2 digits.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
npwp_number (str): The NPWP number to mask.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
str: The masked NPWP number.
|
|
43
|
+
"""
|
|
44
|
+
def mask_phone_number(self, phone_number: str) -> str:
|
|
45
|
+
"""Mask the phone number to show only the first 4 and last 4 digits.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
phone_number (str): The phone number to mask.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
str: The masked phone number.
|
|
52
|
+
"""
|
|
53
|
+
def mask_email_address(self, email_address: str) -> str:
|
|
54
|
+
"""Mask the email address to show only the first 2 and last 2 characters.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
email_address (str): The email address to mask.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
str: The masked email address.
|
|
61
|
+
"""
|
|
62
|
+
def emit(self, record: logging.LogRecord):
|
|
63
|
+
"""Emit the log record.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
record (LogRecord): The log record to emit.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
def init_regex_pii_logging_handler(logger_name: str, pii_regex_process_enabled: bool = False) -> None:
|
|
70
|
+
"""Initialize the NER PII logging handler.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
logger_name (str): The name of the logger.
|
|
74
|
+
pii_regex_process_enabled (bool): Flag to enable regex processing.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
NerLoggerHandler: The initialized NER PII logging handler.
|
|
78
|
+
"""
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
from gl_observability.traces.opentelemetry.instrument.functions import BOSAFunctionsInstrumentor as BOSAFunctionsInstrumentor
|
|
2
|
+
from gl_observability.traces.opentelemetry.instrument.http import HTTPClientInstrumentor as HTTPClientInstrumentor
|
|
3
|
+
|
|
4
|
+
__all__ = ['BOSAFunctionsInstrumentor', 'HTTPClientInstrumentor']
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
|
2
|
+
from typing import Collection
|
|
3
|
+
|
|
4
|
+
class BOSAFunctionsInstrumentor(BaseInstrumentor):
|
|
5
|
+
"""OpenTelemetry Generic Function Instrumentor.
|
|
6
|
+
|
|
7
|
+
Supports:
|
|
8
|
+
- Class functions (CustomClass.function)
|
|
9
|
+
- Module functions (module.function)
|
|
10
|
+
- Static methods (@staticmethod)
|
|
11
|
+
- Class methods (@classmethod)
|
|
12
|
+
|
|
13
|
+
Not Supported:
|
|
14
|
+
- Passing bound instance methods (obj.method) directly to ``instrument``
|
|
15
|
+
- Abstract methods (abc.abstractmethod)
|
|
16
|
+
|
|
17
|
+
Note:
|
|
18
|
+
For overridden methods (including implementation of abstract method), you have to instrument the
|
|
19
|
+
overridden method. Instrumenting the parent class method will not instrument the overridden method.
|
|
20
|
+
|
|
21
|
+
Params:
|
|
22
|
+
methods (list[Callable]): List of methods to instrument.
|
|
23
|
+
max_length (int): Maximum length for function args, kwargs, and return value string. Defaults to 200.
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
```
|
|
27
|
+
### Below source code from `module/classes/custom_class.py`
|
|
28
|
+
class CustomClass:
|
|
29
|
+
|
|
30
|
+
def method(self, ...):
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def class_method(cls, ...):
|
|
35
|
+
...
|
|
36
|
+
|
|
37
|
+
@staticmethod
|
|
38
|
+
def static_method(...):
|
|
39
|
+
...
|
|
40
|
+
|
|
41
|
+
async def async_method(self, ...):
|
|
42
|
+
...
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
async def async_class_method(cls, ...):
|
|
46
|
+
...
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
async def async_static_method(...):
|
|
50
|
+
...
|
|
51
|
+
|
|
52
|
+
### Below source code from `module/functions.py`
|
|
53
|
+
def sync_function(...):
|
|
54
|
+
...
|
|
55
|
+
|
|
56
|
+
async def async_function(...):
|
|
57
|
+
...
|
|
58
|
+
|
|
59
|
+
### Instrumenting the above methods in different modules
|
|
60
|
+
from module import functions
|
|
61
|
+
from module.classes.custom_class import CustomClass
|
|
62
|
+
|
|
63
|
+
# Instrument all functions in the module
|
|
64
|
+
BOSAFunctionsInstrumentor().instrument(
|
|
65
|
+
methods=[
|
|
66
|
+
functions.sync_function, functions.async_function,
|
|
67
|
+
CustomClass.method, CustomClass.class_method,
|
|
68
|
+
CustomClass.static_method, CustomClass.async_method,
|
|
69
|
+
CustomClass.async_class_method, CustomClass.async_static_method
|
|
70
|
+
],
|
|
71
|
+
max_length=100
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
obj = CustomClass()
|
|
75
|
+
# Call the methods
|
|
76
|
+
obj.method(...)
|
|
77
|
+
CustomClass.class_method(...)
|
|
78
|
+
CustomClass.static_method(...)
|
|
79
|
+
|
|
80
|
+
await obj.async_method(...)
|
|
81
|
+
await CustomClass.async_class_method(...)
|
|
82
|
+
await CustomClass.async_static_method(...)
|
|
83
|
+
|
|
84
|
+
functions.sync_function(...)
|
|
85
|
+
await functions.async_function(...)
|
|
86
|
+
|
|
87
|
+
# Uninstrument all functions in the module
|
|
88
|
+
BOSAFunctionsInstrumentor().uninstrument()
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Note:
|
|
92
|
+
To use instrumented function from a module, you must use the function with module prefix. For example,
|
|
93
|
+
if you have a function `sync_function` in a module `functions` and you instrumented it with this
|
|
94
|
+
instrumentor, you must use it as `functions.sync_function(...)`. The reason is because this instrumentor
|
|
95
|
+
rely on monkey patching, which will not effect the function if it is imported before instrumenting.
|
|
96
|
+
By importing the module,you can avoid this issue.
|
|
97
|
+
"""
|
|
98
|
+
DEFAULT_MAX_LENGTH: int
|
|
99
|
+
def instrumentation_dependencies(self) -> Collection[str]:
|
|
100
|
+
"""Returns a collection of dependencies required for instrumentation.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Collection[str]: A collection of dependency names.
|
|
104
|
+
"""
|
|
105
|
+
def instrument(self, **kwargs) -> None:
|
|
106
|
+
"""Instruments generic custom classes.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
**kwargs: Additional keyword arguments.
|
|
110
|
+
methods (list): List of methods to instrument.
|
|
111
|
+
max_length (int): Maximum length for trimming non-dict/list data. Defaults to 200.
|
|
112
|
+
|
|
113
|
+
Raises:
|
|
114
|
+
TypeError: If any method is not callable.
|
|
115
|
+
"""
|
|
116
|
+
def uninstrument(self, **kwargs) -> None:
|
|
117
|
+
"""Uninstrument the instrumented methods.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
**kwargs: Additional keyword arguments.
|
|
121
|
+
"""
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import http.client
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
|
4
|
+
from opentelemetry.trace import Span, Tracer as Tracer, TracerProvider as TracerProvider
|
|
5
|
+
from typing import Any, Callable
|
|
6
|
+
|
|
7
|
+
METHOD_INDEX: int
|
|
8
|
+
URL_INDEX: int
|
|
9
|
+
BODY_INDEX: int
|
|
10
|
+
HEADERS_INDEX: int
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class RequestInfo:
|
|
14
|
+
"""Container for HTTP request information passed to request hooks."""
|
|
15
|
+
method: str
|
|
16
|
+
url: str
|
|
17
|
+
headers: dict[str, str]
|
|
18
|
+
body: Any
|
|
19
|
+
connection: http.client.HTTPConnection
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class ResponseInfo:
|
|
23
|
+
"""Container for HTTP response information passed to response hooks."""
|
|
24
|
+
status_code: int
|
|
25
|
+
headers: dict[str, str]
|
|
26
|
+
response: http.client.HTTPResponse
|
|
27
|
+
connection: http.client.HTTPConnection
|
|
28
|
+
RequestHookT = Callable[[Span, RequestInfo], None]
|
|
29
|
+
ResponseHookT = Callable[[Span, ResponseInfo], None]
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class InstrumentationContext:
|
|
33
|
+
"""Context for instrumentation configuration."""
|
|
34
|
+
tracer: Tracer
|
|
35
|
+
request_hook: RequestHookT | None
|
|
36
|
+
response_hook: ResponseHookT | None
|
|
37
|
+
|
|
38
|
+
class HTTPClientInstrumentor(BaseInstrumentor):
|
|
39
|
+
"""Instrumentor for Python's http.client library.
|
|
40
|
+
|
|
41
|
+
Wraps http.client.HTTPConnection.request() and getresponse() methods
|
|
42
|
+
to create spans for HTTP requests.
|
|
43
|
+
"""
|
|
44
|
+
def instrumentation_dependencies(self) -> list[str]:
|
|
45
|
+
"""Return list of instrumentation dependencies.
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
list[str]: Empty list (http.client is stdlib).
|
|
49
|
+
"""
|
|
50
|
+
def instrument(self, *, tracer_provider: TracerProvider | None = None, request_hook: RequestHookT | None = None, response_hook: ResponseHookT | None = None, **kwargs: Any) -> None:
|
|
51
|
+
"""Instrument the library.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
tracer_provider: OpenTelemetry TracerProvider instance
|
|
55
|
+
request_hook: Optional callback for request customization
|
|
56
|
+
response_hook: Optional callback for response customization
|
|
57
|
+
**kwargs: Additional keyword arguments
|
|
58
|
+
"""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*
|
|
Binary file
|
gl_observability.pyi
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# This file was generated by Nuitka
|
|
2
|
+
|
|
3
|
+
# Stubs included by default
|
|
4
|
+
from gl_observability.initializer import TelemetryConfig, init_telemetry
|
|
5
|
+
from gl_observability.backend import OpenTelemetryConfig, SentryConfig
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
__name__ = ...
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Modules used internally, to allow implicit dependencies to be seen:
|
|
13
|
+
import os
|
|
14
|
+
import gl_observability.backend.OpenTelemetryConfig
|
|
15
|
+
import gl_observability.backend.SentryConfig
|
|
16
|
+
import fastapi
|
|
17
|
+
import opentelemetry
|
|
18
|
+
import opentelemetry.exporter
|
|
19
|
+
import opentelemetry.exporter.otlp
|
|
20
|
+
import opentelemetry.exporter.otlp.proto
|
|
21
|
+
import opentelemetry.exporter.otlp.proto.grpc
|
|
22
|
+
import opentelemetry.exporter.otlp.proto.grpc.trace_exporter
|
|
23
|
+
import opentelemetry.exporter.otlp.proto.http
|
|
24
|
+
import opentelemetry.exporter.otlp.proto.http.trace_exporter
|
|
25
|
+
import opentelemetry.instrumentation
|
|
26
|
+
import opentelemetry.instrumentation.fastapi
|
|
27
|
+
import opentelemetry.instrumentation.httpx
|
|
28
|
+
import opentelemetry.instrumentation.langchain
|
|
29
|
+
import opentelemetry.instrumentation.requests
|
|
30
|
+
import opentelemetry.propagate
|
|
31
|
+
import opentelemetry.sdk
|
|
32
|
+
import opentelemetry.sdk.resources
|
|
33
|
+
import opentelemetry.sdk.trace
|
|
34
|
+
import opentelemetry.sdk.trace.export
|
|
35
|
+
import opentelemetry.sdk.trace.sampling
|
|
36
|
+
import sentry_sdk
|
|
37
|
+
import sentry_sdk.integrations
|
|
38
|
+
import sentry_sdk.integrations.opentelemetry
|
|
39
|
+
import typing
|
|
40
|
+
import logging
|
|
41
|
+
import requests
|
|
42
|
+
import re
|
|
43
|
+
import importlib
|
|
44
|
+
import inspect
|
|
45
|
+
import wrapt
|
|
46
|
+
import opentelemetry.instrumentation.instrumentor
|
|
47
|
+
import http
|
|
48
|
+
import http.client
|
|
49
|
+
import dataclasses
|
|
50
|
+
import http.HTTPStatus
|
|
51
|
+
import urllib
|
|
52
|
+
import urllib.parse
|
|
53
|
+
import opentelemetry.semconv
|
|
54
|
+
import opentelemetry.semconv.attributes
|
|
55
|
+
import opentelemetry.trace
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: gl-observability-binary
|
|
3
|
+
Version: 0.0.0b1
|
|
4
|
+
Summary: SDK for Observability tools
|
|
5
|
+
Author-email: HansSeanNathanael <hans.s.nathanael@gdplabs.id>
|
|
6
|
+
Requires-Python: <3.14,>=3.11
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: fastapi<1.0.0,>=0.115.6
|
|
9
|
+
Requires-Dist: requests<3.0.0,>=2.31.0
|
|
10
|
+
Requires-Dist: httpx<1.0.0,>=0.27.0
|
|
11
|
+
Requires-Dist: langchain-core<1.0.0,>=0.3
|
|
12
|
+
Requires-Dist: sentry-sdk<3.0.0,>=2.20.0
|
|
13
|
+
Requires-Dist: opentelemetry-api
|
|
14
|
+
Requires-Dist: opentelemetry-sdk
|
|
15
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http
|
|
16
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc
|
|
17
|
+
Requires-Dist: opentelemetry-instrumentation-fastapi
|
|
18
|
+
Requires-Dist: opentelemetry-instrumentation-langchain
|
|
19
|
+
Requires-Dist: opentelemetry-instrumentation-requests
|
|
20
|
+
Requires-Dist: opentelemetry-instrumentation-httpx
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest<9.0.0,>=8.3.4; extra == "dev"
|
|
23
|
+
Requires-Dist: pre-commit<4.0.0,>=3.7.0; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest-cov<6.0.0,>=5.0.0; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-asyncio<1.0.0,>=0.25.3; extra == "dev"
|
|
26
|
+
Requires-Dist: pytest-mock<4.0.0,>=3.14.0; extra == "dev"
|
|
27
|
+
Requires-Dist: coverage<8.0.0,>=7.6.10; extra == "dev"
|
|
28
|
+
Requires-Dist: mypy<2.0.0,>=1.11.2; extra == "dev"
|
|
29
|
+
Requires-Dist: ruff<1.0.0,>=0.11.12; extra == "dev"
|
|
30
|
+
|
|
31
|
+
# GL Observability
|
|
32
|
+
|
|
33
|
+
`gl-observability` is a comprehensive SDK for implementing observability in Python applications. It provides easy-to-use wrappers for OpenTelemetry, Sentry, and custom logging handlers with PII redaction capabilities.
|
|
34
|
+
|
|
35
|
+
## Key Features
|
|
36
|
+
|
|
37
|
+
- 📊 **OpenTelemetry Integration**: simplified initialization for tracing and metrics.
|
|
38
|
+
- 🛡️ **Sentry Support**: easy setup for error tracking and performance monitoring.
|
|
39
|
+
- 🕵️ **PII Redaction**: custom logging handlers to redact PII using Regex or NER (Named Entity Recognition).
|
|
40
|
+
- 🔌 **Framework Support**: built-in support for FastAPI, Langchain, HTTPX, and Requests instrumentation.
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
### Prerequisites
|
|
45
|
+
|
|
46
|
+
- Python 3.11-3.13 - [Install here](https://www.python.org/downloads/)
|
|
47
|
+
- Pip (if using pip) - [Install here](https://pip.pypa.io/en/stable/installation/)
|
|
48
|
+
- Poetry 2.1.3+ (if using Poetry) - [Install here](https://python-poetry.org/docs/#installation)
|
|
49
|
+
- uv (if using uv) - [Install here](https://docs.astral.sh/uv/guides/install-python/)
|
|
50
|
+
- Git (if using Git) - [Install here](https://git-scm.com/downloads)
|
|
51
|
+
- For git installation, access to the [GDP Labs SDK github repository](https://github.com/GDP-ADMIN/gl-sdk)
|
|
52
|
+
|
|
53
|
+
### 1. Installation from Pypi
|
|
54
|
+
|
|
55
|
+
Choose one of the following methods to install the package:
|
|
56
|
+
|
|
57
|
+
#### Using pip
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install gl-observability-binary
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
#### Using Poetry
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
poetry add gl-observability-binary
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
#### Using uv
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
uv add gl-observability-binary
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 2. Development Installation (Git)
|
|
76
|
+
|
|
77
|
+
For development purposes, you can install directly from the Git repository:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
poetry add "git+ssh://git@github.com/GDP-ADMIN/gl-sdk.git#subdirectory=libs/gl-observability"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Usage
|
|
84
|
+
|
|
85
|
+
### 1. Telemetry Initialization
|
|
86
|
+
|
|
87
|
+
The library uses a unified `init_telemetry` function that takes a `TelemetryConfig` object. You can configure it for OpenTelemetry, Sentry, or both.
|
|
88
|
+
|
|
89
|
+
#### OpenTelemetry Configuration (External Exporter)
|
|
90
|
+
|
|
91
|
+
This setup sends traces to an external OTLP collector (e.g., Jaeger, Tempo).
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from fastapi import FastAPI
|
|
95
|
+
from gl_observability.backend import FastAPIConfig, OpenTelemetryConfig
|
|
96
|
+
from gl_observability import TelemetryConfig, init_telemetry
|
|
97
|
+
|
|
98
|
+
# 1. Setup FastAPI Config (optional, if using FastAPI)
|
|
99
|
+
app = FastAPI()
|
|
100
|
+
fastapi_config = FastAPIConfig(app=app)
|
|
101
|
+
|
|
102
|
+
# 2. Configure OpenTelemetry
|
|
103
|
+
otel_config = OpenTelemetryConfig(
|
|
104
|
+
endpoint="localhost:4317", # OTLP endpoint
|
|
105
|
+
use_grpc=False, # Use gRPC or HTTP
|
|
106
|
+
fastapi_config=fastapi_config,
|
|
107
|
+
use_langchain=True, # Enable Langchain instrumentation
|
|
108
|
+
use_httpx=True, # Enable HTTPX instrumentation
|
|
109
|
+
use_requests=True, # Enable Requests instrumentation
|
|
110
|
+
attributes={"service.name": "my-service", "env": "production"}
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# 3. Initialize Telemetry
|
|
114
|
+
init_telemetry(TelemetryConfig(otel_config=otel_config))
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### Sentry Configuration
|
|
118
|
+
|
|
119
|
+
This setup sends errors and traces to Sentry.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from gl_observability.backend import SentryConfig
|
|
123
|
+
from gl_observability import TelemetryConfig, init_telemetry
|
|
124
|
+
|
|
125
|
+
def traces_sampler(sampling_context: dict) -> float:
|
|
126
|
+
"""Custom trace sampler."""
|
|
127
|
+
return 1.0
|
|
128
|
+
|
|
129
|
+
# 1. Configure Sentry
|
|
130
|
+
sentry_config = SentryConfig(
|
|
131
|
+
dsn="your-sentry-dsn",
|
|
132
|
+
environment="production",
|
|
133
|
+
release="1.0.0",
|
|
134
|
+
traces_sampler=traces_sampler,
|
|
135
|
+
send_default_pii=True
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# 2. Initialize Telemetry
|
|
139
|
+
init_telemetry(TelemetryConfig(sentry_config=sentry_config))
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### Sentry with OpenTelemetry
|
|
143
|
+
|
|
144
|
+
This setup combines Sentry with OpenTelemetry instrumentation, allowing Sentry to capture OTel spans.
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
from fastapi import FastAPI
|
|
148
|
+
from gl_observability.backend import FastAPIConfig, OpenTelemetryConfig, SentryConfig
|
|
149
|
+
from gl_observability import TelemetryConfig, init_telemetry
|
|
150
|
+
|
|
151
|
+
app = FastAPI()
|
|
152
|
+
fastapi_config = FastAPIConfig(app=app)
|
|
153
|
+
|
|
154
|
+
# 1. Configure OpenTelemetry (without endpoint, as Sentry handles export)
|
|
155
|
+
otel_config = OpenTelemetryConfig(
|
|
156
|
+
attributes={"service.name": "my-service"},
|
|
157
|
+
fastapi_config=fastapi_config,
|
|
158
|
+
use_langchain=True
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# 2. Configure Sentry with OTel config
|
|
162
|
+
sentry_config = SentryConfig(
|
|
163
|
+
dsn="your-sentry-dsn",
|
|
164
|
+
environment="production",
|
|
165
|
+
open_telemetry_config=otel_config
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
# 3. Initialize Telemetry
|
|
169
|
+
init_telemetry(TelemetryConfig(sentry_config=sentry_config))
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 2. Logging Handlers
|
|
173
|
+
|
|
174
|
+
The library provides logging handlers to automatically redact Personally Identifiable Information (PII) from logs.
|
|
175
|
+
|
|
176
|
+
#### Regex-based PII Redaction
|
|
177
|
+
|
|
178
|
+
Uses regular expressions to mask common PII patterns like KTP, NPWP, Phone Numbers, and Email.
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
import logging
|
|
182
|
+
from gl_observability.logs.regex_pii_logger_handler import init_regex_pii_logging_handler
|
|
183
|
+
|
|
184
|
+
# Initialize the handler for a specific logger
|
|
185
|
+
init_regex_pii_logging_handler(
|
|
186
|
+
logger_name="my_application_logger",
|
|
187
|
+
pii_regex_process_enabled=True
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
logger = logging.getLogger("my_application_logger")
|
|
191
|
+
logger.info("User email is john.doe@example.com and phone is 08123456789")
|
|
192
|
+
# Output: User email is jo******om and phone is 0812******6789
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### NER-based PII Redaction (Named Entity Recognition)
|
|
196
|
+
|
|
197
|
+
Uses an external API to perform Named Entity Recognition for more advanced PII detection and redaction.
|
|
198
|
+
|
|
199
|
+
> [!WARNING]
|
|
200
|
+
> The NER logging handler makes synchronous API calls for each log record, which may impact performance.
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
import logging
|
|
204
|
+
from gl_observability.logs.ner_pii_logger_handler import init_ner_pii_logging_handler
|
|
205
|
+
|
|
206
|
+
# Initialize the handler
|
|
207
|
+
init_ner_pii_logging_handler(
|
|
208
|
+
logger_name="my_application_logger",
|
|
209
|
+
api_url="https://your-ner-api.com/anonymize",
|
|
210
|
+
api_field="text", # The field name in API response containing the redacted text
|
|
211
|
+
pii_ner_process_enabled=True
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
logger = logging.getLogger("my_application_logger")
|
|
215
|
+
logger.info("My KTP is 3525011212941001")
|
|
216
|
+
# Output will be redacted based on API response
|
|
217
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
gl_observability.cp313-win_amd64.pyd,sha256=Z9oOG0VBa7YcqkEqVX2zp7nOGfgIvEoAjV0HUEyBztw,649728
|
|
2
|
+
gl_observability.pyi,sha256=46n3y42spCx9vMmhRew5Ah26B67UoblpNHDsmIb8uU8,1626
|
|
3
|
+
gl_observability/__init__.pyi,sha256=Ae5Vy1UKE0GokAsbCejhl8IfomzxoHQklX1EMqWAZEs,312
|
|
4
|
+
gl_observability/initializer.pyi,sha256=vSBAy4QdpjDbrmKLYwFk_yBzwqCklDvMyTiVsmAWEzw,1108
|
|
5
|
+
gl_observability/backend/__init__.pyi,sha256=IbzwPhr570SWM4925eUdYt_QarRz0idNResU9gv6Lig,295
|
|
6
|
+
gl_observability/backend/opentelemetry/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
gl_observability/backend/opentelemetry/initializer.pyi,sha256=X4ojVPJVwcdghJq0RHytwvltEyiV3qC8uZv1u7h7Rhc,2947
|
|
8
|
+
gl_observability/backend/sentry/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
gl_observability/backend/sentry/initializer.pyi,sha256=pOZGRlHCM2TLi-3knvvWFLSB1gbeyeGx6lDnthuJ7Ss,1990
|
|
10
|
+
gl_observability/logs/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
gl_observability/logs/ner_pii_logger_handler.pyi,sha256=KkX_78DsEJVFqdgcrrV-sosUmIR14gKJD6JEp16YOLU,1573
|
|
12
|
+
gl_observability/logs/regex_pii_logger_handler.pyi,sha256=mN9pAOn8t3GrEjM7hldAn2HZLV8m3Ja2wY5vwWDWdAI,2538
|
|
13
|
+
gl_observability/traces/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
gl_observability/traces/opentelemetry/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
+
gl_observability/traces/opentelemetry/instrument/__init__.pyi,sha256=PC9q9GLoWkGDGgcrYsp6j3rpS_A3yse80NaCAb-3BBQ,312
|
|
16
|
+
gl_observability/traces/opentelemetry/instrument/functions.pyi,sha256=NeLDDzYJwXrAR5ltmfkdqj78UQqbyTHtW-eFXgoI5uM,4305
|
|
17
|
+
gl_observability/traces/opentelemetry/instrument/http.pyi,sha256=GQRN3YdFElTF-m_nRWUG8XE50ge1QxMmRJiLY1TYP3c,2061
|
|
18
|
+
gl_observability.build/.gitignore,sha256=aEiIwOuxfzdCmLZe4oB1JsBmCUxwG8x-u-HBCV9JT8E,1
|
|
19
|
+
gl_observability_binary-0.0.0b1.dist-info/METADATA,sha256=r1pS0wyqq4WC19Hzp5mLoYu1lu_8jqW2GcUx-dGQA5o,7356
|
|
20
|
+
gl_observability_binary-0.0.0b1.dist-info/WHEEL,sha256=O_u6PJIQ2pIcyIInxVQ9r-yArMuUZbBIaF1kpYVkYxA,96
|
|
21
|
+
gl_observability_binary-0.0.0b1.dist-info/top_level.txt,sha256=qX0-e4NxRAAXXjWIZ7gvIspQP7J_dgxPQ7e3-WEbIeQ,17
|
|
22
|
+
gl_observability_binary-0.0.0b1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gl_observability
|