Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ Please mark backwards incompatible changes with an exclamation mark at the start

## [Unreleased]

### Added
- The `#stats` method to the `Elasticsearch::Client` class. The method returns
an object that can be used to retrieve statistics about the Cluster. For the
moment only `#indices` is available, which returns index-related statistics.

## [28.0.0] - 2025-05-09

### Added
Expand Down
47 changes: 47 additions & 0 deletions documentation/source/user_guidelines/elasticsearch/stats.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
Stats
=====

The ``Stats`` class gives you access to various statistics about the
Elasticsearch cluster. The class can be accessed by calling the ``#stats``
method on an instance of the ``Elasticsearch::Client`` class. For example:

.. code-block:: ruby

require 'jay_api/elasticsearch/client_factory'

client_factory = JayAPI::Elasticsearch::ClientFactory.new(...)
client = client_factory.create

stats = client.stats

The ``Stats`` class has the following methods:

#indices
--------

This method gives you access to index-related statistics. The method returns an
instance of the ``Stats::Indices`` class, which in turn allows you to access
Comment thread
sergio-bobillier marked this conversation as resolved.
information on each of the individual indices through these methods:

#all
++++

This method returns an ``Enumerator`` whose elements are ``Stats::Index``
objects, one for each of the indices on the cluster, including system indices.

#system
+++++++

This method returns an ``Enumerator`` whose elements are ``Stats::Index``
objects, one for each of the system indices on the cluster.

#user
+++++

This method returns an ``Enumerator`` whose elements are ``Stats::Index``
objects, one for each of the user-created indices on the cluster.

The ``Stats::Index`` objects have the following methods:

``#name``
The name of the index.
1 change: 1 addition & 0 deletions lib/jay_api/elasticsearch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
require_relative 'elasticsearch/query_results'
require_relative 'elasticsearch/response'
require_relative 'elasticsearch/search_after_results'
require_relative 'elasticsearch/stats'
require_relative 'elasticsearch/tasks'
require_relative 'elasticsearch/time'

Expand Down
7 changes: 7 additions & 0 deletions lib/jay_api/elasticsearch/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require 'forwardable'

require_relative '../abstract/connection'
require_relative 'stats'

module JayAPI
module Elasticsearch
Expand Down Expand Up @@ -91,6 +92,12 @@ def task_by_id(**args)
retry_request { transport_client.tasks.get(**args) }
end

# @return [JayAPI::Elasticsearch::Stats] An instance of the +Stats+ class,
# which gives the caller access to Elasticsearch's Statistics API.
def stats
@stats ||= ::JayAPI::Elasticsearch::Stats.new(transport_client)
end

private

# @param [Proc] block The block to execute.
Expand Down
39 changes: 39 additions & 0 deletions lib/jay_api/elasticsearch/stats.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

require_relative 'stats/index'
require_relative 'stats/indices'

module JayAPI
module Elasticsearch
# This class provides access to Elasticsearch's Cluster Statistic API.
class Stats
attr_reader :transport_client, :logger

# @param [Elasticsearch::Transport::Client] transport_client The transport
# client to use to make requests to the cluster.
def initialize(transport_client)
@transport_client = transport_client
end

# @return [JayAPI::Elasticsearch::Stats::Indices] Information about the
# indices that exist in the Elasticsearch cluster.
# @raise [Elasticsearch::Transport::Transport::ServerError] If the request
# to the Statistics API endpoint fails.
def indices
# DO NOT MEMOIZE! Leave it to the caller.
::JayAPI::Elasticsearch::Stats::Indices.new(response['indices'])
end

private

# @return [Hash] The Hash with the statistics returned by the
# Elasticsearch cluster.
# @raise [Elasticsearch::Transport::Transport::ServerError] If the
# request fails.
def response
# DO NOT MEMOIZE! Leave it to the caller.
transport_client.indices.stats
end
end
end
end
19 changes: 19 additions & 0 deletions lib/jay_api/elasticsearch/stats/index.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

module JayAPI
module Elasticsearch
class Stats
# Holds information about an Elasticsearch Index.
class Index
attr_reader :name

# @param [String] name The name of the index.
# @param [Hash] data Information about the index.
def initialize(name, data)
@name = name
@data = data
end
end
end
end
end
64 changes: 64 additions & 0 deletions lib/jay_api/elasticsearch/stats/indices.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# frozen_string_literal: true

require_relative 'index'

module JayAPI
module Elasticsearch
class Stats
# Provides access to the list of indices returned by Elasticsearch's
# Stats API
class Indices
# A lambda used to select / reject system indices (indices whose name
# starts with dot).
SYSTEM_SELECTOR = ->(name, _data) { name.starts_with?('.') }

# @param [Hash{String=>Hash}] indices A +Hash+ with the information
# about the indices. Its keys are the names of the indices, its values
# hashes with information about each of the indices.
def initialize(indices)
@indices = indices
end

# @return [Enumerator::Lazy<JayAPI::Elasticsearch::Stats::Index>] A lazy
# enumerator of +Index+ objects, one for each of the indexes. All
# indices (system and user-defined are included).
def all
@all ||= with_lazy_instantiation { indices }
end

