Skip to content

Commit 563999a

Browse files
improvements
1 parent 4c8f979 commit 563999a

File tree

12 files changed

+797
-235
lines changed

12 files changed

+797
-235
lines changed

superclient/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,11 @@
1+
from importlib.metadata import PackageNotFoundError, version as _pkg_version
2+
3+
try:
4+
__version__ = _pkg_version("superclient")
5+
except PackageNotFoundError:
6+
# Fallback for when the package isn't installed (e.g. running from source without editable install)
7+
__version__ = "0.0.0"
8+
9+
# Initialize the Superstream agent on import
110
from .agent import initialize as _init
211
_init()

superclient/agent/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import sys
66
from typing import Any, Dict, Optional, Tuple
77

8-
from ..logger import get_logger, set_debug_enabled
8+
from ..util.logger import get_logger, set_debug_enabled
99
from ..util.config import get_env_vars, is_disabled
1010
from ..util.network import get_host_info
1111
from .interceptor import patch_kafka_python, patch_aiokafka, patch_confluent
@@ -24,7 +24,7 @@
2424
if is_disabled():
2525
logger.warn("Superstream functionality disabled via SUPERSTREAM_DISABLED")
2626

27-
_VERSION = "1.0.0"
27+
# Preserve reference to built-in import function
2828
_original_import = builtins.__import__
2929

3030
# ---------------------------------------------------------------------------

superclient/agent/clients.py

Lines changed: 82 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,72 +4,85 @@
44
import os
55
from typing import Any, Dict
66

7-
from ..logger import get_logger
7+
from ..util.logger import get_logger
8+
from .. import __version__ as _VERSION
9+
from ..util.config import (
10+
copy_client_configuration_properties,
11+
convert_to_dot_syntax,
12+
get_original_config,
13+
mask_sensitive,
14+
)
815

916
logger = get_logger("agent.clients")
1017

11-
_VERSION = "0.1.0"
1218
_SUPERLIB_PREFIX = "superstreamlib-"
1319

14-
def mask_sensitive(k: str, v: Any) -> Any:
15-
"""Mask sensitive configuration values."""
16-
return "[MASKED]" if "password" in k.lower() or "sasl.jaas.config" in k.lower() else v
17-
18-
def copy_security(src: Dict[str, Any], dst: Dict[str, Any]):
19-
"""Copy security-related configuration from source to destination."""
20-
keys = [
21-
"security.protocol",
22-
"sasl.mechanism",
23-
"sasl.jaas.config",
24-
"ssl.keystore.password",
25-
"ssl.truststore.password",
26-
"ssl.key.password",
27-
"client.dns.lookup",
28-
]
29-
for k in keys:
30-
if k in src and k not in dst:
31-
dst[k] = src[k]
32-
33-
def internal_send_clients(bootstrap: str, base_cfg: Dict[str, Any], payload: bytes) -> None:
34-
"""Send payload to superstream.clients using available Kafka library."""
35-
# Attempt kafka-python first
36-
try:
37-
import kafka # type: ignore
38-
39-
cfg = {
40-
"bootstrap_servers": bootstrap,
41-
"client_id": _SUPERLIB_PREFIX + "client-reporter",
42-
"compression_type": "zstd",
43-
"batch_size": 16_384,
44-
"linger_ms": 1000,
45-
}
46-
copy_security(base_cfg, cfg)
47-
prod = kafka.KafkaProducer(**{k.replace(".", "_"): v for k, v in cfg.items()})
48-
prod.send("superstream.clients", payload)
49-
prod.flush()
50-
prod.close()
20+
def _create_producer_kafka_python(bootstrap: str, base_cfg: Dict[str, Any]):
21+
import kafka # type: ignore
22+
23+
cfg = {
24+
"bootstrap.servers": bootstrap,
25+
"client.id": _SUPERLIB_PREFIX + "client-reporter",
26+
"compression.type": "zstd",
27+
"batch.size": 16_384,
28+
"linger.ms": 1000,
29+
}
30+
copy_client_configuration_properties(base_cfg, cfg)
31+
kafka_cfg = {k.replace(".", "_"): v for k, v in cfg.items()}
32+
return kafka.KafkaProducer(**kafka_cfg)
33+
34+
35+
def _create_producer_confluent(bootstrap: str, base_cfg: Dict[str, Any]):
36+
from confluent_kafka import Producer as _CProducer # type: ignore
37+
38+
cfg = {
39+
"bootstrap.servers": bootstrap,
40+
"client.id": _SUPERLIB_PREFIX + "client-reporter",
41+
"compression.type": "zstd",
42+
"batch.size": 16384,
43+
"linger.ms": 1000,
44+
}
45+
copy_client_configuration_properties(base_cfg, cfg)
46+
return _CProducer(cfg)
47+
48+
49+
_PRODUCER_BUILDERS = {
50+
"kafka-python": _create_producer_kafka_python,
51+
"confluent": _create_producer_confluent,
52+
# aiokafka is async; for heartbeat reporting we use kafka-python builder as fallback
53+
"aiokafka": _create_producer_kafka_python,
54+
}
55+
56+
57+
def internal_send_clients(
58+
bootstrap: str,
59+
base_cfg: Dict[str, Any],
60+
payload: bytes,
61+
lib_name: str,
62+
) -> None:
63+
"""Send payload to superstream.clients using the *same* Kafka library as the application.
64+
65+
In the unlikely event of failure we silently swallow exceptions – reporting
66+
must never interrupt the user application – but we log for troubleshooting.
67+
"""
68+
69+
builder = _PRODUCER_BUILDERS.get(lib_name)
70+
if builder is None:
71+
logger.debug("Unknown Kafka library '{}', skipping client report", lib_name)
5172
return
52-
except Exception:
53-
pass # fallthrough
5473

