Skip to content

Commit ffc4862

Browse files
Merge pull request #2 from ivan-californias/master
Send events in batch and with custom timestamp.
2 parents 7b0895a + 6d64e51 commit ffc4862

File tree

1 file changed

+89
-30
lines changed

1 file changed

+89
-30
lines changed

splunk/splunk.go

Lines changed: 89 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
package splunk
22

33
import (
4-
"crypto/tls"
5-
"time"
64
"bytes"
7-
"os"
8-
"net/http"
5+
"crypto/tls"
96
"encoding/json"
107
"errors"
8+
"net/http"
9+
"os"
10+
"time"
1111
)
1212

1313
// Event represents the log event object that is sent to Splunk when Client.Log is called.
1414
type Event struct {
15-
Time int64 `json:"time" binding:"required"` // epoch time in seconds
16-
Host string `json:"host" binding:"required"` // hostname
17-
Source string `json:"source" binding:"required"` // app name
18-
SourceType string `json:"sourcetype" binding:"required"` // Splunk bucket to group logs in
19-
Index string `json:"index" binding:"required"` // idk what it does..
20-
Event interface{} `json:"event" binding:"required"` // throw any useful key/val pairs here
15+
Time int64 `json:"time" binding:"required"` // epoch time in seconds
16+
Host string `json:"host" binding:"required"` // hostname
17+
Source string `json:"source" binding:"required"` // app name
18+
SourceType string `json:"sourcetype" binding:"required"` // Splunk bucket to group logs in
19+
Index string `json:"index" binding:"required"` // idk what it does..
20+
Event interface{} `json:"event" binding:"required"` // throw any useful key/val pairs here
2121
}
2222

2323
// Client manages communication with Splunk's HTTP Event Collector.
@@ -27,37 +27,66 @@ type Event struct {
2727
// The Token field must be defined with your access token to the Event Collector.
2828
// The Source, SourceType, and Index fields must be defined.
2929
type Client struct {
30-
HTTPClient *http.Client // HTTP client used to communicate with the API
31-
URL string
32-
Token string
33-
Source string
34-
SourceType string
35-
Index string
30+
HTTPClient *http.Client // HTTP client used to communicate with the API
31+
URL string
32+
Hostname string
33+
Token string
34+
Source string //Default source
35+
SourceType string //Default source type
36+
Index string //Default index
3637
}
3738

3839
// NewClient creates a new client to Splunk.
3940
// This should be the primary way a Splunk client object is constructed.
4041
//
4142
// If an httpClient object is specified it will be used instead of the
4243
// default http.DefaultClient.
43-
func NewClient(httpClient *http.Client, URL string, Token string, Source string, SourceType string, Index string) (*Client) {
44+
func NewClient(httpClient *http.Client, URL string, Token string, Source string, SourceType string, Index string) *Client {
4445
// Create a new client
4546
if httpClient == nil {
4647
tr := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}} // turn off certificate checking
4748
httpClient = &http.Client{Timeout: time.Second * 20, Transport: tr}
4849
}
49-
50-
c := &Client{HTTPClient: httpClient, URL: URL, Token: Token, Source: Source, SourceType: SourceType, Index: Index}
51-
50+
hostname, _ := os.Hostname()
51+
c := &Client{
52+
HTTPClient: httpClient,
53+
URL: URL,
54+
Hostname: hostname,
55+
Token: Token,
56+
Source: Source,
57+
SourceType: SourceType,
58+
Index: Index,
59+
}
5260
return c
5361
}
5462

