bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/cmd/bosun/expr/elastic_all.go (about) 1 package expr 2 3 import ( 4 "errors" 5 "fmt" 6 "sync" 7 "time" 8 9 "github.com/jinzhu/now" 10 11 elastic6 "github.com/olivere/elastic" 12 elastic7 "github.com/olivere/elastic/v7" 13 elastic2 "gopkg.in/olivere/elastic.v3" 14 elastic5 "gopkg.in/olivere/elastic.v5" 15 ) 16 17 const ( 18 ESV2 ESVersion = "v2" 19 ESV5 ESVersion = "v5" 20 ESV6 ESVersion = "v6" 21 ESV7 ESVersion = "v7" 22 23 // 2016-09-22T22:26:14.679270711Z 24 elasticRFC3339 = "date_optional_time" 25 ) 26 27 type ESVersion string 28 29 type ESQuery struct { 30 Query func(ver ESVersion) interface{} 31 } 32 33 // Map of prefixes to corresponding clients 34 // TODO: switch to sync.Map 35 var esClients struct { 36 sync.Mutex 37 m map[string]interface{} 38 } 39 40 func init() { 41 esClients.m = make(map[string]interface{}) 42 } 43 44 func ESAll(e *State) (*Results, error) { 45 var r Results 46 q := ESQuery{ 47 Query: func(ver ESVersion) interface{} { 48 switch ver { 49 case ESV2: 50 return elastic2.NewMatchAllQuery() 51 case ESV5: 52 return elastic5.NewMatchAllQuery() 53 case ESV6: 54 return elastic6.NewMatchAllQuery() 55 case ESV7: 56 return elastic7.NewMatchAllQuery() 57 } 58 return nil 59 }, 60 } 61 r.Results = append(r.Results, &Result{Value: q}) 62 return &r, nil 63 } 64 65 func ESAnd(e *State, esqueries ...ESQuery) (*Results, error) { 66 var r Results 67 q := ESQuery{ 68 Query: func(ver ESVersion) interface{} { 69 switch ver { 70 case ESV2: 71 queries := make([]elastic2.Query, len(esqueries)) 72 for i, q := range esqueries { 73 queries[i] = q.Query(ver).(elastic2.Query) 74 } 75 return elastic2.NewBoolQuery().Must(queries...) 76 case ESV5: 77 queries := make([]elastic5.Query, len(esqueries)) 78 for i, q := range esqueries { 79 queries[i] = q.Query(ver).(elastic5.Query) 80 } 81 return elastic5.NewBoolQuery().Must(queries...) 82 case ESV6: 83 queries := make([]elastic6.Query, len(esqueries)) 84 for i, q := range esqueries { 85 queries[i] = q.Query(ver).(elastic6.Query) 86 } 87 return elastic6.NewBoolQuery().Must(queries...) 88 case ESV7: 89 queries := make([]elastic7.Query, len(esqueries)) 90 for i, q := range esqueries { 91 queries[i] = q.Query(ver).(elastic7.Query) 92 } 93 return elastic7.NewBoolQuery().Must(queries...) 94 } 95 return nil 96 }, 97 } 98 r.Results = append(r.Results, &Result{Value: q}) 99 return &r, nil 100 } 101 102 func ESNot(e *State, query ESQuery) (*Results, error) { 103 var r Results 104 q := ESQuery{ 105 Query: func(ver ESVersion) interface{} { 106 switch ver { 107 case ESV2: 108 return elastic2.NewBoolQuery().MustNot(query.Query(ver).(elastic2.Query)) 109 case ESV5: 110 return elastic5.NewBoolQuery().MustNot(query.Query(ver).(elastic5.Query)) 111 case ESV6: 112 return elastic6.NewBoolQuery().MustNot(query.Query(ver).(elastic6.Query)) 113 case ESV7: 114 return elastic7.NewBoolQuery().MustNot(query.Query(ver).(elastic7.Query)) 115 } 116 return nil 117 }, 118 } 119 r.Results = append(r.Results, &Result{Value: q}) 120 return &r, nil 121 } 122 123 func ESOr(e *State, esqueries ...ESQuery) (*Results, error) { 124 var r Results 125 q := ESQuery{ 126 Query: func(ver ESVersion) interface{} { 127 switch ver { 128 case ESV2: 129 queries := make([]elastic2.Query, len(esqueries)) 130 for i, q := range esqueries { 131 queries[i] = q.Query(ver).(elastic2.Query) 132 } 133 return elastic2.NewBoolQuery().Should(queries...).MinimumNumberShouldMatch(1) 134 case ESV5: 135 queries := make([]elastic5.Query, len(esqueries)) 136 for i, q := range esqueries { 137 queries[i] = q.Query(ver).(elastic5.Query) 138 } 139 return elastic5.NewBoolQuery().Should(queries...).MinimumNumberShouldMatch(1) 140 case ESV6: 141 queries := make([]elastic6.Query, len(esqueries)) 142 for i, q := range esqueries { 143 queries[i] = q.Query(ver).(elastic6.Query) 144 } 145 return elastic6.NewBoolQuery().Should(queries...).MinimumNumberShouldMatch(1) 146 case ESV7: 147 queries := make([]elastic7.Query, len(esqueries)) 148 for i, q := range esqueries { 149 queries[i] = q.Query(ver).(elastic7.Query) 150 } 151 return elastic7.NewBoolQuery().Should(queries...).MinimumNumberShouldMatch(1) 152 } 153 return nil 154 }, 155 } 156 r.Results = append(r.Results, &Result{Value: q}) 157 return &r, nil 158 } 159 160 func ESRegexp(e *State, key string, regex string) (*Results, error) { 161 var r Results 162 q := ESQuery{ 163 Query: func(ver ESVersion) interface{} { 164 switch ver { 165 case ESV2: 166 return elastic2.NewRegexpQuery(key, regex) 167 case ESV5: 168 return elastic5.NewRegexpQuery(key, regex) 169 case ESV6: 170 return elastic6.NewRegexpQuery(key, regex) 171 case ESV7: 172 return elastic7.NewRegexpQuery(key, regex) 173 } 174 return nil 175 }, 176 } 177 r.Results = append(r.Results, &Result{Value: q}) 178 return &r, nil 179 } 180 181 func ESQueryString(e *State, key string, query string) (*Results, error) { 182 var r Results 183 q := ESQuery{ 184 // Query: qs 185 Query: func(ver ESVersion) interface{} { 186 switch ver { 187 case ESV2: 188 qs := elastic2.NewQueryStringQuery(query) 189 if key != "" { 190 qs.Field(key) 191 } 192 return qs 193 case ESV5: 194 qs := elastic5.NewQueryStringQuery(query) 195 if key != "" { 196 qs.Field(key) 197 } 198 return qs 199 case ESV6: 200 qs := elastic6.NewQueryStringQuery(query) 201 if key != "" { 202 qs.Field(key) 203 } 204 return qs 205 case ESV7: 206 qs := elastic7.NewQueryStringQuery(query) 207 if key != "" { 208 qs.Field(key) 209 } 210 return qs 211 } 212 return nil 213 }, 214 } 215 r.Results = append(r.Results, &Result{Value: q}) 216 return &r, nil 217 } 218 219 func ESExists(e *State, field string) (*Results, error) { 220 var r Results 221 q := ESQuery{ 222 Query: func(ver ESVersion) interface{} { 223 switch ver { 224 case ESV2: 225 return elastic2.NewExistsQuery(field) 226 case ESV5: 227 return elastic5.NewExistsQuery(field) 228 case ESV6: 229 return elastic6.NewExistsQuery(field) 230 case ESV7: 231 return elastic7.NewExistsQuery(field) 232 } 233 return nil 234 }, 235 } 236 r.Results = append(r.Results, &Result{Value: q}) 237 return &r, nil 238 } 239 240 func ESGT(e *State, key string, gt float64) (*Results, error) { 241 var r Results 242 q := ESQuery{ 243 Query: func(ver ESVersion) interface{} { 244 switch ver { 245 case ESV2: 246 return elastic2.NewRangeQuery(key).Gt(gt) 247 case ESV5: 248 return elastic5.NewRangeQuery(key).Gt(gt) 249 case ESV6: 250 return elastic6.NewRangeQuery(key).Gt(gt) 251 case ESV7: 252 return elastic7.NewRangeQuery(key).Gt(gt) 253 } 254 return nil 255 }, 256 } 257 r.Results = append(r.Results, &Result{Value: q}) 258 return &r, nil 259 } 260 261 func ESGTE(e *State, key string, gte float64) (*Results, error) { 262 var r Results 263 q := ESQuery{ 264 Query: func(ver ESVersion) interface{} { 265 switch ver { 266 case ESV2: 267 return elastic2.NewRangeQuery(key).Gte(gte) 268 case ESV5: 269 return elastic5.NewRangeQuery(key).Gte(gte) 270 case ESV6: 271 return elastic6.NewRangeQuery(key).Gte(gte) 272 case ESV7: 273 return elastic7.NewRangeQuery(key).Gte(gte) 274 } 275 return nil 276 }, 277 } 278 r.Results = append(r.Results, &Result{Value: q}) 279 return &r, nil 280 } 281 282 func ESLT(e *State, key string, lt float64) (*Results, error) { 283 var r Results 284 q := ESQuery{ 285 Query: func(ver ESVersion) interface{} { 286 switch ver { 287 case ESV2: 288 return elastic2.NewRangeQuery(key).Lt(lt) 289 case ESV5: 290 return elastic5.NewRangeQuery(key).Lt(lt) 291 case ESV6: 292 return elastic6.NewRangeQuery(key).Lt(lt) 293 case ESV7: 294 return elastic7.NewRangeQuery(key).Lt(lt) 295 } 296 return nil 297 }, 298 } 299 r.Results = append(r.Results, &Result{Value: q}) 300 return &r, nil 301 } 302 303 func ESLTE(e *State, key string, lte float64) (*Results, error) { 304 var r Results 305 q := ESQuery{ 306 Query: func(ver ESVersion) interface{} { 307 switch ver { 308 case ESV2: 309 return elastic2.NewRangeQuery(key).Lte(lte) 310 case ESV5: 311 return elastic5.NewRangeQuery(key).Lte(lte) 312 case ESV6: 313 return elastic6.NewRangeQuery(key).Lte(lte) 314 case ESV7: 315 return elastic7.NewRangeQuery(key).Lte(lte) 316 } 317 return nil 318 }, 319 } 320 r.Results = append(r.Results, &Result{Value: q}) 321 return &r, nil 322 } 323 324 // ElasticHosts is an array of Logstash hosts and exists as a type for something to attach 325 // methods to. The elasticsearch library will use the listed to hosts to discover all 326 // of the hosts in the config 327 // type ElasticHosts []string 328 type ElasticHosts struct { 329 Hosts map[string]ElasticConfig 330 } 331 332 type ElasticConfig struct { 333 Hosts []string 334 Version ESVersion 335 SimpleClient bool 336 ClientOptionFuncs interface{} 337 } 338 339 // InitClient sets up the elastic client. If the client has already been 340 // initialized it is a noop 341 func (e ElasticHosts) InitClient(prefix string) error { 342 if _, ok := e.Hosts[prefix]; !ok { 343 prefixes := make([]string, len(e.Hosts)) 344 i := 0 345 for k := range e.Hosts { 346 prefixes[i] = k 347 i++ 348 } 349 return fmt.Errorf("prefix %v not defined, available prefixes are: %v", prefix, prefixes) 350 } 351 if c := esClients.m[prefix]; c != nil { 352 // client already initialized 353 return nil 354 } 355 var err error 356 if e.Hosts[prefix].SimpleClient { 357 // simple client enabled 358 err = createVersionedSimpleESClient(prefix, e.Hosts[prefix]) 359 } else { 360 // default behavior 361 err = createVersionedESClient(prefix, e.Hosts[prefix]) 362 } 363 if err != nil { 364 return err 365 } 366 return nil 367 } 368 369 func createVersionedSimpleESClient(prefix string, cfg ElasticConfig) error { 370 var err error 371 switch cfg.Version { 372 case ESV2: 373 esClients.m[prefix], err = elastic2.NewSimpleClient(elastic2.SetURL(cfg.Hosts...), elastic2.SetMaxRetries(10)) 374 case ESV5: 375 esClients.m[prefix], err = elastic5.NewSimpleClient(elastic5.SetURL(cfg.Hosts...), elastic5.SetMaxRetries(10)) 376 case ESV6: 377 esClients.m[prefix], err = elastic6.NewSimpleClient(elastic6.SetURL(cfg.Hosts...), elastic6.SetMaxRetries(10)) 378 case ESV7: 379 esClients.m[prefix], err = elastic7.NewSimpleClient(elastic7.SetURL(cfg.Hosts...), elastic7.SetMaxRetries(10)) 380 } 381 return err 382 } 383 384 func createVersionedESClient(prefix string, cfg ElasticConfig) error { 385 var err error 386 switch cfg.Version { 387 case ESV2: 388 if len(cfg.Hosts) == 0 { 389 // client option enabled 390 esClients.m[prefix], err = elastic2.NewClient(cfg.ClientOptionFuncs.([]elastic2.ClientOptionFunc)...) 391 } else { 392 // default behavior 393 esClients.m[prefix], err = elastic2.NewClient(elastic2.SetURL(cfg.Hosts...), elastic2.SetMaxRetries(10)) 394 } 395 case ESV5: 396 if len(cfg.Hosts) == 0 { 397 // client option enabled 398 esClients.m[prefix], err = elastic5.NewClient(cfg.ClientOptionFuncs.([]elastic5.ClientOptionFunc)...) 399 } else { 400 // default behavior 401 esClients.m[prefix], err = elastic5.NewClient(elastic5.SetURL(cfg.Hosts...), elastic5.SetMaxRetries(10)) 402 } 403 case ESV6: 404 if len(cfg.Hosts) == 0 { 405 // client option enabled 406 esClients.m[prefix], err = elastic6.NewClient(cfg.ClientOptionFuncs.([]elastic6.ClientOptionFunc)...) 407 } else { 408 // default behavior 409 esClients.m[prefix], err = elastic6.NewClient(elastic6.SetURL(cfg.Hosts...), elastic6.SetMaxRetries(10)) 410 } 411 case ESV7: 412 if len(cfg.Hosts) == 0 { 413 // client option enabled 414 esClients.m[prefix], err = elastic7.NewClient(cfg.ClientOptionFuncs.([]elastic7.ClientOptionFunc)...) 415 } else { 416 // default behavior 417 esClients.m[prefix], err = elastic7.NewClient(elastic7.SetURL(cfg.Hosts...), elastic7.SetMaxRetries(10)) 418 } 419 } 420 return err 421 } 422 423 func ESIndicies(e *State, timeField string, literalIndices ...string) *Results { 424 var r Results 425 indexer := ESIndexer{} 426 // Don't check for existing indexes in this case, just pass through and let elastic return 427 // an error at query time if the index does not exist 428 indexer.Generate = func(start, end *time.Time) []string { 429 return literalIndices 430 } 431 indexer.TimeField = timeField 432 r.Results = append(r.Results, &Result{Value: indexer}) 433 return &r 434 } 435 436 func ESLS(e *State, indexRoot string) (*Results, error) { 437 return ESDaily(e, "@timestamp", indexRoot+"-", "2006.01.02") 438 } 439 440 func ESDaily(e *State, timeField, indexRoot, layout string) (*Results, error) { 441 var r Results 442 indexer := ESIndexer{} 443 indexer.TimeField = timeField 444 indexer.Generate = func(start, end *time.Time) []string { 445 var indices []string 446 truncStart := now.New(*start).BeginningOfDay() 447 truncEnd := now.New(*end).BeginningOfDay() 448 for d := truncStart; !d.After(truncEnd); d = d.AddDate(0, 0, 1) { 449 indices = append(indices, fmt.Sprintf("%v%v", indexRoot, d.Format(layout))) 450 } 451 return indices 452 } 453 r.Results = append(r.Results, &Result{Value: indexer}) 454 return &r, nil 455 } 456 457 func ESMonthly(e *State, timeField, indexRoot, layout string) (*Results, error) { 458 var r Results 459 indexer := ESIndexer{} 460 indexer.TimeField = timeField 461 indexer.Generate = func(start, end *time.Time) []string { 462 var indices []string 463 truncStart := now.New(*start).BeginningOfMonth() 464 truncEnd := now.New(*end).BeginningOfMonth() 465 for d := truncStart; !d.After(truncEnd); d = d.AddDate(0, 1, 0) { 466 indices = append(indices, fmt.Sprintf("%v%v", indexRoot, d.Format(layout))) 467 } 468 return indices 469 } 470 r.Results = append(r.Results, &Result{Value: indexer}) 471 return &r, nil 472 } 473 474 func ESCount(prefix string, e *State, indexer ESIndexer, keystring string, filter ESQuery, interval, sduration, eduration string) (r *Results, err error) { 475 switch ver := e.ElasticHosts.Hosts[prefix].Version; ver { 476 case ESV2: 477 return ESDateHistogram2(prefix, e, indexer, keystring, filter.Query(ver).(elastic2.Query), interval, sduration, eduration, "", "", 0) 478 case ESV5: 479 return ESDateHistogram5(prefix, e, indexer, keystring, filter.Query(ver).(elastic5.Query), interval, sduration, eduration, "", "", 0) 480 case ESV6: 481 return ESDateHistogram6(prefix, e, indexer, keystring, filter.Query(ver).(elastic6.Query), interval, sduration, eduration, "", "", 0) 482 case ESV7: 483 return ESDateHistogram7(prefix, e, indexer, keystring, filter.Query(ver).(elastic7.Query), interval, sduration, eduration, "", "", 0) 484 } 485 return nil, errors.New("unknown version") 486 } 487 488 // ESStat returns a bucketed statistical reduction for the specified field. 489 func ESStat(prefix string, e *State, indexer ESIndexer, keystring string, filter ESQuery, field, rstat, interval, sduration, eduration string) (r *Results, err error) { 490 switch ver := e.ElasticHosts.Hosts[prefix].Version; ver { 491 case ESV2: 492 return ESDateHistogram2(prefix, e, indexer, keystring, filter.Query(ver).(elastic2.Query), interval, sduration, eduration, field, rstat, 0) 493 case ESV5: 494 return ESDateHistogram5(prefix, e, indexer, keystring, filter.Query(ver).(elastic5.Query), interval, sduration, eduration, field, rstat, 0) 495 case ESV6: 496 return ESDateHistogram6(prefix, e, indexer, keystring, filter.Query(ver).(elastic6.Query), interval, sduration, eduration, field, rstat, 0) 497 case ESV7: 498 return ESDateHistogram7(prefix, e, indexer, keystring, filter.Query(ver).(elastic7.Query), interval, sduration, eduration, field, rstat, 0) 499 } 500 return nil, errors.New("unknown version") 501 }