watch-tool/elasticsearch.go

155 lines
3.6 KiB
Go

package main
import (
"context"
"encoding/json"
"fmt"
"log/slog"
"strings"
"time"
"github.com/elastic/go-elasticsearch/v8"
)
func NewElasticsearchClient(config ElasticsearchConfig) (*elasticsearch.Client, error) {
esConfig := elasticsearch.Config{
Addresses: []string{config.URL},
}
if config.Username != "" && config.Password != "" {
esConfig.Username = config.Username
esConfig.Password = config.Password
}
client, err := elasticsearch.NewClient(esConfig)
if err != nil {
return nil, fmt.Errorf("failed to create elasticsearch client: %w", err)
}
return client, nil
}
func TestElasticsearchConnection(es *elasticsearch.Client) error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
res, err := es.Info(es.Info.WithContext(ctx))
if err != nil {
return fmt.Errorf("connection test failed: %w", err)
}
defer res.Body.Close()
if res.IsError() {
return fmt.Errorf("connection test failed: %s", res.String())
}
return nil
}
type ElasticsearchSender interface {
SendBatch(baseIndex string, entries []LogEntry) error
SendSystemMetrics(baseIndex string, metrics SystemResources) error
}
type ElasticsearchClient struct {
client *elasticsearch.Client
}
func NewElasticsearchSender(client *elasticsearch.Client) ElasticsearchSender {
return &ElasticsearchClient{client: client}
}
func (esc *ElasticsearchClient) SendBatch(baseIndex string, entries []LogEntry) error {
if len(entries) == 0 {
return nil
}
var body strings.Builder
for _, entry := range entries {
// indexName := determineIndexName(baseIndex, entry)
indexName := "tixel"
indexLine := fmt.Sprintf(`{"index":{"_index":"%s"}}`, indexName)
body.WriteString(indexLine)
body.WriteString("\n")
data, err := json.Marshal(entry)
if err != nil {
slog.Error("error marshalling JSON", "error", err)
continue
}
body.WriteString(string(data))
body.WriteString("\n")
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
res, err := esc.client.Bulk(
strings.NewReader(body.String()),
esc.client.Bulk.WithContext(ctx),
)
if err != nil {
return fmt.Errorf("bulk request error: %w", err)
}
defer res.Body.Close()
if res.IsError() {
return fmt.Errorf("bulk request failed: %s", res.String())
}
slog.Debug("Batch successfully sent", "count", len(entries))
return nil
}
func (esc *ElasticsearchClient) SendSystemMetrics(baseIndex string, metrics SystemResources) error {
msg := LogEntry{
Service: "system-metrics",
Timestamp: time.Now(),
LogLevel: "Info",
SystemMetrics: metrics,
}
data, err := json.Marshal(msg)
if err != nil {
return fmt.Errorf("JSON marshalling error: %w", err)
}
systemIndex := "tixel"
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
res, err := esc.client.Index(
systemIndex,
strings.NewReader(string(data)),
esc.client.Index.WithContext(ctx),
)
if err != nil {
return fmt.Errorf("elasticsearch index error: %w", err)
}
defer res.Body.Close()
if res.IsError() {
return fmt.Errorf("elasticsearch error: %s", res.String())
}
slog.Debug("System-Metrics sent",
"CPU", metrics.CPUPercent,
"MEM_used", metrics.MemoryUsed,
"MEM_total", metrics.MemoryTotal,
"MEM_percentage", metrics.MemoryPercent,
)
return nil
}
// func determineIndexName(baseIndex string, entry LogEntry) string {
// switch entry.Type {
// case "system_metrics":
// return fmt.Sprintf("%s-system", baseIndex)
// case "service_log":
// return fmt.Sprintf("%s-service-%s", baseIndex, entry.Service)
// default:
// return fmt.Sprintf("%s-%s", baseIndex, entry.Tool)
// }
// }