עם ניסיון של 7+ שנים ולמעלה מ-40 התקנות production, אנו מספקים מערכות Loki חזקות. לוגים מפוזרים על פני עשרות שרתים — מציאת שורש התקלה הופכת למסע של שבוע. בעומסי שיא, לוגים אובדים, וחיפוש שגיאה לוקח שעות. אנו פותרים זאת ביום אחד: הקמת ריכוז לוגים מרכזי עם Grafana Loki ו-Promtail. בניגוד ל-ELK, Loki אינו מבצע אינדקס לתוכן, אלא רק לתוויות (labels). בפועל, זה מניב חיסכון של עד 70% באחסון ופי שניים עד שלושה פחות עומס תפעולי. בפרויקט אחד עם 50 מיקרוסרוויסים (10 מיליון בקשות ביום), צמצמנו את זמן הגילוי מיומיים ל-15 דקות. צרו קשר — נשלים את ההתקנה תוך 2-3 ימים. עלות התקנה בסיסית מתחילה ב-$500 עבור המערכת (Loki, Promtail, Grafana על Docker; מקור לוג אחד).
למה Loki עדיף על Elasticsearch
לפי הנתונים הרשמיים של Grafana Labs, Loki מספק חיסכון של עד 70% באחסון בהשוואה ל-ELK. עם 500 GB של לוגים ביום, החיסכון החודשי יכול להגיע ל-$10,000. Loki מאחסן לוגים בנתחים דחוסים ללא אינדקס הפוך. מהירות השאילתה לפי תוויות היא במילישניות. אם אין צורך באגרגציה מורכבת על שדות שרירותיים, Loki הוא הבחירה הנכונה. החיסכון בתשתית יכול לנוע בין $5,000 ל-$15,000 בחודש בהתאם לנפח הלוגים.
| קריטריון | Loki | ELK |
|---|---|---|
| עלות אחסון | נמוכה (נתחים דחוסים) | גבוהה (אינדקס הפוך) |
| מהירות חיפוש לפי תוויות | מהירה | בינונית |
| חיפוש טקסט מלא | מוגבל | מלא |
| מורכבות תפעולית | נמוכה (קובץ בינארי יחיד) | גבוהה (שלוש מערכות) |
| אינטגרציה עם Grafana | טבעית | דרך תוסף |
כיצד אנו מתקינים את המערכת
אנו משתמשים ב-Docker Compose להתקנה מהירה. התצורה כוללת שלושה שירותים:
---
version: '3.8'
services:
loki:
image: grafana/loki:3.0.0
ports:
- "3100:3100"
volumes:
- ./loki-config.yml:/etc/loki/local-config.yaml
- loki_data:/loki
command:
-config.file=/etc/loki/local-config.yaml
promtail:
image: grafana/promtail:3.0.0
volumes:
- /var/log:/var/log:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- ./promtail-config.yml:/etc/promtail/config.yml
command:
-config.file=/etc/promtail/config.yml
grafana:
image: grafana/grafana:11.0.0
ports:
- "3000:3000"
environment:
- GF_AUTH_ANONYMOUS_ENABLED=false
- GF_SECURITY_ADMIN_PASSWORD=admin_password
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning
volumes:
loki_data:
grafana_data:
תצורת Loki
---
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
common:
path_prefix: /loki
storage:
filesystem:
chunks_directory: /loki/chunks
rules_directory: /loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemory
schema_config:
configs:
- from: 2024-01-01
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
limits_config:
retention_period: 744h # 31 день
ingestion_rate_mb: 16
ingestion_burst_size_mb: 32
max_query_length: 721h
compactor:
working_directory: /loki/compactor
retention_enabled: true
delete_request_store: filesystem
תצורת Promtail
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: nginx
static_configs:
- targets: [localhost]
labels:
job: nginx
env: production
__path__: /var/log/nginx/access.log
pipeline_stages:
- regex:
expression: '^(?P<ip>\S+) - (?P<user>\S+) \[(?P<timestamp>[^\]]+)\] "(?P<method>\S+) (?P<path>\S+) \S+" (?P<status>\d+) (?P<bytes>\d+)'
- labels:
status:
method:
- timestamp:
source: timestamp
format: "02/Jan/2006:15:04:05 -0700"
- job_name: laravel
static_configs:
- targets: [localhost]
labels:
job: laravel-app
env: production
__path__: /var/www/app/storage/logs/laravel.log
pipeline_stages:
- multiline:
firstline: '^\[\d{4}-\d{2}-\d{2}'
max_wait_time: 3s
- regex:
expression: '^\[(?P<timestamp>[^\]]+)\] (?P<env>\w+)\.(?P<level>\w+): (?P<message>.*)'
- labels:
level:
env:
- timestamp:
source: timestamp
format: "2006-01-02 15:04:05"
- job_name: docker
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 5s
relabel_configs:
- source_labels: [__meta_docker_container_name]
target_label: container
- source_labels: [__meta_docker_container_log_stream]
target_label: logstream
התקנה ב-Kubernetes
עבור Kubernetes, השתמשו ב-Helm charts: `helm install loki grafana/loki-stack` — זה יפרוס את Loki, Promtail ו-Grafana עם הגדרות ברירת מחדל. עבור production, כווננו retention, תוויות ו-pipeline_stages דרך values.yaml.כיצד לשלב את Laravel עם Loki דרך Monolog
אנו כותבים handler מותאם אישית ל-Monolog ששולח רשומות לוג ל-Loki דרך HTTP API. זה עובד בשיטת fire-and-forget — אינו חוסם את הבקשה.
// app/Logging/LokiHandler.php
namespace App\Logging;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\LogRecord;
class LokiHandler extends AbstractProcessingHandler
{
public function __construct(
private string $lokiUrl,
private array $labels = []
) {
parent::__construct();
}
protected function write(LogRecord $record): void
{
$timestamp = (string)($record->datetime->getTimestamp() * 1_000_000_000);
$payload = [
'streams' => [[
'stream' => array_merge($this->labels, [
'level' => $record->level->getName(),
'channel' => $record->channel,
]),
'values' => [[$timestamp, $record->formatted]],
]],
];
$context = stream_context_create(['http' => [
'method' => 'POST',
'header' => 'Content-Type: application/json',
'content' => json_encode($payload),
'timeout' => 1,
]]);
@file_get_contents("{$this->lokiUrl}/loki/api/v1/push", false, $context);
}
}
// config/logging.php
'loki' => [
'driver' => 'monolog',
'handler' => App\Logging\LokiHandler::class,
'with' => [
'lokiUrl' => env('LOKI_URL', 'http://loki:3100'),
'labels' => [
'app' => 'web-app',
'env' => env('APP_ENV', 'production'),
],
],
],התקנה שלב אחר שלב לאיסוף לוגים של Laravel
- צרו את המחלקה
version: '3.8' services: loki: image: grafana/loki:3.0.0 ports: - "3100:3100" volumes: - ./loki-config.yml:/etc/loki/local-config.yaml - loki_data:/loki command: -config.file=/etc/loki/local-config.yaml promtail: image: grafana/promtail:3.0.0 volumes: - /var/log:/var/log:ro - /var/lib/docker/containers:/var/lib/docker/containers:ro - ./promtail-config.yml:/etc/promtail/config.yml command: -config.file=/etc/promtail/config.yml grafana: image: grafana/grafana:11.0.0 ports: - "3000:3000" environment: - GF_AUTH_ANONYMOUS_ENABLED=false - GF_SECURITY_ADMIN_PASSWORD=admin_password volumes: - grafana_data:/var/lib/grafana - ./grafana/provisioning:/etc/grafana/provisioning volumes: loki_data: grafana_data:כפי שמוצג לעיל. - רשמו את הערוץ
auth_enabled: false server: http_listen_port: 3100 grpc_listen_port: 9096 common: path_prefix: /loki storage: filesystem: chunks_directory: /loki/chunks rules_directory: /loki/rules replication_factor: 1 ring: kvstore: store: inmemory schema_config: configs: - from: 2024-01-01 store: tsdb object_store: filesystem schema: v13 index: prefix: index_ period: 24h limits_config: retention_period: 744h # 31 день ingestion_rate_mb: 16 ingestion_burst_size_mb: 32 max_query_length: 721h compactor: working_directory: /loki/compactor retention_enabled: true delete_request_store: filesystemב-server: http_listen_port: 9080 grpc_listen_port: 0 positions: filename: /tmp/positions.yaml clients: - url: http://loki:3100/loki/api/v1/push scrape_configs: - job_name: nginx static_configs: - targets: [localhost] labels: job: nginx env: production __path__: /var/log/nginx/access.log pipeline_stages: - regex: expression: '^(?P<ip>\S+) - (?P<user>\S+) \[(?P<timestamp>[^\]]+)\] "(?P<method>\S+) (?P<path>\S+) \S+" (?P<status>\d+) (?P<bytes>\d+)' - labels: status: method: - timestamp: source: timestamp format: "02/Jan/2006:15:04:05 -0700" - job_name: laravel static_configs: - targets: [localhost] labels: job: laravel-app env: production __path__: /var/www/app/storage/logs/laravel.log pipeline_stages: - multiline: firstline: '^\[\d{4}-\d{2}-\d{2}' max_wait_time: 3s - regex: expression: '^\[(?P<timestamp>[^\]]+)\] (?P<env>\w+)\.(?P<level>\w+): (?P<message>.*)' - labels: level: env: - timestamp: source: timestamp format: "2006-01-02 15:04:05" - job_name: docker docker_sd_configs: - host: unix:///var/run/docker.sock refresh_interval: 5s relabel_configs: - source_labels: [__meta_docker_container_name] target_label: container - source_labels: [__meta_docker_container_log_stream] target_label: logstream. - הוסיפו את משתנה הסביבה
// app/Logging/LokiHandler.php namespace App\Logging; use Monolog\Handler\AbstractProcessingHandler; use Monolog\LogRecord; class LokiHandler extends AbstractProcessingHandler { public function __construct( private string $lokiUrl, private array $labels = [] ) { parent::__construct(); } protected function write(LogRecord $record): void { $timestamp = (string)($record->datetime->getTimestamp() * 1_000_000_000); $payload = [ 'streams' => [[ 'stream' => array_merge($this->labels, [ 'level' => $record->level->getName(), 'channel' => $record->channel, ]), 'values' => [[$timestamp, $record->formatted]], ]], ]; $context = stream_context_create(['http' => [ 'method' => 'POST', 'header' => 'Content-Type: application/json', 'content' => json_encode($payload), 'timeout' => 1, ]]); @file_get_contents("{$this->lokiUrl}/loki/api/v1/push", false, $context); } } // config/logging.php 'loki' => [ 'driver' => 'monolog', 'handler' => App\Logging\LokiHandler::class, 'with' => [ 'lokiUrl' => env('LOKI_URL', 'http://loki:3100'), 'labels' => [ 'app' => 'web-app', 'env' => env('APP_ENV', 'production'), ], ], ],ב-LokiHandler. - אמתו את אספקת הלוגים דרך LogQL:
loki. - אופציונלית, הגדירו pipeline_stages לניתוח חריגות מרובות שורות.
כיצד לכתוב שאילתות LogQL
LogQL דומה ל-PromQL. תבניות בסיסיות:
# Все ошибки Laravel за последний час
{job="laravel-app", level="error"} |= "Exception"
# Nginx 5xx
{job="nginx"} | json | status >= 500
# Rate ошибок по минутам
rate({job="laravel-app", level="error"}[1m])
# Топ медленных запросов (если request_time в логе)
{job="nginx"} | regexp `request_time=(?P<rt>[0-9.]+)` | unwrap rt | quantile_over_time(0.95, [5m]) by (path)
# Подсчёт ошибок по типу
sum by (level) ( count_over_time({job="laravel-app"}[5m]) ) כיצד להגדיר התראות על עליות שגיאות
צרו כלל התראה דרך provisioning YAML. דוגמת תנאי: config/logging.php. ההתראה מופעלת אם הסף נחצה במשך יותר משתי דקות. מוגדר ב-LOKI_URL. הוסיפו גם התראה על עלייה פתאומית בשגיאות Nginx 5xx.
תהליך ולוחות זמנים
| שלב | מה אנו עושים | משך |
|---|---|---|
| ניתוח | זיהוי מקורות לוג, תוויות, retention | 0.5 יום |
| עיצוב | בחירת Promtail, תצורת Loki, datasource | 0.5 יום |
| יישום | פריסת המערכת, הגדרת איסוף, דשבורדים, התראות | 0.5 יום |
| בדיקות | אימות אספקה תקינה, פונקציונליות שאילתות | 0.5 יום |
| פריסה | מסירת תיעוד, אישורי גישה, הדרכת צוות | כלול |
סה"כ: 2-3 ימים עבור המערכת המלאה. התמחור מתחיל ב-$500 עבור המערכת הבסיסית (Loki, Promtail, Grafana על Docker; מקור לוג אחד). קבלו ייעוץ לפרויקט שלכם — נעריך ונציע פתרון.
מה כלול
- מערכת Loki + Promtail + Grafana פרוסה ב-Docker Compose או על bare metal.
- הגדרת retention, תוויות ו-pipeline_stages עבור המקורות שלכם.
- handler מותאם אישית ל-Monolog עבור Laravel (או דומה עבור פריימוורקים אחרים).
- דשבורדים של Grafana המציגים שגיאות, מגמות, נקודות קצה מובילות.
- כללי התראה על עליות שגיאות, 5xx, שאילתות איטיות.
- תיעוד תפעול ושחזור.
- מסירה והדרכת צוות (שעה אחת).
- אחריות לחודש אחד לפעולה תקינה של המערכת לאחר ההתקנה.
בעיות נפוצות ופתרונותיהן
- הגדרת retention שגויה — compactor נשכח, לוגים לא נמחקים. תמיד בדקו את
.env. - חוסר ב-pipeline_stages — תוויות לא מנותחות, סינון קשה. עבור Laravel, השתמשו תמיד בשלב multiline.
- יותר מדי תוויות — כל תווית חדשה יוצרת אינדקס, ומאטה כתיבה. הגבילו תוויות ל-5-7 לכל מקור.
למדו עוד על לוגים בויקיפדיה. הזמינו את ההתקנה וקבלו ייעוץ לפרויקט שלכם.







