github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/clients/pkg/promtail/targets/gelf/gelftarget.go (about) 1 package gelf 2 3 import ( 4 "bytes" 5 "context" 6 "strings" 7 "sync" 8 "time" 9 10 "github.com/go-kit/log" 11 "github.com/go-kit/log/level" 12 "github.com/grafana/go-gelf/v2/gelf" 13 "github.com/prometheus/common/model" 14 "github.com/prometheus/prometheus/model/labels" 15 "github.com/prometheus/prometheus/model/relabel" 16 17 "github.com/grafana/loki/clients/pkg/promtail/api" 18 "github.com/grafana/loki/clients/pkg/promtail/scrapeconfig" 19 "github.com/grafana/loki/clients/pkg/promtail/targets/target" 20 21 "github.com/grafana/loki/pkg/logproto" 22 ) 23 24 // SeverityLevels maps severity levels to severity string levels. 25 var SeverityLevels = map[int32]string{ 26 0: "emergency", 27 1: "alert", 28 2: "critical", 29 3: "error", 30 4: "warning", 31 5: "notice", 32 6: "informational", 33 7: "debug", 34 } 35 36 // Target listens to gelf messages on udp. 37 type Target struct { 38 metrics *Metrics 39 logger log.Logger 40 handler api.EntryHandler 41 config *scrapeconfig.GelfTargetConfig 42 relabelConfig []*relabel.Config 43 gelfReader *gelf.Reader 44 encodeBuff *bytes.Buffer 45 wg sync.WaitGroup 46 47 ctx context.Context 48 ctxCancel context.CancelFunc 49 } 50 51 // NewTarget configures a new Gelf Target. 52 func NewTarget( 53 metrics *Metrics, 54 logger log.Logger, 55 handler api.EntryHandler, 56 relabel []*relabel.Config, 57 config *scrapeconfig.GelfTargetConfig, 58 ) (*Target, error) { 59 60 if config.ListenAddress == "" { 61 config.ListenAddress = ":12201" 62 } 63 64 gelfReader, err := gelf.NewReader(config.ListenAddress) 65 if err != nil { 66 return nil, err 67 } 68 ctx, cancel := context.WithCancel(context.Background()) 69 70 t := &Target{ 71 metrics: metrics, 72 logger: logger, 73 handler: handler, 74 config: config, 75 relabelConfig: relabel, 76 gelfReader: gelfReader, 77 encodeBuff: bytes.NewBuffer(make([]byte, 0, 1024)), 78 79 ctx: ctx, 80 ctxCancel: cancel, 81 } 82 83 t.run() 84 return t, err 85 } 86 87 func (t *Target) run() { 88 t.wg.Add(1) 89 go func() { 90 defer t.wg.Done() 91 level.Info(t.logger).Log("msg", "listening for GELF UDP messages", "listen_address", t.config.ListenAddress) 92 for { 93 select { 94 case <-t.ctx.Done(): 95 level.Info(t.logger).Log("msg", "GELF UDP listener shutdown", "listen_address", t.config.ListenAddress) 96 return 97 default: 98 msg, err := t.gelfReader.ReadMessage() 99 if err != nil { 100 level.Error(t.logger).Log("msg", "error while reading gelf message", "listen_address", t.config.ListenAddress, "err", err) 101 t.metrics.gelfErrors.Inc() 102 continue 103 } 104 if msg != nil { 105 t.metrics.gelfEntries.Inc() 106 t.handleMessage(msg) 107 } 108 } 109 } 110 }() 111 } 112 113 func (t *Target) handleMessage(msg *gelf.Message) { 114 lb := labels.NewBuilder(nil) 115 116 // Add all labels from the config. 117 for k, v := range t.config.Labels { 118 lb.Set(string(k), string(v)) 119 } 120 lb.Set("__gelf_message_level", SeverityLevels[msg.Level]) 121 lb.Set("__gelf_message_host", msg.Host) 122 lb.Set("__gelf_message_version", msg.Version) 123 lb.Set("__gelf_message_facility", msg.Facility) 124 125 processed := relabel.Process(lb.Labels(), t.relabelConfig...) 126 127 filtered := make(model.LabelSet) 128 for _, lbl := range processed { 129 if strings.HasPrefix(lbl.Name, "__") { 130 continue 131 } 132 filtered[model.LabelName(lbl.Name)] = model.LabelValue(lbl.Value) 133 } 134 135 var timestamp time.Time 136 if t.config.UseIncomingTimestamp && msg.TimeUnix != 0 { 137 // TimeUnix is the timestamp of the message, in seconds since the UNIX epoch with decimals for fractional seconds. 138 timestamp = secondsToUnixTimestamp(msg.TimeUnix) 139 } else { 140 timestamp = time.Now() 141 } 142 t.encodeBuff.Reset() 143 err := msg.MarshalJSONBuf(t.encodeBuff) 144 if err != nil { 145 level.Error(t.logger).Log("msg", "error while marshalling gelf message", "listen_address", t.config.ListenAddress, "err", err) 146 t.metrics.gelfErrors.Inc() 147 return 148 } 149 t.handler.Chan() <- api.Entry{ 150 Labels: filtered, 151 Entry: logproto.Entry{ 152 Timestamp: timestamp, 153 Line: t.encodeBuff.String(), 154 }, 155 } 156 } 157 158 func secondsToUnixTimestamp(seconds float64) time.Time { 159 return time.Unix(0, int64(seconds*float64(time.Second))) 160 } 161 162 // Type returns GelfTargetType. 163 func (t *Target) Type() target.TargetType { 164 return target.GelfTargetType 165 } 166 167 // Ready indicates whether or not the gelf target is ready to be read from. 168 func (t *Target) Ready() bool { 169 return true 170 } 171 172 // DiscoveredLabels returns the set of labels discovered by the gelf target, which 173 // is always nil. Implements Target. 174 func (t *Target) DiscoveredLabels() model.LabelSet { 175 return nil 176 } 177 178 // Labels returns the set of labels that statically apply to all log entries 179 // produced by the GelfTarget. 180 func (t *Target) Labels() model.LabelSet { 181 return t.config.Labels 182 } 183 184 // Details returns target-specific details. 185 func (t *Target) Details() interface{} { 186 return map[string]string{} 187 } 188 189 // Stop shuts down the GelfTarget. 190 func (t *Target) Stop() { 191 level.Info(t.logger).Log("msg", "Shutting down GELF UDP listener", "listen_address", t.config.ListenAddress) 192 t.ctxCancel() 193 if err := t.gelfReader.Close(); err != nil { 194 level.Error(t.logger).Log("msg", "error while closing gelf reader", "err", err) 195 } 196 t.wg.Wait() 197 t.handler.Stop() 198 }