55-
# Fallback to confluent-kafka if available
5674
try:
57-
from confluent_kafka import Producer as _CProducer # type: ignore
58-
59-
cfg = {
60-
"bootstrap.servers": bootstrap,
61-
"client.id": _SUPERLIB_PREFIX + "client-reporter",
62-
"compression.type": "zstd",
63-
"batch.size": 16384,
64-
"linger.ms": 1000,
65-
}
66-
copy_security(base_cfg, cfg)
67-
prod = _CProducer(cfg)
68-
prod.produce("superstream.clients", payload)
69-
prod.flush()
75+
prod = builder(bootstrap, base_cfg)
76+
# confluent-kafka Producer uses .produce, kafka-python uses .send
77+
if hasattr(prod, "produce"):
78+
prod.produce("superstream.clients", payload)
79+
prod.flush()
80+
else:
81+
prod.send("superstream.clients", payload)
82+
prod.flush()
83+
prod.close()
7084
except Exception:
71-
# As a last resort just log and drop – should never interrupt app
72-
logger.debug("Failed to send clients message via all libraries")
85+
logger.debug("Failed to send clients message via {}", lib_name)
7386

7487
def get_host_info() -> tuple[str, str]:
7588
"""Get hostname and IP address."""
@@ -84,22 +97,29 @@ def get_host_info() -> tuple[str, str]:
8497
def send_clients_msg(tracker: Any, error: str = "") -> None:
8598
"""Send a message to the clients topic."""
8699
hostname, ip = get_host_info()
100+
# Prepare configuration dictionaries in dot syntax with defaults merged
101+
orig_cfg_dot = get_original_config(tracker.orig_cfg, tracker.library)
102+
orig_cfg_masked = {k: mask_sensitive(k, v) for k, v in orig_cfg_dot.items()}
103+
104+
opt_cfg_dot = convert_to_dot_syntax(tracker.opt_cfg, tracker.library)
105+
opt_cfg_masked = {k: mask_sensitive(k, v) for k, v in opt_cfg_dot.items()}
106+
87107
msg_dict = {
88108
"client_id": tracker.client_id,
89109
"ip_address": ip,
90110
"type": "producer",
91-
"message_type": "client_stats" if not error else "client_info",
111+
"message_type": "client_stats",
92112
"version": _VERSION,
93113
"topics": sorted(tracker.topics),
94-
"original_configuration": {k: mask_sensitive(k, v) for k, v in tracker.orig_cfg.items()},
95-
"optimized_configuration": {k: mask_sensitive(k, v) for k, v in tracker.opt_cfg.items()},
114+
"original_configuration": orig_cfg_masked,
115+
"optimized_configuration": opt_cfg_masked,
96116
"environment_variables": {k: v for k, v in os.environ.items() if k.startswith("SUPERSTREAM_")},
97117
"hostname": hostname,
98118
"superstream_client_uid": tracker.uuid,
99119
"most_impactful_topic": tracker.determine_topic(),
100-
"language": "Python",
120+
"language": f"Python ({tracker.library})",
101121
"error": error,
102122
}
103123
payload = json.dumps(msg_dict).encode()
104-
internal_send_clients(tracker.bootstrap, tracker.orig_cfg, payload)
124+
internal_send_clients(tracker.bootstrap, tracker.orig_cfg, payload, tracker.library)
105125
logger.debug("Sent clients message for {}", tracker.client_id)

