Skip to content

Commit 195b6cc

Browse files
committed
Seperate packages Flow added
1 parent 494a35a commit 195b6cc

File tree

9 files changed

+387
-26
lines changed

9 files changed

+387
-26
lines changed

.github/workflows/main-rc.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,32 @@ jobs:
3131
with:
3232
user: __token__
3333
password: ${{ secrets.PYPI_TOKEN }}
34+
35+
deploy-k8s:
36+
37+
runs-on: ubuntu-latest
38+
39+
steps:
40+
- uses: actions/checkout@v2
41+
- name: Set up Python
42+
uses: actions/setup-python@v2
43+
with:
44+
python-version: '3.x'
45+
- name: Install dependencies
46+
run: |
47+
echo "Building middleware-io-k8s (HTTP exporter)..."
48+
cp pyproject-k8s.toml pyproject.toml
49+
pip install -r dev-requirements.txt
50+
pip install setuptools wheel build twine
51+
- name: Build and publish
52+
env:
53+
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
54+
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
55+
run: |
56+
python -m build
57+
twine upload dist/*
58+
- name: Publish a Python distribution to PyPI
59+
uses: pypa/gh-action-pypi-publish@release/v1
60+
with:
61+
user: __token__
62+
password: ${{ secrets.PYPI_TOKEN }}

.github/workflows/main.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,42 @@ jobs:
4343
Release ${{ github.ref }}
4444
draft: false
4545
prerelease: false
46+
deploy-k8s:
47+
48+
runs-on: ubuntu-latest
49+
50+
steps:
51+
- uses: actions/checkout@v2
52+
- name: Set up Python
53+
uses: actions/setup-python@v2
54+
with:
55+
python-version: '3.x'
56+
- name: Install dependencies
57+
run: |
58+
cp pyproject-k8s.toml pyproject.toml
59+
pip install -r dev-requirements.txt
60+
pip install setuptools wheel build twine
61+
- name: Build and publish
62+
env:
63+
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
64+
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
65+
run: |
66+
python -m build
67+
twine upload dist/*
68+
- name: Publish a Python distribution to PyPI
69+
uses: pypa/gh-action-pypi-publish@release/v1
70+
with:
71+
user: __token__
72+
password: ${{ secrets.PYPI_TOKEN }}
73+
- name: Create Release
74+
id: create_release
75+
uses: actions/create-release@v1
76+
env:
77+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
78+
with:
79+
tag_name: ${{ github.ref }}
80+
release_name: Release K8s ${{ github.ref }}
81+
body: |
82+
Release K8s ${{ github.ref }}
83+
draft: false
84+
prerelease: false

middleware/exporter_config.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
"""
2+
Exporter configuration that adapts based on the package variant.
3+
Automatically selects HTTP or gRPC exporters based on installed package.
4+
5+
- middleware-io: gRPC exporters (standard)
6+
- middleware-io-k8s: HTTP exporters (for Kubernetes)
7+
"""
8+
9+
import logging
10+
from middleware.version import __package_name__
11+
12+
_logger = logging.getLogger(__name__)
13+
14+
# PACKAGE VARIANT DETECTION
15+
16+
IS_K8S_VARIANT = "k8s" in __package_name__.lower()
17+
18+
_logger.info(f"Detected package: {__package_name__}")
19+
20+
# IMPORT APPROPRIATE EXPORTERS
21+
22+
if IS_K8S_VARIANT:
23+
# K8s variant - MUST use HTTP exporters
24+
try:
25+
from opentelemetry.exporter.otlp.proto.http.metric_exporter import (
26+
OTLPMetricExporter as MetricExporter,
27+
)
28+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
29+
OTLPSpanExporter as TraceExporter,
30+
)
31+
from opentelemetry.exporter.otlp.proto.http._log_exporter import (
32+
OTLPLogExporter as LogExporter,
33+
)
34+
35+
_logger.info("✓ Using HTTP exporters for K8s variant")
36+
except ImportError as e:
37+
_logger.error(f"Failed to import HTTP exporters for K8s variant: {e}")
38+
raise ImportError(
39+
f"middleware-io-k8s package requires HTTP exporter dependencies. "
40+
f"Please ensure 'opentelemetry-exporter-otlp-proto-http' is installed. "
41+
f"Original error: {e}"
42+
) from e
43+
else:
44+
# Standard variant - MUST use gRPC exporters
45+
try:
46+
import grpc
47+
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import (
48+
OTLPMetricExporter as MetricExporter,
49+
)
50+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
51+
OTLPSpanExporter as TraceExporter,
52+
)
53+
from opentelemetry.exporter.otlp.proto.grpc._log_exporter import (
54+
OTLPLogExporter as LogExporter,
55+
)
56+
57+
_logger.info("✓ Using gRPC exporters for standard variant")
58+
except ImportError as e:
59+
_logger.error(f"Failed to import gRPC exporters for standard variant: {e}")
60+
raise ImportError(
61+
f"middleware-io package requires gRPC exporter dependencies. "
62+
f"Please ensure 'opentelemetry-exporter-otlp-proto-grpc' is installed. "
63+
f"Original error: {e}"
64+
) from e
65+
66+
67+
def create_metric_exporter(endpoint: str):
68+
"""
69+
Create OTLP metric exporter of appropriate type.
70+
71+
Args:
72+
endpoint (str): The OTLP endpoint URL
73+
74+
Returns:
75+
OTLPMetricExporter: HTTP or gRPC based on package variant
76+
"""
77+
if IS_K8S_VARIANT:
78+
# K8s: HTTP exporter
79+
return MetricExporter(endpoint=endpoint + "/v1/metrics")
80+
else:
81+
# Standard: gRPC exporter with compression
82+
return MetricExporter(endpoint=endpoint, compression=grpc.Compression.Gzip)
83+
84+
85+
def create_trace_exporter(endpoint: str):
86+
"""
87+
Create OTLP trace exporter of appropriate type.
88+
89+
Args:
90+
endpoint (str): The OTLP endpoint URL
91+
92+
Returns:
93+
OTLPSpanExporter: HTTP or gRPC based on package variant
94+
"""
95+
if IS_K8S_VARIANT:
96+
# K8s: HTTP exporter
97+
return TraceExporter(endpoint=endpoint + "/v1/traces")
98+
else:
99+
# Standard: gRPC exporter with compression
100+
return TraceExporter(endpoint=endpoint, compression=grpc.Compression.Gzip)
101+
102+
103+
def create_log_exporter(endpoint: str):
104+
"""
105+
Create OTLP log exporter of appropriate type.
106+
107+
Args:
108+
endpoint (str): The OTLP endpoint URL
109+
110+
Returns:
111+
OTLPLogExporter: HTTP or gRPC based on package variant
112+
"""
113+
if IS_K8S_VARIANT:
114+
# K8s: HTTP exporter
115+
return LogExporter(endpoint=endpoint + "/v1/logs")
116+
else:
117+
# Standard: gRPC exporter with compression
118+
return LogExporter(endpoint=endpoint, compression=grpc.Compression.Gzip)

middleware/log.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
import sys
33
import logging
44
from opentelemetry.sdk.resources import Resource
5-
from opentelemetry.exporter.otlp.proto.http._log_exporter import (
6-
OTLPLogExporter,
7-
)
5+
from middleware.exporter_config import create_log_exporter
6+
87
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
98
from opentelemetry.sdk._logs.export import (
109
BatchLogRecordProcessor,
@@ -29,10 +28,8 @@ def create_logger_handler(options: MWOptions, resource: Resource) -> LoggingHand
2928
Returns:
3029
LoggerProvider: the new logger provider
3130
"""
32-
exporter = OTLPLogExporter(
33-
endpoint=options.target + "/v1/logs",
34-
# compression=grpc.Compression.Gzip,
35-
)
31+
exporter = create_log_exporter(options.target)
32+
3633
logger_provider = LoggerProvider(resource=resource, shutdown_on_exit=True)
3734
logger_provider.add_log_record_processor(BatchLogRecordProcessor(exporter))
3835
if options.console_exporter:
@@ -60,6 +57,7 @@ def create_logger_handler(options: MWOptions, resource: Resource) -> LoggingHand
6057

6158
return handler
6259

60+
6361
class MWLoggingHandler(LoggingHandler):
6462
@staticmethod
6563
def _get_attributes(record: LogRecord):
@@ -69,12 +67,12 @@ def _get_attributes(record: LogRecord):
6967
if key == "request":
7068
if hasattr(value, "method") and hasattr(value, "path"):
7169
if len(vars(value)) == 2:
72-
attributes[key] = f'{value.method} {value.path}'
70+
attributes[key] = f"{value.method} {value.path}"
7371
else:
7472
attributes[key] = str(value)
7573
else:
7674
attributes[key] = str(value)
7775
elif not isinstance(value, (bool, str, bytes, int, float)):
7876
attributes[key] = str(value)
7977

80-
return attributes
78+
return attributes

middleware/metrics.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
PeriodicExportingMetricReader,
1818
ConsoleMetricExporter,
1919
)
20-
from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter
20+
from middleware.exporter_config import create_metric_exporter
21+
2122
from middleware.options import MWOptions
2223

2324
_logger = logging.getLogger(__name__)
@@ -34,11 +35,8 @@ def create_meter_provider(options: MWOptions, resource: Resource):
3435
Returns:
3536
MeterProvider: the new meter provider
3637
"""
37-
38-
exporter = OTLPMetricExporter(
39-
endpoint=options.target + "/v1/metrics",
40-
# compression=grpc.Compression.Gzip,
41-
)
38+
exporter = create_metric_exporter(options.target)
39+
4240
readers = [PeriodicExportingMetricReader(exporter)]
4341
if options.console_exporter:
4442
output = sys.stdout

middleware/trace.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@
88
SimpleSpanProcessor,
99
ConsoleSpanExporter,
1010
)
11-
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
11+
from middleware.exporter_config import create_trace_exporter
1212
from opentelemetry.processor.baggage import ALLOW_ALL_BAGGAGE_KEYS, BaggageSpanProcessor
1313
from middleware.options import MWOptions
1414
from opentelemetry.trace import set_tracer_provider, Span
1515
from middleware.sampler import configure_sampler
1616

1717
_logger = logging.getLogger(__name__)
1818

19+
1920
class ExceptionFilteringSpanProcessor(SpanProcessor):
2021
def on_start(self, span: ReadableSpan, parent_context):
2122
pass
@@ -32,7 +33,10 @@ def on_end(self, span: ReadableSpan):
3233
seen_stack_traces = set()
3334
filtered_events = []
3435
for event in span.events:
35-
if event.name == "exception" and "exception.stack_details" in event.attributes:
36+
if (
37+
event.name == "exception"
38+
and "exception.stack_details" in event.attributes
39+
):
3640
stack_trace = event.attributes.get("exception.stack_trace")
3741
seen_stack_traces.add(stack_trace)
3842
filtered_events.append(event)
@@ -50,6 +54,7 @@ def shutdown(self):
5054
def force_flush(self, timeout_millis=None):
5155
pass
5256

57+
5358
def create_tracer_provider(options: MWOptions, resource: Resource) -> TracerProvider:
5459
"""
5560
Configures and returns a new TracerProvider to send traces telemetry.
@@ -62,10 +67,8 @@ def create_tracer_provider(options: MWOptions, resource: Resource) -> TracerProv
6267
TracerProvider: the new tracer provider
6368
"""
6469

65-
exporter = OTLPSpanExporter(
66-
endpoint=options.target + "/v1/traces",
67-
# compression=grpc.Compression.Gzip,
68-
)
70+
exporter = create_trace_exporter(options.target)
71+
6972
trace_provider = TracerProvider(
7073
resource=resource, shutdown_on_exit=True, sampler=configure_sampler(options)
7174
)
@@ -93,4 +96,4 @@ def create_tracer_provider(options: MWOptions, resource: Resource) -> TracerProv
9396
)
9497
)
9598
set_tracer_provider(tracer_provider=trace_provider)
96-
return trace_provider
99+
return trace_provider

middleware/version.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1-
import pkg_resources
21

3-
__version__ = pkg_resources.get_distribution("middleware-io").version
2+
"""Version and package information."""
3+
try:
4+
import pkg_resources
5+
__version__ = pkg_resources.get_distribution("middleware-io").version
6+
__package_name__ = "middleware-io"
7+
except:
8+
try:
9+
import pkg_resources
10+
__version__ = pkg_resources.get_distribution("middleware-io-k8s").version
11+
__package_name__ = "middleware-io-k8s"
12+
except:
13+
__version__ = "unknown"
14+
__package_name__ = "middleware-io"

0 commit comments

Comments
 (0)