Repository navigation
Expand file tree
/
Copy pathmain.go
More file actions
213 lines (187 loc) · 8.94 KB
/
Copy pathmain.go
File metadata and controls
213 lines (187 loc) · 8.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"time"
"github.com/SumoLogic/sumologic-cloudfoundry-nozzle/caching"
"github.com/SumoLogic/sumologic-cloudfoundry-nozzle/eventQueue"
"github.com/SumoLogic/sumologic-cloudfoundry-nozzle/eventRouting"
"github.com/SumoLogic/sumologic-cloudfoundry-nozzle/events"
"github.com/SumoLogic/sumologic-cloudfoundry-nozzle/firehoseclient"
"github.com/SumoLogic/sumologic-cloudfoundry-nozzle/logging"
"github.com/SumoLogic/sumologic-cloudfoundry-nozzle/sumoCFFirehose"
"github.com/alecthomas/kingpin/v2"
"github.com/cloudfoundry-community/go-cfclient"
)
var (
apiEndpoint = kingpin.Flag("api_endpoint", "URL to CF API Endpoint").Envar("API_ENDPOINT").String()
sumoEndpointsString = kingpin.Flag("sumo_endpoints", "SUMO-ENDPOINTS Complete URLs for the endpoints, copied from the Sumo Logic HTTP Source configuration").Envar("SUMO_ENDPOINTS").String()
subscriptionId = kingpin.Flag("subscription_id", "Cloud Foundry ID for the subscription.").Default("firehose").Envar("FIREHOSE_SUBSCRIPTION_ID").String()
user = kingpin.Flag("cloudfoundry_user", "Cloud Foundry User").Envar("CLOUDFOUNDRY_USER").String() //user created in CF, authorized to connect the firehose
password = kingpin.Flag("cloudfoundry_password", "Cloud Foundry Password").Envar("CLOUDFOUNDRY_PASSWORD").String()
keepAlive, errDt = time.ParseDuration("25s") //default Error,ContainerMetric,HttpStart,HttpStop,HttpStartStop,LogMessage,ValueMetric,CounterEvent
defaultPostMinimumDelay, _ = time.ParseDuration("2000ms")
wantedEvents = kingpin.Flag("events", fmt.Sprintf("Comma separated list of events you would like. Valid options are %s", eventRouting.GetListAuthorizedEventEvents())).Default("LogMessage").Envar("EVENTS").String()
boltDatabasePath = "event.db"
skipSSLValidation = kingpin.Flag("skip_ssl_validation", "Skip SSL validation (to allow things like self-signed certs). Do not set to true in production").Default("false").Envar("SKIP_SSL_VALIDATION").Bool()
tickerTime = kingpin.Flag("nozzle_polling_period", "How frequently this Nozzle polls the CF Firehose for data").Default("5m").Envar("NOZZLE_POLLING_PERIOD").Duration()
eventsBatchSize = kingpin.Flag("log_events_batch_size", "When number of messages in the buffer is equal to this flag, send those to Sumo Logic").Default("500").Envar("LOG_EVENTS_BATCH_SIZE").Int()
verboseLogMessages = kingpin.Flag("verbose_log_messages", "Enable Verbose in 'LogMessage' Event. If this flag NOT present, the LogMessage will contain ONLY the fields: tiemstamp, cf_app_guid, Msg").Default("true").Envar("VERBOSE_LOG_MESSAGES").Bool()
)
var (
version = "1.0.9"
)
func main() {
//logging init
logging.Init(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr)
kingpin.Version(version)
kingpin.Parse()
sumoConfigs, err := parseSumoConfigs(*sumoEndpointsString)
if err != nil {
logging.Error.Fatal("Error parsing sumo configs: ", err.Error())
}
cfApi := parseCfApiFromVcapApplication(os.Getenv("VCAP_APPLICATION"))
if *apiEndpoint == "" {
logging.Info.Println("Cloud Foundry API Endpoint was empty. Setting it to cf_api value: " + cfApi)
*apiEndpoint = cfApi
}
logging.Info.Println("Set Configurations:")
logging.Info.Println("cf_api: " + cfApi)
logging.Info.Println("CF API Endpoint: " + *apiEndpoint)
logging.Info.Println("Cloud Foundry Nozzle Subscription ID: " + *subscriptionId)
logging.Info.Println("Cloud Foundry User: " + *user)
logging.Info.Println("Events Selected: " + *wantedEvents)
logging.Info.Printf("Skip SSL Validation: %v", *skipSSLValidation)
logging.Info.Printf("Nozzle Polling Period: %v", *tickerTime)
logging.Info.Printf("Log Events Batch Size: [%d]", *eventsBatchSize)
logging.Info.Printf("Verbose Log Messages: %v\n", *verboseLogMessages)
logging.Info.Printf("Sumo Logic Configurations: %v", sumoConfigs)
logging.Info.Println("Starting Sumo Logic Nozzle " + version)
if errDt != nil {
logging.Info.Println("Could not parse Duration...")
}
c := cfclient.Config{
ApiAddress: *apiEndpoint,
Username: *user,
Password: *password,
SkipSslValidation: *skipSSLValidation,
}
cfClient, errCfClient := cfclient.NewClient(&c)
if errCfClient != nil {
logging.Error.Fatal("Error setting up CF Client: ", errCfClient)
}
//Creating Caching
var cachingClient caching.Caching
if caching.IsNeeded(*wantedEvents) {
cachingClient = caching.NewCachingBolt(cfClient, boltDatabasePath)
} else {
cachingClient = caching.NewCachingEmpty()
}
queues := make([]*eventQueue.Queue, len(sumoConfigs))
for i, sumoConfig := range sumoConfigs {
logging.Info.Println("Creating queue for endpoint: " + sumoConfig.Endpoint)
queue := eventQueue.NewQueue(make([]*events.Event, 100))
queues[i] = &queue
postMinDelay, errDPt := time.ParseDuration(sumoConfig.PostMinimumDelay)
if errDPt != nil {
logging.Info.Println("Error parsing PostMinimumDelay, got: " + sumoConfig.PostMinimumDelay + ". Will be using default value of 2s instead")
postMinDelay = defaultPostMinimumDelay
}
logging.Info.Printf("Using post minimum delay: %v\n", postMinDelay)
loggingClientSumo := sumoCFFirehose.NewSumoLogicAppender(sumoConfig.Endpoint, 5000, &queue, *eventsBatchSize, postMinDelay, sumoConfig.Category, sumoConfig.Name, sumoConfig.Host, *verboseLogMessages, sumoConfig.CustomMetadata, sumoConfig.IncludeOnlyMatchingFilter, sumoConfig.ExcludeAlwaysMatchingFilter, version)
go loggingClientSumo.Start() //multi
}
logging.Info.Println("Creating Events")
events := eventRouting.NewEventRouting(cachingClient, queues)
err = events.SetupEventRouting(*wantedEvents)
if err != nil {
logging.Error.Fatal("Error setting up event routing: ", err)
os.Exit(1)
}
// Parse extra fields from cmd call
cachingClient.CreateBucket()
//Let's Update the database the first time
logging.Info.Printf("Start filling app/space/org cache.\n")
apps := cachingClient.GetAllApp()
logging.Info.Printf("Done filling cache! Found [%d] Apps \n", len(apps))
logging.Info.Println("Apps found: ")
for i := 0; i < len(apps); i++ {
logging.Info.Printf("[%d] "+apps[i].Name+" GUID: "+apps[i].Guid, i+1)
}
cachingClient.PerformPoollingCaching(*tickerTime)
firehoseConfig := &firehoseclient.FirehoseConfig{
TrafficControllerURL: cfClient.Endpoint.DopplerEndpoint,
InsecureSSLSkipVerify: *skipSSLValidation,
IdleTimeoutSeconds: keepAlive,
FirehoseSubscriptionID: *subscriptionId,
}
logging.Info.Printf("Connecting to Firehose... \n")
firehoseClient := firehoseclient.NewFirehoseNozzle(cfClient, events, firehoseConfig)
errFirehose := firehoseClient.Start()
logging.Info.Printf("FirehoseClient Error: %v", errFirehose)
defer cachingClient.Close()
}
type sumoConfigStruct struct {
Endpoint string `json:"endpoint"`
PostMinimumDelay string `json:"sumo_post_minimum_delay"`
Category string `json:"sumo_category"`
Name string `json:"sumo_name"`
Host string `json:"sumo_host"`
CustomMetadata string `json:"custom_metadata"`
IncludeOnlyMatchingFilter string `json:"include_only_matching_filter"`
ExcludeAlwaysMatchingFilter string `json:"exclude_always_matching_filter"`
GUID string `json:"guid"`
}
func (s sumoConfigStruct) String() string {
return fmt.Sprintf("\n"+
"Sumo Logic Endpoint: %v\n"+
"Sumo Logic HTTP Post Minimum Delay: %v\n"+
"Sumo Logic Name: %v\n"+
"Sumo Logic Host: %v\n"+
"Sumo Logic Category: %v\n"+
"Custom Metadata: %v\n"+
"Include Only Matching Filter: %v\n"+
"Exclude Always Matching Filter: %v\n",
s.Endpoint,
s.PostMinimumDelay,
s.Name,
s.Host,
s.Category,
s.CustomMetadata,
s.IncludeOnlyMatchingFilter,
s.ExcludeAlwaysMatchingFilter)
}
func parseSumoConfigs(jsonString string) ([]sumoConfigStruct, error) {
res := []sumoConfigStruct{}
err := json.Unmarshal([]byte(jsonString), &res)
if err != nil {
return nil, err
}
return res, nil
}
type vcapApplication struct {
ApplicationId string `json:"application_id"`
ApplicationName string `json:"application_name"`
ApplicationUris string `json:"application_uris"`
ApplicationVersion string `json:"application_version"`
CfApi string `json:"cf_api"`
Host string `json:"host"`
Limits string `json:"limits"`
Name string `json:"name"`
SpaceId string `json:"space_id"`
SpaceName string `json:"space_name"`
Start string `json:"start"`
StartedAt string `json:"started_at"`
StartedAtTimestamp string `json:"started_at_timestamp"`
StateTimestamp string `json:"state_timestamp"`
Uris string `json:"uris"`
Users string `json:"users"`
Version string `json:"version"`
}
func parseCfApiFromVcapApplication(jsonString string) string {
res := vcapApplication{}
json.Unmarshal([]byte(jsonString), &res)
return res.CfApi
}