5563
// NewEvent creates a new log event to send to Splunk.
5664
// This should be the primary way a Splunk log object is constructed, and is automatically called by the Log function attached to the client.
57-
func NewEvent(event interface{}, source string, sourcetype string, index string) (Event) {
58-
hostname, _ := os.Hostname()
59-
e := Event{Time: time.Now().Unix(), Host: hostname, Source: source, SourceType: sourcetype, Index: index, Event: event}
65+
// This method takes the current timestamp for the event, meaning that the event is generated at runtime.
66+
func (c *Client) NewEvent(event interface{}, source string, sourcetype string, index string) *Event {
67+
e := &Event{
68+
Time: time.Now().Unix(),
69+
Host: c.Hostname,
70+
Source: source,
71+
SourceType: sourcetype,
72+
Index: index,
73+
Event: event,
74+
}
75+
return e
76+
}
6077

78+
// NewEventWithTime creates a new log event with a specified timetamp to send to Splunk.
79+
// This is similar to NewEvent but if you want to log in a different time rather than time.Now this becomes handy. If that's
80+
// the case, use this function to create the Event object and the the LogEvent function.
81+
func (c *Client) NewEventWithTime(t int64, event interface{}, source string, sourcetype string, index string) *Event {
82+
e := &Event{
83+
Time: t,
84+
Host: c.Hostname,
85+
Source: source,
86+
SourceType: sourcetype,
87+
Index: index,
88+
Event: event,
89+
}
6190
return e
6291
}
6392

@@ -66,23 +95,54 @@ func NewEvent(event interface{}, source string, sourcetype string, index string)
6695
// All that must be provided for a log event are the desired map[string]string key/val pairs. These can be anything
6796
// that provide context or information for the situation you are trying to log (i.e. err messages, status codes, etc).
6897
// The function auto-generates the event timestamp and hostname for you.
69-
func (c *Client) Log(event interface{}) (error) {
98+
func (c *Client) Log(event interface{}) error {
7099
// create Splunk log
71-
log := NewEvent(event, c.Source, c.SourceType, c.Index)
100+
log := c.NewEvent(event, c.Source, c.SourceType, c.Index)
101+
return c.LogEvent(log)
102+
}
72103

104+
// Client.LogWithTime is used to construct a new log event with a scpecified timestamp and POST it to the Splunk server.
105+
//
106+
// This is similar to Client.Log, just with the t parameter.
107+
func (c *Client) LogWithTime(t int64, event interface{}) error {
108+
// create Splunk log
109+
log := c.NewEventWithTime(t, event, c.Source, c.SourceType, c.Index)
110+
return c.LogEvent(log)
111+
}
112+
113+
// Client.LogEvent is used to POST a single event to the Splunk server.
114+
func (c *Client) LogEvent(e *Event) error {
73115
// Convert requestBody struct to byte slice to prep for http.NewRequest
74-
b, err := json.Marshal(log)
116+
b, err := json.Marshal(e)
75117
if err != nil {
76118
return err
77119
}
120+
return c.doRequest(bytes.NewBuffer(b))
121+
}
78122

79-
//log.Print(string(b[:])) // print what the splunk post body will be for checking/debugging
123+
// Client.LogEvents is used to POST multiple events with a single request to the Splunk server.
124+
func (c *Client) LogEvents(events []*Event) error {
125+
buf := new(bytes.Buffer)
126+
for _, e := range events {
127+
b, err := json.Marshal(e)
128+
if err != nil {
129+
return err
130+
}
131+
buf.Write(b)
132+
// Each json object should be separated by a blank line
133+
buf.WriteString("\r\n\r\n")
134+
}
135+
// Convert requestBody struct to byte slice to prep for http.NewRequest
136+
return c.doRequest(buf)
137+
}
80138

139+
// Client.doRequest is used internally to POST the bytes of events to the Splunk server.
140+
func (c *Client) doRequest(b *bytes.Buffer) error {
81141
// make new request
82142
url := c.URL
83-
req, err := http.NewRequest("POST", url, bytes.NewBuffer(b))
143+
req, err := http.NewRequest("POST", url, b)
84144
req.Header.Add("Content-Type", "application/json")
85-
req.Header.Add("Authorization", "Splunk " + c.Token)
145+
req.Header.Add("Authorization", "Splunk "+c.Token)
86146

87147
// receive response
88148
res, err := c.HTTPClient.Do(req)
@@ -102,6 +162,5 @@ func (c *Client) Log(event interface{}) (error) {
102162
err = errors.New(responseBody)
103163

104164
}
105-
//log.Print(responseBody) // print error to screen for checking/debugging
106165
return err
107166
}

0 commit comments

Comments
 (0)