superclient/agent/interceptor.py

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
import os
44
from typing import Any, Dict
55

6-
from ..logger import get_logger
6+
from ..util.logger import get_logger
77
from ..util.config import get_topics_list, is_disabled
8-
from ..core.manager import fetch_metadata, optimal_cfg
8+
from .metadata import fetch_metadata, optimal_cfg
99
from ..core.reporter import send_clients_msg
1010
from .tracker import ProducerTracker, Heartbeat
1111

@@ -30,12 +30,17 @@ def init_patch(self, *args, **kwargs):
3030
bootstrap = orig_cfg.get("bootstrap_servers") or (args[0] if args else None)
3131
if not bootstrap:
3232
return orig_init(self, *args, **kwargs)
33+
bootstrap = normalize_bootstrap(bootstrap)
3334
client_id = orig_cfg.get("client_id", "")
3435
if client_id.startswith(_SUPERLIB_PREFIX):
3536
return orig_init(self, *args, **kwargs)
3637
topics_env = get_topics_list()
37-
metadata = fetch_metadata(bootstrap, orig_cfg)
38-
opt_cfg = optimal_cfg(metadata, topics_env, orig_cfg)
38+
metadata = fetch_metadata(bootstrap, orig_cfg, "kafka-python")
39+
error_msg = ""
40+
if metadata and not metadata.active:
41+
error_msg = "[ERR-301] Superstream optimization is not active for this kafka cluster, please head to the Superstream console and activate it."
42+
logger.error(error_msg)
43+
opt_cfg = optimal_cfg(metadata, topics_env, orig_cfg) if metadata and metadata.active else {}
3944
for k, v in opt_cfg.items():
4045
snake = k.replace(".", "_")
4146
if kwargs.get(snake) != v:
@@ -64,13 +69,15 @@ def send_patch(inner, topic, *a, **kw):
6469
orig_close = self.close
6570

6671
def close_patch(inner, *a, **kw):
67-
tr.close()
68-
Heartbeat.unregister_tracker(tr.uuid)
72+
if not hasattr(self, "_superstream_closed"):
73+
self._superstream_closed = True
74+
tr.close()
75+
Heartbeat.unregister_tracker(tr.uuid)
6976
return orig_close(*a, **kw)
7077

7178
self.close = close_patch
7279
self._superstream_patch = True
73-
send_clients_msg(tr)
80+
send_clients_msg(tr, error_msg)
7481
logger.info("Successfully optimized producer configuration for {}", client_id)
7582

