Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6034a90
Support wait_for_status query param on root endpoint
estolfo Oct 27, 2025
870b8aa
Use Java::OrgLogstashHealth::Status enum values for status constant
estolfo Oct 28, 2025
75a1338
Add docs for root api including new query params
estolfo Oct 28, 2025
804ce9d
Be consistent with return statuses definition in specs
estolfo Oct 28, 2025
265952e
Use org.logstash.health.Status for constant and in tests
estolfo Oct 29, 2025
d7b7429
Return http status code 503 when timeout and support target status or…
estolfo Oct 29, 2025
e329a4b
Update docs with note about returning status code 503
estolfo Oct 29, 2025
fdf667b
Use Timeout instead while waiting for the status
estolfo Oct 30, 2025
13a1c27
Only use green, yellow, and red statuses in constant (exclude unknown)
estolfo Oct 30, 2025
c68ba40
Handle non integer timeout string
estolfo Oct 30, 2025
4741401
Add the loop back in to timeout block
estolfo Oct 30, 2025
aec5543
Update tests
estolfo Oct 30, 2025
00351c4
Refactor and fix tests
estolfo Oct 31, 2025
ea0bb63
Not necessary to handle status code in app helpers anymore
estolfo Oct 31, 2025
0d765fd
Rename method to reflect time units
estolfo Oct 31, 2025
8516f2e
Use shared examples in specs
estolfo Oct 31, 2025
8f0dfea
Small update to comment
estolfo Oct 31, 2025
864f20f
Change variables names for clarity
estolfo Oct 31, 2025
2a54b33
No need to check for nil, the method is called only if the variable i…
estolfo Oct 31, 2025
6f1e092
Fix shared examples name
estolfo Nov 4, 2025
68e3539
Update docs/static/spec/openapi/logstash-api.yaml
estolfo Nov 4, 2025
fa8816c
Update docs/static/spec/openapi/logstash-api.yaml
estolfo Nov 4, 2025
e11d22a
Use deadline instead of Timeout
estolfo Nov 4, 2025
596c1e9
Be more explicit about class being Float
estolfo Nov 4, 2025
537ed6a
No need for timeout
estolfo Nov 4, 2025
a0b51c8
Test timeout units in ms
estolfo Nov 4, 2025
5657d07
Minor updates to specs
estolfo Nov 4, 2025
405589b
Update comment
estolfo Nov 4, 2025
6fdf433
Use status code 408 when the request times out
estolfo Nov 4, 2025
ba52df2
Require timeout along with wait_for_status
estolfo Nov 5, 2025
83ebd0b
Update docs to be clearer about timeout being required with wait_for_…
estolfo Nov 5, 2025
0081e59
Move before block to shared examples
estolfo Nov 5, 2025
4fabcfc
Update logstash-core/lib/logstash/api/modules/root.rb
estolfo Nov 24, 2025
359d184
Limit the sleep time to max timeout
estolfo Nov 24, 2025
d415f65
Update logstash-core/lib/logstash/api/modules/root.rb
estolfo Nov 24, 2025
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
71 changes: 71 additions & 0 deletions docs/static/spec/openapi/logstash-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,77 @@ tags:
# description:
# url:
paths:
/:
get:
summary: Gets basic metadata
description: |
Shows basic metadata about the running logstash service. This includes build info, pipeline info and the service's status.
operationId: root
tags:
- root
parameters:
- name: wait_for_status
in: query
required: false
schema:
type: string
description: One of green, yellow or red. Will wait (until the timeout provided) until the status of the service changes to the one provided or better, i.e. green > yellow > red. The query param, timeout, is required when this query param is provided.
- name: timeout
in: query
required: false
schema:
type: string
description: Period to wait for the status to reach the requested target status. If the target status is not reached before the timeout expires, the request returns status code 503.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link to external documentation, as do the ES docs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Nit)

I know the original ES docs don't have it, but specifying the unit here might be a useful clarification

