1/*
2** Zabbix
3** Copyright (C) 2001-2021 Zabbix SIA
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program; if not, write to the Free Software
17** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18**/
19
20package zbxlib
21
22/*
23#cgo CFLAGS: -I${SRCDIR}/../../../../../include -I${SRCDIR}/../../../../../build/win32/include
24
25#include "common.h"
26#include "sysinfo.h"
27#include "log.h"
28#include "../src/zabbix_agent/metrics.h"
29#include "../src/zabbix_agent/logfiles/logfiles.h"
30
31extern int CONFIG_EVENTLOG_MAX_LINES_PER_SECOND;
32
33typedef ZBX_ACTIVE_METRIC* ZBX_ACTIVE_METRIC_LP;
34typedef zbx_vector_ptr_t * zbx_vector_ptr_lp_t;
35typedef char * char_lp_t;
36
37void metric_set_refresh(ZBX_ACTIVE_METRIC *metric, int refresh);
38void metric_get_meta(ZBX_ACTIVE_METRIC *metric, zbx_uint64_t *lastlogsize, int *mtime);
39void metric_set_unsupported(ZBX_ACTIVE_METRIC *metric);
40int metric_set_supported(ZBX_ACTIVE_METRIC *metric, zbx_uint64_t lastlogsize_sent, int mtime_sent,
41		zbx_uint64_t lastlogsize_last, int mtime_last);
42
43int	process_eventlog_check(char *server, unsigned short port, zbx_vector_ptr_t *regexps, ZBX_ACTIVE_METRIC *metric,
44		zbx_process_value_func_t process_value_cb, zbx_uint64_t *lastlogsize_sent, char **error);
45
46typedef struct
47{
48	char *value;
49	char *source;
50	int timestamp;
51	int logeventid;
52	int severity;
53
54	int state;
55	zbx_uint64_t lastlogsize;
56}
57eventlog_value_t;
58
59typedef struct
60{
61	zbx_vector_ptr_t values;
62	int slots;
63}
64eventlog_result_t, *eventlog_result_lp_t;
65
66static eventlog_result_t *new_eventlog_result(int slots)
67{
68	eventlog_result_t *result;
69
70	result = (eventlog_result_t *)zbx_malloc(NULL, sizeof(eventlog_result_t));
71	zbx_vector_ptr_create(&result->values);
72	result->slots = slots;
73	return result;
74}
75
76static void add_eventlog_value(eventlog_result_t *result, const char *value, const char *source, int logeventid, int severity,
77	int timestamp, int state, zbx_uint64_t lastlogsize)
78{
79	eventlog_value_t *log;
80	log = (eventlog_value_t *)zbx_malloc(NULL, sizeof(eventlog_value_t));
81	log->value = zbx_strdup(NULL, value);
82	log->source = zbx_strdup(NULL, source);
83	log->logeventid = logeventid;
84	log->severity = severity;
85	log->timestamp = timestamp;
86	log->state = state;
87	log->lastlogsize = lastlogsize;
88	zbx_vector_ptr_append(&result->values, log);
89}
90
91static int get_eventlog_value(eventlog_result_t *result, int index, char **value, char **source, int *logeventid,
92	 int *severity, int *timestamp, int *state, zbx_uint64_t *lastlogsize)
93{
94	eventlog_value_t *log;
95
96	if (index == result->values.values_num)
97		return FAIL;
98
99	log = (eventlog_value_t *)result->values.values[index];
100	*value = log->value;
101	*source = log->source;
102	*logeventid = log->logeventid;
103	*severity = log->severity;
104	*timestamp = log->timestamp;
105	*state = log->state;
106	*lastlogsize = log->lastlogsize;
107	return SUCCEED;
108}
109
110static void free_eventlog_value(eventlog_value_t *log)
111{
112	zbx_free(log->value);
113	zbx_free(log->source);
114	zbx_free(log);
115}
116
117static void free_eventlog_result(eventlog_result_t *result)
118{
119	zbx_vector_ptr_clear_ext(&result->values, (zbx_clean_func_t)free_eventlog_value);
120	zbx_vector_ptr_destroy(&result->values);
121	zbx_free(result);
122}
123
124int	process_eventlog_value_cb(const char *server, unsigned short port, const char *host, const char *key,
125		const char *value, unsigned char state, zbx_uint64_t *lastlogsize, const int *mtime,
126		unsigned long *timestamp, const char *source, unsigned short *severity, unsigned long *logeventid,
127		unsigned char flags)
128{
129	eventlog_result_t *result = (eventlog_result_t *)server;
130	if (result->values.values_num == result->slots)
131		return FAIL;
132
133	add_eventlog_value(result, value, source, *logeventid, *severity, *timestamp, state, *lastlogsize);
134	return SUCCEED;
135}
136*/
137import "C"
138
139import (
140	"errors"
141	"time"
142	"unsafe"
143)
144
145type EventLogItem struct {
146	LastTs  time.Time // the last log value timestamp + 1ns
147	Results []*EventLogResult
148	Output  ResultWriter
149}
150
151type EventLogResult struct {
152	Value          *string
153	EventSource    *string
154	EventID        *int
155	EventTimestamp *int
156	EventSeverity  *int
157	Ts             time.Time
158	Error          error
159	LastLogsize    uint64
160	Mtime          int
161}
162
163func ProcessEventLogCheck(data unsafe.Pointer, item *EventLogItem, refresh int, cblob unsafe.Pointer) {
164	C.metric_set_refresh(C.ZBX_ACTIVE_METRIC_LP(data), C.int(refresh))
165
166	var clastLogsizeSent, clastLogsizeLast C.zbx_uint64_t
167	var cstate, cmtime C.int
168	C.metric_get_meta(C.ZBX_ACTIVE_METRIC_LP(data), &clastLogsizeSent, &cmtime)
169	clastLogsizeLast = clastLogsizeSent
170
171	result := C.new_eventlog_result(C.int(item.Output.PersistSlotsAvailable()))
172
173	var cerrmsg *C.char
174	ret := C.process_eventlog_check(C.char_lp_t(unsafe.Pointer(result)), 0, C.zbx_vector_ptr_lp_t(cblob),
175		C.ZBX_ACTIVE_METRIC_LP(data), C.zbx_process_value_func_t(C.process_eventlog_value_cb), &clastLogsizeSent,
176		&cerrmsg)
177
178	// add cached results
179	var cvalue, csource *C.char
180	var clogeventid, cseverity, ctimestamp C.int
181	var clastlogsize C.zbx_uint64_t
182	logTs := time.Now()
183	if logTs.Before(item.LastTs) {
184		logTs = item.LastTs
185	}
186	for i := 0; C.get_eventlog_value(result, C.int(i), &cvalue, &csource, &clogeventid, &cseverity, &ctimestamp, &cstate,
187		&clastlogsize) != C.FAIL; i++ {
188
189		var value, source string
190		var logeventid, severity, timestamp int
191		var r EventLogResult
192		if cstate == C.ITEM_STATE_NORMAL {
193			value = C.GoString(cvalue)
194			source = C.GoString(csource)
195			logeventid = int(clogeventid)
196			severity = int(cseverity)
197			timestamp = int(ctimestamp)
198
199			r = EventLogResult{
200				Value:          &value,
201				EventSource:    &source,
202				EventID:        &logeventid,
203				EventSeverity:  &severity,
204				EventTimestamp: &timestamp,
205				Ts:             logTs,
206				LastLogsize:    uint64(clastlogsize),
207			}
208
209		} else {
210			r = EventLogResult{
211				Error:       errors.New(C.GoString(cvalue)),
212				Ts:          logTs,
213				LastLogsize: uint64(clastlogsize),
214			}
215
216		}
217
218		item.Results = append(item.Results, &r)
219		logTs = logTs.Add(time.Nanosecond)
220	}
221	C.free_eventlog_result(result)
222
223	item.LastTs = logTs
224
225	if ret == C.FAIL {
226		C.metric_set_unsupported(C.ZBX_ACTIVE_METRIC_LP(data))
227
228		var err error
229		if cerrmsg != nil {
230			err = errors.New(C.GoString(cerrmsg))
231			C.free(unsafe.Pointer(cerrmsg))
232		} else {
233			err = errors.New("Unknown error.")
234		}
235		result := &EventLogResult{
236			Ts:    time.Now(),
237			Error: err,
238		}
239		item.Results = append(item.Results, result)
240	} else {
241		ret := C.metric_set_supported(C.ZBX_ACTIVE_METRIC_LP(data), clastLogsizeSent, 0, clastLogsizeLast, 0)
242
243		if ret == Succeed {
244			C.metric_get_meta(C.ZBX_ACTIVE_METRIC_LP(data), &clastLogsizeLast, &cmtime)
245			result := EventLogResult{
246				Ts:          time.Now(),
247				LastLogsize: uint64(clastLogsizeLast),
248			}
249			item.Results = append(item.Results, &result)
250		}
251	}
252}
253
254func SetEventlogMaxLinesPerSecond(num int) {
255	C.CONFIG_EVENTLOG_MAX_LINES_PER_SECOND = C.int(num)
256}
257