148 lines
3.5 KiB
Go
148 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log/slog"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/elastic/go-elasticsearch/v7"
|
|
)
|
|
|
|
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)
|
|
|
|
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 {
|
|
data, err := json.Marshal(metrics)
|
|
if err != nil {
|
|
return fmt.Errorf("JSON marshalling error: %w", err)
|
|
}
|
|
|
|
systemIndex := fmt.Sprintf("%s-system", baseIndex)
|
|
|
|
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)
|
|
}
|
|
}
|