Utility-Module mit Logging, Decorators, Validation und Rate-Limiting.
from trixy_core.utils import (
# Debug-Funktionen
pinfo, pdebug, perror, pwarn, set_debug_mode,
# Version
VERSION, VERSION_STRING, PROTOCOL_VERSION,
)
Gibt eine Info-Nachricht aus.
from trixy_core.utils import pinfo
pinfo("Server gestartet auf Port %d", 2101)
Gibt eine Debug-Nachricht aus (nur wenn Debug-Modus aktiv).
from trixy_core.utils import pdebug
pdebug("Empfangene Daten: %s", data)
Gibt eine Fehlermeldung aus.
from trixy_core.utils import perror
perror("Verbindung fehlgeschlagen: %s", error)
Gibt eine Warnung aus.
from trixy_core.utils import pwarn
pwarn("Konfiguration fehlt, verwende Standardwerte")
Aktiviert/deaktiviert den Debug-Modus.
from trixy_core.utils import set_debug_mode
set_debug_mode(True) # Debug-Ausgaben aktivieren
Strukturiertes Logging mit JSON-Unterstützung und Correlation-IDs.
from trixy_core.utils.logging import (
StructuredLogger,
get_logger,
LogContext,
get_correlation_id,
set_correlation_id,
JSONFormatter,
TextFormatter,
)
Logger mit strukturierter Ausgabe und Kontext-Propagation.
from trixy_core.utils.logging import StructuredLogger
logger = StructuredLogger("my_module")
# Einfaches Logging
logger.info("Benutzer angemeldet", user_id=123, ip="192.168.1.1")
# Mit Kontext
with logger.context(request_id="abc123"):
logger.debug("Verarbeite Anfrage")
logger.info("Anfrage abgeschlossen", duration=0.5)
# Fehler mit Traceback
try:
process()
except Exception as e:
logger.exception("Verarbeitung fehlgeschlagen", error=str(e))
Methoden:
| Methode | Beschreibung |
|---|---|
debug(msg, **kwargs) |
Debug-Level |
info(msg, **kwargs) |
Info-Level |
warning(msg, **kwargs) |
Warning-Level |
error(msg, **kwargs) |
Error-Level |
exception(msg, **kwargs) |
Error mit Traceback |
context(**kwargs) |
Context-Manager für zusätzliche Felder |
Kontext für Request-Tracing.
from trixy_core.utils.logging import LogContext, set_correlation_id
# Correlation-ID setzen
set_correlation_id("req-12345")
# Kontext für alle nachfolgenden Logs
with LogContext(user_id=123, session="abc"):
logger.info("Operation gestartet")
from trixy_core.utils.logging import JSONFormatter, TextFormatter, CompactFormatter
# JSON für Produktion
json_formatter = JSONFormatter(include_timestamp=True)
# Text für Entwicklung
text_formatter = TextFormatter(colorize=True)
# Kompakt für Logs
compact_formatter = CompactFormatter()
Wiederverwendbare Decorators für Timing, Caching, Retry und Validation.
from trixy_core.utils.decorators import (
timed, async_timed, profile,
cached, async_cached, cache_clear,
retry, async_retry,
deprecated, pending_deprecation,
validate, validate_args, validate_return,
)
Misst und loggt die Ausführungszeit.
from trixy_core.utils.decorators import timed, async_timed
@timed(name="db_query", threshold=0.5)
def query_database(sql: str) -> list:
return db.execute(sql)
@async_timed(name="api_call")
async def fetch_api(url: str) -> dict:
async with session.get(url) as response:
return await response.json()
Parameter:
| Parameter | Typ | Default | Beschreibung |
|---|---|---|---|
name |
str |
Funktionsname | Name für Logs |
threshold |
float |
None |
Warnung wenn überschritten |
logger |
Logger |
None |
Benutzerdefinierter Logger |
LRU-Cache mit optionalem TTL.
from trixy_core.utils.decorators import cached, async_cached, cache_clear
@cached(ttl=300, max_size=100)
def get_user(user_id: int) -> User:
return db.query(User).get(user_id)
@async_cached(ttl=60)
async def fetch_config(key: str) -> dict:
return await redis.get(key)
# Cache leeren
cache_clear(get_user)
Parameter:
| Parameter | Typ | Default | Beschreibung |
|---|---|---|---|
ttl |
float |
None |
Time-to-live in Sekunden |
max_size |
int |
128 |
Maximale Cache-Größe |
key_func |
Callable |
None |
Benutzerdefinierte Key-Funktion |
Wiederholt bei Fehlern mit Backoff.
from trixy_core.utils.decorators import retry, async_retry, RetryConfig
@retry(max_attempts=3, backoff=1.0, exceptions=(ConnectionError, TimeoutError))
def connect_to_server(host: str) -> Connection:
return socket.connect(host)
@async_retry(max_attempts=5, backoff=2.0, jitter=0.5)
async def send_request(data: dict) -> Response:
return await client.post("/api", json=data)
# Mit Konfiguration
config = RetryConfig(
max_attempts=3,
backoff=1.0,
max_backoff=30.0,
jitter=0.1,
exceptions=(IOError,),
)
@retry(config=config)
def read_file(path: str) -> str:
return Path(path).read_text()
Parameter:
| Parameter | Typ | Default | Beschreibung |
|---|---|---|---|
max_attempts |
int |
3 |
Maximale Versuche |
backoff |
float |
1.0 |
Basis-Wartezeit |
max_backoff |
float |
60.0 |
Maximale Wartezeit |
jitter |
float |
0.0 |
Zufällige Variation |
exceptions |
tuple |
(Exception,) |
Zu fangene Exceptions |
Markiert Funktionen als veraltet.
from trixy_core.utils.decorators import deprecated, pending_deprecation
@deprecated(message="Verwende new_function() stattdessen", version="2.0.0")
def old_function():
pass
@pending_deprecation(message="Wird in 3.0.0 entfernt")
def legacy_function():
pass
Validiert Funktionsparameter.
from trixy_core.utils.decorators import validate, validate_args, validate_return
@validate(
name=str,
age=(int, lambda x: x >= 0),
email=(str, lambda x: "@" in x),
)
def create_user(name: str, age: int, email: str) -> User:
return User(name=name, age=age, email=email)
@validate_args(
url=(str, lambda x: x.startswith("http")),
)
@validate_return(dict)
async def fetch_json(url: str) -> dict:
return await client.get(url).json()
Token-Bucket und Sliding-Window Rate-Limiting.
from trixy_core.utils.ratelimit import (
TokenBucket,
SlidingWindow,
rate_limit,
async_rate_limit,
RateLimitExceeded,
RateLimitConfig,
)
Token-Bucket-Algorithmus für Rate-Limiting.
from trixy_core.utils.ratelimit import TokenBucket
# 10 Requests pro Sekunde
bucket = TokenBucket(rate=10, capacity=10)
if bucket.consume():
process_request()
else:
raise RateLimitExceeded("Zu viele Anfragen")
# Mehrere Tokens auf einmal
if bucket.consume(tokens=5):
process_batch()
Parameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
rate |
float |
Tokens pro Sekunde |
capacity |
int |
Maximale Token-Anzahl |
Sliding-Window-Algorithmus für präziseres Limiting.
from trixy_core.utils.ratelimit import SlidingWindow
# 100 Requests pro Minute
window = SlidingWindow(limit=100, window_size=60)
if window.allow():
process_request()
else:
retry_after = window.retry_after()
raise RateLimitExceeded(f"Retry nach {retry_after}s")
from trixy_core.utils.ratelimit import rate_limit, async_rate_limit
@rate_limit(rate=10, capacity=10)
def api_endpoint(request):
return process(request)
@async_rate_limit(limit=100, window_size=60, strategy="sliding_window")
async def async_endpoint(request):
return await process(request)
Schema-basierte Validierung für Dictionaries und Dataclasses.
from trixy_core.utils.validation import (
# Validators
TypeValidator, RangeValidator, PatternValidator,
LengthValidator, RequiredValidator, EnumValidator,
ListValidator, DictValidator, CompositeValidator,
# Schema
Schema, Field, NestedField, ListField,
# Functions
validate_dict, validate_dataclass,
# Exceptions
ValidationError, ValidationErrors,
)
from trixy_core.utils.validation import (
TypeValidator, RangeValidator, PatternValidator,
LengthValidator, CompositeValidator,
)
# Typ-Validierung
type_v = TypeValidator(int)
type_v.validate(42) # OK
type_v.validate("42") # ValidationError
# Bereichs-Validierung
range_v = RangeValidator(min_value=0, max_value=100)
range_v.validate(50) # OK
# Pattern-Validierung
pattern_v = PatternValidator(r"^[a-z]+@[a-z]+\.[a-z]+$")
pattern_v.validate("user@example.com") # OK
# Längen-Validierung
length_v = LengthValidator(min_length=3, max_length=50)
length_v.validate("hello") # OK
# Kombinierte Validierung
composite = CompositeValidator([
TypeValidator(str),
LengthValidator(min_length=1),
PatternValidator(r"^[A-Za-z]+$"),
])
composite.validate("Hello") # OK
from trixy_core.utils.validation import Schema, Field, NestedField, ListField
class UserSchema(Schema):
name = Field(str, required=True, min_length=1, max_length=100)
age = Field(int, required=True, min_value=0, max_value=150)
email = Field(str, required=True, pattern=r"^.+@.+\..+$")
roles = ListField(str, min_items=1)
address = NestedField(AddressSchema, required=False)
# Validieren
schema = UserSchema()
errors = schema.validate({
"name": "Max",
"age": 25,
"email": "max@example.com",
"roles": ["user"],
})
if errors:
for error in errors:
print(f"{error.field}: {error.message}")
from trixy_core.utils.validation import validate_dict
schema = {
"name": {"type": str, "required": True},
"age": {"type": int, "min": 0},
"tags": {"type": list, "items": str},
}
data = {"name": "Test", "age": 25, "tags": ["a", "b"]}
errors = validate_dict(data, schema)