1// Copyright 2012-present Oliver Eilhard. All rights reserved.
2// Use of this source code is governed by a MIT-license.
3// See http://olivere.mit-license.org/license.txt for details.
4
5package elastic
6
7import (
8	"context"
9	"fmt"
10	"net/url"
11	"strings"
12
13	"github.com/olivere/elastic/uritemplates"
14)
15
16// IndicesStatsService provides stats on various metrics of one or more
17// indices. See https://www.elastic.co/guide/en/elasticsearch/reference/6.7/indices-stats.html.
18type IndicesStatsService struct {
19	client           *Client
20	pretty           bool
21	metric           []string
22	index            []string
23	level            string
24	types            []string
25	completionFields []string
26	fielddataFields  []string
27	fields           []string
28	groups           []string
29	human            *bool
30}
31
32// NewIndicesStatsService creates a new IndicesStatsService.
33func NewIndicesStatsService(client *Client) *IndicesStatsService {
34	return &IndicesStatsService{
35		client:           client,
36		index:            make([]string, 0),
37		metric:           make([]string, 0),
38		completionFields: make([]string, 0),
39		fielddataFields:  make([]string, 0),
40		fields:           make([]string, 0),
41		groups:           make([]string, 0),
42		types:            make([]string, 0),
43	}
44}
45
46// Metric limits the information returned the specific metrics. Options are:
47// docs, store, indexing, get, search, completion, fielddata, flush, merge,
48// query_cache, refresh, suggest, and warmer.
49func (s *IndicesStatsService) Metric(metric ...string) *IndicesStatsService {
50	s.metric = append(s.metric, metric...)
51	return s
52}
53
54// Index is the list of index names; use `_all` or empty string to perform
55// the operation on all indices.
56func (s *IndicesStatsService) Index(indices ...string) *IndicesStatsService {
57	s.index = append(s.index, indices...)
58	return s
59}
60
61// Type is a list of document types for the `indexing` index metric.
62func (s *IndicesStatsService) Type(types ...string) *IndicesStatsService {
63	s.types = append(s.types, types...)
64	return s
65}
66
67// Level returns stats aggregated at cluster, index or shard level.
68func (s *IndicesStatsService) Level(level string) *IndicesStatsService {
69	s.level = level
70	return s
71}
72
73// CompletionFields is a list of fields for `fielddata` and `suggest`
74// index metric (supports wildcards).
75func (s *IndicesStatsService) CompletionFields(completionFields ...string) *IndicesStatsService {
76	s.completionFields = append(s.completionFields, completionFields...)
77	return s
78}
79
80// FielddataFields is a list of fields for `fielddata` index metric (supports wildcards).
81func (s *IndicesStatsService) FielddataFields(fielddataFields ...string) *IndicesStatsService {
82	s.fielddataFields = append(s.fielddataFields, fielddataFields...)
83	return s
84}
85
86// Fields is a list of fields for `fielddata` and `completion` index metric
87// (supports wildcards).
88func (s *IndicesStatsService) Fields(fields ...string) *IndicesStatsService {
89	s.fields = append(s.fields, fields...)
90	return s
91}
92
93// Groups is a list of search groups for `search` index metric.
94func (s *IndicesStatsService) Groups(groups ...string) *IndicesStatsService {
95	s.groups = append(s.groups, groups...)
96	return s
97}
98
99// Human indicates whether to return time and byte values in human-readable format..
100func (s *IndicesStatsService) Human(human bool) *IndicesStatsService {
101	s.human = &human
102	return s
103}
104
105// Pretty indicates that the JSON response be indented and human readable.
106func (s *IndicesStatsService) Pretty(pretty bool) *IndicesStatsService {
107	s.pretty = pretty
108	return s
109}
110
111// buildURL builds the URL for the operation.
112func (s *IndicesStatsService) buildURL() (string, url.Values, error) {
113	var err error
114	var path string
115	if len(s.index) > 0 && len(s.metric) > 0 {
116		path, err = uritemplates.Expand("/{index}/_stats/{metric}", map[string]string{
117			"index":  strings.Join(s.index, ","),
118			"metric": strings.Join(s.metric, ","),
119		})
120	} else if len(s.index) > 0 {
121		path, err = uritemplates.Expand("/{index}/_stats", map[string]string{
122			"index": strings.Join(s.index, ","),
123		})
124	} else if len(s.metric) > 0 {
125		path, err = uritemplates.Expand("/_stats/{metric}", map[string]string{
126			"metric": strings.Join(s.metric, ","),
127		})
128	} else {
129		path = "/_stats"
130	}
131	if err != nil {
132		return "", url.Values{}, err
133	}
134
135	// Add query string parameters
136	params := url.Values{}
137	if s.pretty {
138		params.Set("pretty", "true")
139	}
140	if len(s.groups) > 0 {
141		params.Set("groups", strings.Join(s.groups, ","))
142	}
143	if s.human != nil {
144		params.Set("human", fmt.Sprintf("%v", *s.human))
145	}
146	if s.level != "" {
147		params.Set("level", s.level)
148	}
149	if len(s.types) > 0 {
150		params.Set("types", strings.Join(s.types, ","))
151	}
152	if len(s.completionFields) > 0 {
153		params.Set("completion_fields", strings.Join(s.completionFields, ","))
154	}
155	if len(s.fielddataFields) > 0 {
156		params.Set("fielddata_fields", strings.Join(s.fielddataFields, ","))
157	}
158	if len(s.fields) > 0 {
159		params.Set("fields", strings.Join(s.fields, ","))
160	}
161	return path, params, nil
162}
163
164// Validate checks if the operation is valid.
165func (s *IndicesStatsService) Validate() error {
166	return nil
167}
168
169// Do executes the operation.
170func (s *IndicesStatsService) Do(ctx context.Context) (*IndicesStatsResponse, error) {
171	// Check pre-conditions
172	if err := s.Validate(); err != nil {
173		return nil, err
174	}
175
176	// Get URL for request
177	path, params, err := s.buildURL()
178	if err != nil {
179		return nil, err
180	}
181
182	// Get HTTP response
183	res, err := s.client.PerformRequest(ctx, PerformRequestOptions{
184		Method: "GET",
185		Path:   path,
186		Params: params,
187	})
188	if err != nil {
189		return nil, err
190	}
191
192	// Return operation response
193	ret := new(IndicesStatsResponse)
194	if err := s.client.decoder.Decode(res.Body, ret); err != nil {
195		return nil, err
196	}
197	return ret, nil
198}
199
200// IndicesStatsResponse is the response of IndicesStatsService.Do.
201type IndicesStatsResponse struct {
202	// Shards provides information returned from shards.
203	Shards *ShardsInfo `json:"_shards"`
204
205	// All provides summary stats about all indices.
206	All *IndexStats `json:"_all,omitempty"`
207
208	// Indices provides a map into the stats of an index. The key of the
209	// map is the index name.
210	Indices map[string]*IndexStats `json:"indices,omitempty"`
211}
212
213// IndexStats is index stats for a specific index.
214type IndexStats struct {
215	Primaries *IndexStatsDetails              `json:"primaries,omitempty"`
216	Total     *IndexStatsDetails              `json:"total,omitempty"`
217	Shards    map[string][]*IndexStatsDetails `json:"shards,omitempty"`
218}
219
220type IndexStatsDetails struct {
221	Docs        *IndexStatsDocs        `json:"docs,omitempty"`
222	Store       *IndexStatsStore       `json:"store,omitempty"`
223	Indexing    *IndexStatsIndexing    `json:"indexing,omitempty"`
224	Get         *IndexStatsGet         `json:"get,omitempty"`
225	Search      *IndexStatsSearch      `json:"search,omitempty"`
226	Merges      *IndexStatsMerges      `json:"merges,omitempty"`
227	Refresh     *IndexStatsRefresh     `json:"refresh,omitempty"`
228	Flush       *IndexStatsFlush       `json:"flush,omitempty"`
229	Warmer      *IndexStatsWarmer      `json:"warmer,omitempty"`
230	FilterCache *IndexStatsFilterCache `json:"filter_cache,omitempty"`
231	IdCache     *IndexStatsIdCache     `json:"id_cache,omitempty"`
232	Fielddata   *IndexStatsFielddata   `json:"fielddata,omitempty"`
233	Percolate   *IndexStatsPercolate   `json:"percolate,omitempty"`
234	Completion  *IndexStatsCompletion  `json:"completion,omitempty"`
235	Segments    *IndexStatsSegments    `json:"segments,omitempty"`
236	Translog    *IndexStatsTranslog    `json:"translog,omitempty"`
237	Suggest     *IndexStatsSuggest     `json:"suggest,omitempty"`
238	QueryCache  *IndexStatsQueryCache  `json:"query_cache,omitempty"`
239}
240
241type IndexStatsDocs struct {
242	Count   int64 `json:"count,omitempty"`
243	Deleted int64 `json:"deleted,omitempty"`
244}
245
246type IndexStatsStore struct {
247	Size        string `json:"size,omitempty"` // human size, e.g. 119.3mb
248	SizeInBytes int64  `json:"size_in_bytes,omitempty"`
249}
250
251type IndexStatsIndexing struct {
252	IndexTotal         int64  `json:"index_total,omitempty"`
253	IndexTime          string `json:"index_time,omitempty"`
254	IndexTimeInMillis  int64  `json:"index_time_in_millis,omitempty"`
255	IndexCurrent       int64  `json:"index_current,omitempty"`
256	DeleteTotal        int64  `json:"delete_total,omitempty"`
257	DeleteTime         string `json:"delete_time,omitempty"`
258	DeleteTimeInMillis int64  `json:"delete_time_in_millis,omitempty"`
259	DeleteCurrent      int64  `json:"delete_current,omitempty"`
260	NoopUpdateTotal    int64  `json:"noop_update_total,omitempty"`
261}
262
263type IndexStatsGet struct {
264	Total               int64  `json:"total,omitempty"`
265	GetTime             string `json:"get_time,omitempty"`
266	TimeInMillis        int64  `json:"time_in_millis,omitempty"`
267	ExistsTotal         int64  `json:"exists_total,omitempty"`
268	ExistsTime          string `json:"exists_time,omitempty"`
269	ExistsTimeInMillis  int64  `json:"exists_time_in_millis,omitempty"`
270	MissingTotal        int64  `json:"missing_total,omitempty"`
271	MissingTime         string `json:"missing_time,omitempty"`
272	MissingTimeInMillis int64  `json:"missing_time_in_millis,omitempty"`
273	Current             int64  `json:"current,omitempty"`
274}
275
276type IndexStatsSearch struct {
277	OpenContexts        int64  `json:"open_contexts,omitempty"`
278	QueryTotal          int64  `json:"query_total,omitempty"`
279	QueryTime           string `json:"query_time,omitempty"`
280	QueryTimeInMillis   int64  `json:"query_time_in_millis,omitempty"`
281	QueryCurrent        int64  `json:"query_current,omitempty"`
282	FetchTotal          int64  `json:"fetch_total,omitempty"`
283	FetchTime           string `json:"fetch_time,omitempty"`
284	FetchTimeInMillis   int64  `json:"fetch_time_in_millis,omitempty"`
285	FetchCurrent        int64  `json:"fetch_current,omitempty"`
286	ScrollTotal         int64  `json:"scroll_total,omitempty"`
287	ScrollTime          string `json:"scroll_time,omitempty"`
288	ScrollTimeInMillis  int64  `json:"scroll_time_in_millis,omitempty"`
289	ScrollCurrent       int64  `json:"scroll_current,omitempty"`
290	SuggestTotal        int64  `json:"suggest_total,omitempty"`
291	SuggestTime         string `json:"suggest_time,omitempty"`
292	SuggestTimeInMillis int64  `json:"suggest_time_in_millis,omitempty"`
293	SuggestCurrent      int64  `json:"suggest_current,omitempty"`
294}
295
296type IndexStatsMerges struct {
297	Current            int64  `json:"current,omitempty"`
298	CurrentDocs        int64  `json:"current_docs,omitempty"`
299	CurrentSize        string `json:"current_size,omitempty"`
300	CurrentSizeInBytes int64  `json:"current_size_in_bytes,omitempty"`
301	Total              int64  `json:"total,omitempty"`
302	TotalTime          string `json:"total_time,omitempty"`
303	TotalTimeInMillis  int64  `json:"total_time_in_millis,omitempty"`
304	TotalDocs          int64  `json:"total_docs,omitempty"`
305	TotalSize          string `json:"total_size,omitempty"`
306	TotalSizeInBytes   int64  `json:"total_size_in_bytes,omitempty"`
307}
308
309type IndexStatsRefresh struct {
310	Total             int64  `json:"total,omitempty"`
311	TotalTime         string `json:"total_time,omitempty"`
312	TotalTimeInMillis int64  `json:"total_time_in_millis,omitempty"`
313}
314
315type IndexStatsFlush struct {
316	Total             int64  `json:"total,omitempty"`
317	TotalTime         string `json:"total_time,omitempty"`
318	TotalTimeInMillis int64  `json:"total_time_in_millis,omitempty"`
319}
320
321type IndexStatsWarmer struct {
322	Current           int64  `json:"current,omitempty"`
323	Total             int64  `json:"total,omitempty"`
324	TotalTime         string `json:"total_time,omitempty"`
325	TotalTimeInMillis int64  `json:"total_time_in_millis,omitempty"`
326}
327
328type IndexStatsFilterCache struct {
329	MemorySize        string `json:"memory_size,omitempty"`
330	MemorySizeInBytes int64  `json:"memory_size_in_bytes,omitempty"`
331	Evictions         int64  `json:"evictions,omitempty"`
332}
333
334type IndexStatsIdCache struct {
335	MemorySize        string `json:"memory_size,omitempty"`
336	MemorySizeInBytes int64  `json:"memory_size_in_bytes,omitempty"`
337}
338
339type IndexStatsFielddata struct {
340	MemorySize        string `json:"memory_size,omitempty"`
341	MemorySizeInBytes int64  `json:"memory_size_in_bytes,omitempty"`
342	Evictions         int64  `json:"evictions,omitempty"`
343}
344
345type IndexStatsPercolate struct {
346	Total             int64  `json:"total,omitempty"`
347	GetTime           string `json:"get_time,omitempty"`
348	TimeInMillis      int64  `json:"time_in_millis,omitempty"`
349	Current           int64  `json:"current,omitempty"`
350	MemorySize        string `json:"memory_size,omitempty"`
351	MemorySizeInBytes int64  `json:"memory_size_in_bytes,omitempty"`
352	Queries           int64  `json:"queries,omitempty"`
353}
354
355type IndexStatsCompletion struct {
356	Size        string `json:"size,omitempty"`
357	SizeInBytes int64  `json:"size_in_bytes,omitempty"`
358}
359
360type IndexStatsSegments struct {
361	Count                       int64  `json:"count,omitempty"`
362	Memory                      string `json:"memory,omitempty"`
363	MemoryInBytes               int64  `json:"memory_in_bytes,omitempty"`
364	IndexWriterMemory           string `json:"index_writer_memory,omitempty"`
365	IndexWriterMemoryInBytes    int64  `json:"index_writer_memory_in_bytes,omitempty"`
366	IndexWriterMaxMemory        string `json:"index_writer_max_memory,omitempty"`
367	IndexWriterMaxMemoryInBytes int64  `json:"index_writer_max_memory_in_bytes,omitempty"`
368	VersionMapMemory            string `json:"version_map_memory,omitempty"`
369	VersionMapMemoryInBytes     int64  `json:"version_map_memory_in_bytes,omitempty"`
370	FixedBitSetMemory           string `json:"fixed_bit_set,omitempty"`
371	FixedBitSetMemoryInBytes    int64  `json:"fixed_bit_set_memory_in_bytes,omitempty"`
372}
373
374type IndexStatsTranslog struct {
375	Operations  int64  `json:"operations,omitempty"`
376	Size        string `json:"size,omitempty"`
377	SizeInBytes int64  `json:"size_in_bytes,omitempty"`
378}
379
380type IndexStatsSuggest struct {
381	Total        int64  `json:"total,omitempty"`
382	Time         string `json:"time,omitempty"`
383	TimeInMillis int64  `json:"time_in_millis,omitempty"`
384	Current      int64  `json:"current,omitempty"`
385}
386
387type IndexStatsQueryCache struct {
388	MemorySize        string `json:"memory_size,omitempty"`
389	MemorySizeInBytes int64  `json:"memory_size_in_bytes,omitempty"`
390	Evictions         int64  `json:"evictions,omitempty"`
391	HitCount          int64  `json:"hit_count,omitempty"`
392	MissCount         int64  `json:"miss_count,omitempty"`
393}
394