7683
Producer.__init__ = init_patch
@@ -92,12 +99,17 @@ def init_patch(self, *args, **kwargs):
9299
bootstrap = args[0]
93100
if not bootstrap:
94101
return orig_init(self, *args, **kwargs)
102+
bootstrap = normalize_bootstrap(bootstrap)
95103
client_id = orig_cfg.get("client_id", "")
96104
if client_id.startswith(_SUPERLIB_PREFIX):
97105
return orig_init(self, *args, **kwargs)
98106
topics_env = get_topics_list()
99-
metadata = fetch_metadata(bootstrap, orig_cfg)
100-
opt_cfg = optimal_cfg(metadata, topics_env, orig_cfg)
107+
metadata = fetch_metadata(bootstrap, orig_cfg, "aiokafka")
108+
error_msg = ""
109+
if metadata and not metadata.active:
110+
error_msg = "[ERR-301] Superstream optimization is not active for this kafka cluster, please head to the Superstream console and activate it."
111+
logger.error(error_msg)
112+
opt_cfg = optimal_cfg(metadata, topics_env, orig_cfg) if metadata and metadata.active else {}
101113
for k, v in opt_cfg.items():
102114
if kwargs.get(k) != v:
103115
logger.debug("Overriding configuration: {} -> {}", k, v)
@@ -125,13 +137,15 @@ async def send_patch(inner, topic, *a, **kw):
125137
original_stop = self.stop
126138

127139
async def stop_patch(inner, *a, **kw):
140+
if not hasattr(self, "_superstream_closed"):
141+
self._superstream_closed = True
142+
tr.close()
143+
Heartbeat.unregister_tracker(tr.uuid)
128144
await original_stop(*a, **kw)
129-
tr.close()
130-
Heartbeat.unregister_tracker(tr.uuid)
131145

132146
self.stop = stop_patch
133147
self._superstream_patch = True
134-
send_clients_msg(tr)
148+
send_clients_msg(tr, error_msg)
135149
logger.info("Successfully optimized producer configuration for {}", client_id)
136150

137151
Producer.__init__ = init_patch
@@ -149,12 +163,19 @@ def init_patch(self, conf: Dict[str, Any], *args, **kwargs):
149163
return orig_init(self, conf, *args, **kwargs)
150164
conf = dict(conf)
151165
bootstrap = conf.get("bootstrap.servers")
166+
if not bootstrap:
167+
return orig_init(self, conf, *args, **kwargs)
168+
bootstrap = normalize_bootstrap(bootstrap)
152169
client_id = conf.get("client.id", "")
153170
if client_id.startswith(_SUPERLIB_PREFIX):
154171
return orig_init(self, conf, *args, **kwargs)
155172
topics_env = get_topics_list()
156-
metadata = fetch_metadata(bootstrap, conf)
157-
opt_cfg = optimal_cfg(metadata, topics_env, conf)
173+
metadata = fetch_metadata(bootstrap, conf, "confluent")
174+
error_msg = ""
175+
if metadata and not metadata.active:
176+
error_msg = "[ERR-301] Superstream optimization is not active for this kafka cluster, please head to the Superstream console and activate it."
177+
logger.error(error_msg)
178+
opt_cfg = optimal_cfg(metadata, topics_env, conf) if metadata and metadata.active else {}
158179
for k, v in opt_cfg.items():
159180
if conf.get(k) != v:
160181
logger.debug("Overriding configuration: {} -> {}", k, v)
@@ -179,25 +200,18 @@ def produce_patch(inner, topic, *a, **kw):
179200
return original_produce(topic, *a, **kw)
180201

181202
self.produce = produce_patch
182-
orig_flush = self.flush
183-
184-
def flush_patch(inner, *a, **kw):
185-
tr.close()
186-
Heartbeat.unregister_tracker(tr.uuid)
187-
return orig_flush(*a, **kw)
188-
189-
self.flush = flush_patch
190-
if hasattr(self, "close"):
191-
orig_close = self.close
203+
orig_close = self.close
192204

193-
def close_patch(inner, *a, **kw):
205+
def close_patch(inner, *a, **kw):
206+
if not hasattr(self, "_superstream_closed"):
207+
self._superstream_closed = True
194208
tr.close()
195209
Heartbeat.unregister_tracker(tr.uuid)
196-
return orig_close(*a, **kw)
210+
return orig_close(*a, **kw)
197211

198-
self.close = close_patch
212+
self.close = close_patch
199213
self._superstream_patch = True
200-
send_clients_msg(tr)
214+
send_clients_msg(tr, error_msg)
201215
logger.info("Successfully optimized producer configuration for {}", client_id)
202216

203217
Producer.__init__ = init_patch

0 commit comments

Comments
 (0)