- $ref: "#/components/parameters/pretty"
responses:
'200':
description: Indicates a successful call
content:
application/json:
schema:
- type: object
properties:
host:
type: string
version:
type: string
http_address:
type: string
id:
type: string
name:
type: string
ephemeral_id:
type: string
snapshot:
type: string
status:
type: string
pipeline:
type: object
properties:
workers:
type: integer
batch_size:
type: integer
batch_delay:
type: integer
example:
host: "logstash-pipelines.example.com"
version: "9.3.0"
http_address: "127.0.0.1:9600"
id: "58df6f7c-eb5c-5d42-bc20-c7b22779aa12"
name: "logstash-pipelines"
ephermeral_id: "59df6f6c-eb5c-4d42-bc20-c7b44779aa12"
snapshot:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Determine what an example value would be here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this still need to be done?

status: "green"
pipeline:
workers: 10
batch_size: 125
batch_delay: 50
x-metaTags:
- content: Logstash
name: product_name
/_node/jvm:
get:
summary: Gets node-level JVM info
Expand Down
20 changes: 20 additions & 0 deletions logstash-core/lib/logstash/api/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,25 @@ def status_code
404
end
end

class BadRequest < ApiError
def initialize(message = nil)
super(message || "Bad Request")
end

def status_code
400
end
end

class RequestTimeout < ApiError
def initialize(message = nil)
super(message || "Request Timeout")
end

def status_code
408
end
end
end
end
75 changes: 74 additions & 1 deletion logstash-core/lib/logstash/api/modules/root.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,82 @@ module LogStash
module Api
module Modules
class Root < ::LogStash::Api::Modules::Base

HEALTH_STATUS = [
Java::OrgLogstashHealth::Status::GREEN,
Java::OrgLogstashHealth::Status::YELLOW,
Java::OrgLogstashHealth::Status::RED
].map(&:external_value)

INVALID_HEALTH_STATUS_MESSAGE = "Invalid status '%s' provided. The valid statuses are: green, yellow, red."
INVALID_TIMEOUT_MESSAGE = "Invalid timeout '%s' provided."
TIMEOUT_REQUIRED_WITH_STATUS_MESSAGE = "A timeout must be provided along with a status."
TIMED_OUT_WAITING_FOR_STATUS_MESSAGE = "Timed out waiting for status '%s'."

get "/" do
input_status = params[:wait_for_status]
input_timeout = params[:timeout]

if input_status && !(target_status = parse_status(input_status))
return status_error_response(input_status)
end

if input_timeout && !(timeout_s = parse_timeout_s(input_timeout))
return timeout_error_response(input_timeout)
end

if target_status
return timeout_required_with_status_response unless timeout_s
wait_for_status_and_respond(target_status, timeout_s)
else
command = factory.build(:system_basic_info)
respond_with(command.run)
end
end

private
def parse_timeout_s(timeout)
# If we call #to_seconds directly, the value will be rounded. So call to_nanos, then convert
# to a float and divide by 1e9 to get the value in seconds.
LogStash::Util::TimeValue.from_value(timeout).to_nanos.to_f/1_000_000_000
rescue ArgumentError
end

def parse_status(input_status)
target_status = input_status.downcase
target_status if HEALTH_STATUS.include?(target_status)
end

def timeout_error_response(timeout)
respond_with(BadRequest.new(INVALID_TIMEOUT_MESSAGE % [timeout]))
end

def status_error_response(target_status)
respond_with(BadRequest.new(INVALID_HEALTH_STATUS_MESSAGE % [target_status]))
end

def timeout_required_with_status_response
respond_with(BadRequest.new(TIMEOUT_REQUIRED_WITH_STATUS_MESSAGE))
end

def wait_for_status_and_respond(target_status, timeout)
wait_interval = 0.2 # seconds
deadline = Time.now + timeout

loop do
current_status = HEALTH_STATUS.index(agent.health_observer.status.external_value)
break if current_status <= HEALTH_STATUS.index(target_status)

time_remaining = deadline - Time.now
if time_remaining <= 0
return respond_with(RequestTimeout.new(TIMED_OUT_WAITING_FOR_STATUS_MESSAGE % [target_status]))
end
sleep((time_remaining <= wait_interval) ? time_remaining : wait_interval)
wait_interval = wait_interval * 2
end

command = factory.build(:system_basic_info)
respond_with command.run
respond_with(command.run)
end
end
end
Expand Down
Loading
Loading