11package splunk
22
33import (
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.
1414type 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.
2929type 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