TokenViz provides lightweight token usage visualization for LLM systems using Unix tools. This simulates what would typically be monitored through enterprise observability platforms, making it useful for local development and pattern analysis.
# Launch dashboard (local)
make dashboard
# For container environments
DISPLAY=:1 make dashboard
# View status
make status
# Clean up
make stop
flowchart TD
subgraph Generators["Token Generators"]
G1["Generator 1\n(Random 0-3000)"]
G2["Generator 2\n(Random 0-3000)"]
G3["Generator 3\n(Random 0-3000)"]
end
subgraph Storage["Storage Layer"]
L1["/tmp/tokenload/gen1.log"]
L2["/tmp/tokenload/gen2.log"]
L3["/tmp/tokenload/gen3.log"]
end
subgraph Processing["Aggregation Layer"]
A1["Aggregator\n(Sum all inputs)"]
P1["Named Pipe\n/tmp/tokenload_pipe"]
D1["Data File\n/tmp/tokenload_data"]
end
subgraph Display["Visualization Layer"]
V1["tmux pane 1\nGenerator Logs"]
V2["tmux pane 2\nTotal Usage"]
V3["tmux pane 3\nxload Graph"]
end
G1 --> L1
G2 --> L2
G3 --> L3
L1 & L2 & L3 --> A1
A1 --> P1
A1 --> D1
L1 & L2 & L3 --> V1
D1 --> V2
P1 --> V3
sequenceDiagram
participant G as Generators
participant L as Log Files
participant A as Aggregator
participant P as Named Pipe
participant D as Display
loop Every Second
G->>L: Write random token counts
L->>A: Read latest values
A->>P: Write sum to pipe
A->>D: Update display
end
# TokenViz Configuration
SHELL := /bin/bash
.PHONY: all clean test dashboard stop setup generators aggregator test-tmux test-xload status logs kill-all restart
# Check if we're in a container and set DISPLAY accordingly
CONTAINER_CHECK := $(shell test -f /.dockerenv && echo 1 || echo 0)
ifeq ($(CONTAINER_CHECK),1)
XDISPLAY := :1
else
XDISPLAY := :0
endif
# Paths
PIPE := /tmp/tokenload_pipe
DATA := /tmp/tokenload_data
LOGDIR := /tmp/tokenload
SESSION := tokenviz
# Default target
.DEFAULT_GOAL := help
help: ## Show this help message
@echo 'Usage: make [target]'
@echo
@echo 'Targets:'
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
setup: ## Setup
@echo "Setting up directories and files..."
@rm -rf $(LOGDIR) || true
@mkdir -p $(LOGDIR)
@rm -f $(PIPE) || true
@mkfifo $(PIPE)
@touch $(DATA)
@for i in 1 2 3; do echo "Initializing gen$$i..." > $(LOGDIR)/gen$$i.log; done
generators: setup ## Generators
@for i in 1 2 3; do \
( \
while true; do \
if [ -d "$(LOGDIR)" ]; then \
echo "gen$$i: $$((RANDOM % 3000))" >> "$(LOGDIR)/gen$$i.log"; \
else \
exit 0; \
fi; \
sleep 1; \
done \
) & \
done
aggregator: setup ## Aggregator
@( \
while true; do \
if [ -d "$(LOGDIR)" ]; then \
TOTAL=0; \
for f in $(LOGDIR)/gen*.log; do \
if [ -f "$$f" ]; then \
VAL=$$(tail -n1 "$$f" 2>/dev/null | grep -o '[0-9]*$$' || echo 0); \
TOTAL=$$((TOTAL + VAL)); \
fi; \
done; \
echo "$$TOTAL" > "$(PIPE)" 2>/dev/null || exit 0; \
echo "[`date '+%H:%M:%S'`] Total: $$TOTAL" > "$(DATA)" 2>/dev/null || exit 0; \
else \
exit 0; \
fi; \
sleep 1; \
done \
) &
dashboard: setup ## Dashboard
@echo "Starting dashboard with DISPLAY=$(XDISPLAY)..."
@tmux new-session -d -s $(SESSION) -n 'TokenViz' \; \
split-window -h \; \
split-window -h \; \
select-layout even-horizontal \; \
send-keys -t 0 "while true; do clear; tail -n 10 $(LOGDIR)/gen*.log 2>/dev/null || echo 'Waiting for data...'; sleep 1; done" C-m \; \
send-keys -t 1 "while true; do clear; tail -n 10 $(DATA) 2>/dev/null || echo 'Waiting for data...'; sleep 1; done" C-m \; \
send-keys -t 2 "DISPLAY=$(XDISPLAY) xload -geometry 400x200+100+100 -bg black -fg green -scale 5 < $(PIPE)" C-m \; \
select-pane -t 0
@echo "Starting generators..."
@$(MAKE) generators
@echo "Starting aggregator..."
@$(MAKE) aggregator
@echo "Attaching to session..."
@tmux attach -t $(SESSION)
stop: ## Stop all processes
@echo "Stopping all processes..."
@pkill -f "/bin/bash.*while true.*gen" 2>/dev/null || true
@pkill -f "while true.*TOTAL" 2>/dev/null || true
@tmux kill-session -t $(SESSION) 2>/dev/null || true
@rm -f $(PIPE) $(DATA) 2>/dev/null || true
@rm -rf $(LOGDIR) 2>/dev/null || true
@echo "All processes stopped"
kill-all: ## Emergency cleanup
@echo "Emergency cleanup in progress..."
@ps ax | grep "gen.*RANDOM" | grep -v grep | awk '{print $$1}' | xargs kill -9 2>/dev/null || true
@pkill -f "while true.*TOTAL" 2>/dev/null || true
@echo "Emergency cleanup complete"
restart: stop dashboard ## Restart all services
status: ## Status
@echo "TokenViz Status:"
@echo "---------------"
@echo "Environment: $$([ $(CONTAINER_CHECK) -eq 1 ] && echo 'Container' || echo 'Local')"
@echo "Display: $(XDISPLAY)"
@echo "\nGenerator processes:"
@ps ax | grep "while true.*gen" | grep -v grep || echo "No generators running"
@echo "\nAggregator process:"
@ps ax | grep "while true.*TOTAL" | grep -v grep || echo "No aggregator running"
@echo "\nTmux session:"
@tmux has-session -t $(SESSION) 2>/dev/null && echo "Session $(SESSION) is running" || echo "No session running"
logs: ## Logs
@echo "Last 5 lines from each generator:"
@for i in 1 2 3; do \
echo "\nGenerator $$i:"; \
tail -n 5 "$(LOGDIR)/gen$$i.log" 2>/dev/null || echo "No log file"; \
done
@echo "\nLast 5 lines from aggregator:"
@tail -n 5 "$(DATA)" 2>/dev/null || echo "No aggregator data"
test-display: ## Test display
@echo "Container detection: $(CONTAINER_CHECK)"
@echo "Using DISPLAY=$(XDISPLAY)"
@echo "Testing X11 connection..."
@if DISPLAY=$(XDISPLAY) xdpyinfo >/dev/null 2>&1; then \
echo "X11 connection successful"; \
else \
echo "X11 connection failed"; \
exit 1; \
fi
test-display: ## Test display
@echo "Container detection: $(CONTAINER_CHECK)"
@echo "Using DISPLAY=$(XDISPLAY)"
@echo "Testing X11 connection..."
@if DISPLAY=$(XDISPLAY) xdpyinfo >/dev/null 2>&1; then \
echo "X11 connection successful"; \
else \
echo "X11 connection failed"; \
exit 1; \
fi
FROM ubuntu:22.04
# Install required packages
RUN apt-get update && apt-get install -y \
tmux \
x11-apps \
xauth \
make \
&& rm -rf /var/lib/apt/lists/*
# Set up working directory
WORKDIR /app
# Copy application files
COPY . .
# Set display for X11
ENV DISPLAY=:1
# Default command
CMD ["make", "dashboard"]
flowchart LR
subgraph LLMs["LLM Services"]
L1["Service 1"]
L2["Service 2"]
L3["Service 3"]
end
subgraph Queue["Message Queue"]
Q1["SNS Topic\nToken Usage"]
Q2["SQS Queue\nAggregation"]
end
subgraph Monitor["Monitoring"]
M1["CloudWatch\nMetrics"]
M2["CloudWatch\nDashboard"]
end
L1 & L2 & L3 --> Q1
Q1 --> Q2
Q2 --> M1
M1 --> M2
flowchart LR
subgraph LLMs["LLM Services"]
L1["Service 1"]
L2["Service 2"]
L3["Service 3"]
end
subgraph Kafka["Kafka Cluster"]
K1["Topic: token-usage"]
K2["Topic: aggregated-usage"]
end
subgraph Process["Processing"]
P1["Kafka Streams\nAggregation"]
end
subgraph Monitor["Monitoring"]
M1["Metrics API"]
M2["Dashboard"]
end
L1 & L2 & L3 --> K1
K1 --> P1
P1 --> K2
K2 --> M1
M1 --> M2
flowchart LR
subgraph LLMs["LLM Services"]
L1["Service 1\n/metrics"]
L2["Service 2\n/metrics"]
L3["Service 3\n/metrics"]
end
subgraph Collect["Collection"]
C1["Prometheus\nServer"]
end
subgraph Visual["Visualization"]
V1["Grafana\nDashboard"]
end
L1 & L2 & L3 --> C1
C1 --> V1
# Contributing to TokenViz
## Development Setup
1. Fork and clone the repository
2. Ensure XQuartz is installed (macOS)
3. Run tests: `make test`
4. Submit PR with clear description
## Container Development
```bash
# Build container
docker build -t tokenviz .
# Run with X11 socket mounted
docker run -v /tmp/.X11-unix:/tmp/.X11-unix tokenviz
```
## Testing
- Run `make test-display` to verify X11 setup
- Run `make test` for full test suite
- Ensure clean shutdown with `make stop`