Docs
Django
Classic-Django recipes: a shared client module, one-line track() in views, login auditing via signals, and a feed-token view plus template.
1. Install and initialize
pip install softechlog, set SOFTECHLOG_SECRET_KEY in your environment (or via django-environ), and create one module-level client:
myproject/softechlog.pyPython SDK
# myproject/softechlog.py — one client, imported everywhere import os from softechlog import Softechlog log = Softechlog(secret_key=os.environ["SOFTECHLOG_SECRET_KEY"])
2. Track in views
members/views.pytrack()
# members/views.py
from myproject.softechlog import log
def invite_member(request, workspace_id):
invitee = do_invite(workspace_id, request.POST)
# track() never raises — returns None on failure, logs a warning
log.track(
actor={"id": str(request.user.pk),
"name": request.user.get_full_name(),
"email": request.user.email},
action="workspace.member.invited",
target_type="workspace", target_id=str(workspace_id),
metadata={"invited_email": invitee.email, "role": invitee.role},
)
return JsonResponse({"ok": True}, status=201)Running async views or Django 5 with ASGI? The client also exposes
await log.atrack(...) with identical arguments.3. Audit auth events with signals
Login and failed-login events are the classic audit-trail requirement, and Django already emits signals for them — no view changes needed:
audit/signals.pydjango signals
# audit/signals.py — catch auth events without touching views
from django.contrib.auth.signals import user_logged_in, user_login_failed
from django.dispatch import receiver
from myproject.softechlog import log
@receiver(user_logged_in)
def on_login(sender, request, user, **kwargs):
log.track(
actor={"id": str(user.pk), "email": user.email},
action="auth.login.succeeded",
context={"ip_address": request.META.get("REMOTE_ADDR"),
"user_agent": request.META.get("HTTP_USER_AGENT")},
)
@receiver(user_login_failed)
def on_login_failed(sender, credentials, request, **kwargs):
log.track(
actor={"id": credentials.get("username", "unknown")},
action="auth.login.failed",
)Register the module in your app's AppConfig.ready() as usual.
4. Feed token view + template
activity/views.pyfeed_token()
# activity/views.py — feed token for the signed-in user
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
from softechlog import SoftechlogError
from myproject.softechlog import log
@login_required
def activity_token(request):
try:
ft = log.feed_token(actor_id=str(request.user.pk), ttl_seconds=3600)
except SoftechlogError:
return JsonResponse({"error": "token unavailable"}, status=502)
return JsonResponse({"token": ft.token, "expires_at": ft.expires_at})activity.htmltemplate
<!-- templates/settings/activity.html -->
<script src="https://softechlog.com/feed.js"></script>
<softechlog-feed id="feed"></softechlog-feed>
<script>
fetch('{% url "activity_token" %}')
.then((r) => r.json())
.then(({ token }) => document.getElementById('feed').setAttribute('feed-token', token));
</script>