Initial loki skill with promtail auto-discovery

This commit is contained in:
Azat
2026-02-02 22:35:36 +01:00
commit 2aac1371b2
3 changed files with 363 additions and 0 deletions

226
scripts/autorun.sh Normal file
View File

@@ -0,0 +1,226 @@
#!/bin/bash
set -e
LOKI_VERSION="${LOKI_VERSION:-3.0.0}"
SKILLS_DIR="${SKILLS_DIR:-/skills}"
LOKI_DATA_DIR="${LOKI_DATA_DIR:-/data/loki}"
SUPERVISOR_LOG_DIR="${SUPERVISOR_LOG_DIR:-/var/log/supervisor}"
SKILL_DIR="$(dirname "$(dirname "$0")")"
# Detect architecture
get_arch() {
case "$(uname -m)" in
x86_64) echo "amd64" ;;
aarch64) echo "arm64" ;;
armv7l) echo "arm" ;;
*)
echo "Unsupported architecture: $(uname -m)" >&2
exit 1
;;
esac
}
# Install Loki
install_loki() {
if command -v loki &>/dev/null; then
echo "loki already installed"
return 0
fi
echo "Installing Loki v${LOKI_VERSION}..."
local arch=$(get_arch)
local url="https://github.com/grafana/loki/releases/download/v${LOKI_VERSION}/loki-linux-${arch}.zip"
apt-get update && apt-get install -y unzip
curl -sSL "$url" -o /tmp/loki.zip
unzip -o /tmp/loki.zip -d /tmp
mv /tmp/loki-linux-${arch} /usr/local/bin/loki
chmod +x /usr/local/bin/loki
rm /tmp/loki.zip
echo "Loki installed"
}
# Install Promtail
install_promtail() {
if command -v promtail &>/dev/null; then
echo "promtail already installed"
return 0
fi
echo "Installing Promtail v${LOKI_VERSION}..."
local arch=$(get_arch)
local url="https://github.com/grafana/loki/releases/download/v${LOKI_VERSION}/promtail-linux-${arch}.zip"
curl -sSL "$url" -o /tmp/promtail.zip
unzip -o /tmp/promtail.zip -d /tmp
mv /tmp/promtail-linux-${arch} /usr/local/bin/promtail
chmod +x /usr/local/bin/promtail
rm /tmp/promtail.zip
echo "Promtail installed"
}
# Setup directories
setup_dirs() {
mkdir -p "$LOKI_DATA_DIR"
mkdir -p "$SKILL_DIR/config"
echo "Data directory: $LOKI_DATA_DIR"
}
# Generate Loki config
generate_loki_config() {
local retention="${LOKI_RETENTION:-168h}"
cat > "$SKILL_DIR/config/loki.yaml" << EOF
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
common:
instance_addr: 127.0.0.1
path_prefix: $LOKI_DATA_DIR
storage:
filesystem:
chunks_directory: $LOKI_DATA_DIR/chunks
rules_directory: $LOKI_DATA_DIR/rules
replication_factor: 1
ring:
kvstore:
store: inmemory
query_range:
results_cache:
cache:
embedded_cache:
enabled: true
max_size_mb: 100
schema_config:
configs:
- from: 2020-10-24
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
limits_config:
retention_period: $retention
ruler:
alertmanager_url: http://localhost:9093
analytics:
reporting_enabled: false
EOF
echo "Loki config written to $SKILL_DIR/config/loki.yaml"
}
# Generate Promtail config with auto-discovered log paths
generate_promtail_config() {
cat > "$SKILL_DIR/config/promtail.yaml" << EOF
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://localhost:3100/loki/api/v1/push
scrape_configs:
# Supervisor logs (all skills)
- job_name: skills
static_configs:
- targets:
- localhost
labels:
job: skills
__path__: $SUPERVISOR_LOG_DIR/*.log
pipeline_stages:
# Extract skill name from filename
- match:
selector: '{job="skills"}'
stages:
- regex:
source: filename
expression: '.*/(?P<skill>[^/]+)\\.log$'
- labels:
skill:
# Supervisor error logs
- job_name: skills_errors
static_configs:
- targets:
- localhost
labels:
job: skills
level: error
__path__: $SUPERVISOR_LOG_DIR/*.err
pipeline_stages:
- match:
selector: '{job="skills"}'
stages:
- regex:
source: filename
expression: '.*/(?P<skill>[^/]+)\\.err$'
- labels:
skill:
EOF
echo "Promtail config written to $SKILL_DIR/config/promtail.yaml"
}
# Configure Caddy if present
configure_caddy() {
local caddy_dir="$SKILLS_DIR/caddy"
local loki_port="${LOKI_PORT:-3100}"
local loki_domain="${LOKI_DOMAIN:-}"
if [ ! -d "$caddy_dir" ]; then
echo "Caddy not found - Loki API on port $loki_port"
return 0
fi
echo "Caddy detected - configuring reverse proxy..."
mkdir -p "$caddy_dir/snippets.d"
local snippet="$caddy_dir/snippets.d/loki.caddy"
if [ -n "$loki_domain" ]; then
cat > "$snippet" << EOF
# Auto-generated by loki skill
$loki_domain {
reverse_proxy localhost:$loki_port
}
EOF
echo "Caddy config: $loki_domain -> localhost:$loki_port"
else
cat > "$snippet" << EOF
# Auto-generated by loki skill
# Add to your site block:
# handle /loki/* {
# reverse_proxy localhost:$loki_port
# }
EOF
echo "Caddy snippet created (manual config needed)"
fi
}
install_loki
install_promtail
setup_dirs
generate_loki_config
generate_promtail_config
configure_caddy
echo "Loki setup complete"

50
scripts/run.sh Normal file
View File

@@ -0,0 +1,50 @@
#!/bin/bash
set -e
SKILL_DIR="$(dirname "$(dirname "$0")")"
LOKI_PORT="${LOKI_PORT:-3100}"
# Start Loki in background
start_loki() {
echo "Starting Loki on port $LOKI_PORT..."
loki -config.file="$SKILL_DIR/config/loki.yaml" &
LOKI_PID=$!
sleep 3
if ! kill -0 $LOKI_PID 2>/dev/null; then
echo "Failed to start Loki"
exit 1
fi
echo "Loki running (PID $LOKI_PID)"
}
# Start Promtail in background
start_promtail() {
echo "Starting Promtail..."
promtail -config.file="$SKILL_DIR/config/promtail.yaml" &
PROMTAIL_PID=$!
sleep 2
if ! kill -0 $PROMTAIL_PID 2>/dev/null; then
echo "Failed to start Promtail"
exit 1
fi
echo "Promtail running (PID $PROMTAIL_PID)"
}
# Cleanup on exit
cleanup() {
echo "Shutting down..."
[ -n "$PROMTAIL_PID" ] && kill $PROMTAIL_PID 2>/dev/null
[ -n "$LOKI_PID" ] && kill $LOKI_PID 2>/dev/null
exit 0
}
trap cleanup SIGTERM SIGINT
start_loki
start_promtail
echo "Loki stack running. Query at http://localhost:$LOKI_PORT/loki/api/v1/query"
# Wait for either process to exit
wait