# @return [Enumerator::Lazy<JayAPI::Elasticsearch::Stats::Index>] A lazy
# enumerator of +Index+ objects. Includes only the system indices.
def system
@system ||= with_lazy_instantiation { indices.select(&SYSTEM_SELECTOR) }
end

# @return [Enumerator::Lazy<JayAPI::Elasticsearch::Stats::Index>] A lazy
# enumerator of +Index+ objects. Includes only the user-defined
# indices.
def user
@user ||= with_lazy_instantiation { indices.reject(&SYSTEM_SELECTOR) }
end

private

attr_reader :indices

# @param [Array(String, Hash)] args An array with two elements, the name
# of the index and its information.
# @return [JayAPI::Elasticsearch::Stats::Index] An +Index+ object
# representing the given index.
def build_index(args)

Check failure on line 50 in lib/jay_api/elasticsearch/stats/indices.rb

View workflow job for this annotation

GitHub Actions / lint

[reek] reported by reviewdog 🐶 UtilityFunction: JayAPI::Elasticsearch::Stats::Indices#build_index doesn't depend on instance state (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.1.4/docs/Utility-Function.md] Raw Output: lib/jay_api/elasticsearch/stats/indices.rb:50: UtilityFunction: JayAPI::Elasticsearch::Stats::Indices#build_index doesn't depend on instance state (maybe move it to another class?) [https://github.com/troessner/reek/blob/v6.1.4/docs/Utility-Function.md]
JayAPI::Elasticsearch::Stats::Index.new(*args)
end

# Calls the given block and turns its return value into a lazy
# enumerator that instantiates an +Index+ object for each of the
# elements of the collection returned by block.
# @return [Enumerator::Lazy<JayAPI::Elasticsearch::Stats::Index>]
def with_lazy_instantiation(&block)
block.call.lazy.map(&method(:build_index))
end
end
end
end
end
23 changes: 23 additions & 0 deletions spec/integration/jay_api/elasticsearch/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -296,4 +296,27 @@
method_call
end
end

describe '#stats' do
subject(:method_call) { client.stats }

let(:stats) do
instance_double(
JayAPI::Elasticsearch::Stats
)
end

before do
allow(JayAPI::Elasticsearch::Stats).to receive(:new).and_return(stats)
end

it 'initializes an instance of JayAPI::Elasticsearch::Stats and passes the transport client to it' do
expect(JayAPI::Elasticsearch::Stats).to receive(:new).with(transport_client)
method_call
end

it 'returns the JayAPI::Elasticsearch::Stats instance' do
expect(method_call).to be(stats)
end
end
end
19 changes: 19 additions & 0 deletions spec/jay_api/elasticsearch/stats/index_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

require 'jay_api/elasticsearch/stats/index'

RSpec.describe JayAPI::Elasticsearch::Stats::Index do
subject(:index) { described_class.new(name, data) }

let(:name) { 'xyz01_integration_tests' }
let(:data) { {} }

describe '#initialize' do
subject(:method_call) { index }

it 'stores the given name' do
method_call
expect(index.name).to be(name)
end
end
end
79 changes: 79 additions & 0 deletions spec/jay_api/elasticsearch/stats/indices_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# frozen_string_literal: true

require 'jay_api/elasticsearch/stats/indices'

RSpec.describe JayAPI::Elasticsearch::Stats::Indices do
subject(:indices) { described_class.new(indices_hash) }

let(:indices_hash) do
{
'xyz01_integration_test' => {
'uuid' => 'OXRb8_IYTseG2epNa9Ls3g'
},
'xyz01_unit_tests' => {
'uuid' => 'hxDdhi-3TFSndxhLesspFw'
},
'.kibana_views' => {
'uuid' => 'pr-VjrPARlG3lAoAfPqNog'
},
'xyz02_manual_verification' => {
'uuid' => 'uaZ_kKQuSM-HaKH_LcI7BQ'
},
'.backup' => {
'uuid' => 'N7TZOstjRHu8mTwsLZuQ5w'
}
}
end

shared_examples_for '#all' do
it 'returns an Enumerator::Lazy' do
expect(method_call).to be_a(Enumerator::Lazy)
end

it 'includes the expected number of indices' do
expect(method_call.size).to eq(expected_indices_size)
end

it 'includes only instances of JayAPI::Elasticsearch::Stats::Index' do
expect(method_call).to all(be_a(JayAPI::Elasticsearch::Stats::Index))
end

it 'includes the expected list of indices' do
# #to_a is needed here because of the lazy enumerator.
expect(method_call.map(&:name).to_a).to eq(expected_indices)
end
end

describe '#all' do
subject(:method_call) { indices.all }

let(:expected_indices_size) { 5 }

let(:expected_indices) do
%w[xyz01_integration_test xyz01_unit_tests .kibana_views xyz02_manual_verification .backup]
end

it_behaves_like '#all'
end

describe '#system' do
subject(:method_call) { indices.system }

let(:expected_indices_size) { 2 }
let(:expected_indices) { %w[.kibana_views .backup] }

it_behaves_like '#all'
end

describe '#user' do
subject(:method_call) { indices.user }

let(:expected_indices_size) { 3 }

let(:expected_indices) do
%w[xyz01_integration_test xyz01_unit_tests xyz02_manual_verification]
end

it_behaves_like '#all'
end
end
Loading