Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
255bab7
Support wait_for_status query param on root endpoint
estolfo Oct 27, 2025
a73fe16
Use Java::OrgLogstashHealth::Status enum values for status constant
estolfo Oct 28, 2025
131d669
Add docs for root api including new query params
estolfo Oct 28, 2025
61a138a
Be consistent with return statuses definition in specs
estolfo Oct 28, 2025
aa51212
Use org.logstash.health.Status for constant and in tests
estolfo Oct 29, 2025
2bb4c79
Return http status code 503 when timeout and support target status or…
estolfo Oct 29, 2025
7fbd94c
Update docs with note about returning status code 503
estolfo Oct 29, 2025
7503077
Use Timeout instead while waiting for the status
estolfo Oct 30, 2025
0affd82
Only use green, yellow, and red statuses in constant (exclude unknown)
estolfo Oct 30, 2025
242f030
Handle non integer timeout string
estolfo Oct 30, 2025
042bf1c
Add the loop back in to timeout block
estolfo Oct 30, 2025
d0c064e
Update tests
estolfo Oct 30, 2025
9c50760
Refactor and fix tests
estolfo Oct 31, 2025
a5e25f4
Not necessary to handle status code in app helpers anymore
estolfo Oct 31, 2025
dfdf224
Rename method to reflect time units
estolfo Oct 31, 2025
8f9a031
Use shared examples in specs
estolfo Oct 31, 2025
a1cb3f2
Small update to comment
estolfo Oct 31, 2025
6c6d18f
Change variables names for clarity
estolfo Oct 31, 2025
805114f
No need to check for nil, the method is called only if the variable i…
estolfo Oct 31, 2025
a9b53f0
Fix shared examples name
estolfo Nov 4, 2025
174934d
Update docs/static/spec/openapi/logstash-api.yaml
estolfo Nov 4, 2025
79a44a8
Update docs/static/spec/openapi/logstash-api.yaml
estolfo Nov 4, 2025
2e28f38
Use deadline instead of Timeout
estolfo Nov 4, 2025
bab9243
Be more explicit about class being Float
estolfo Nov 4, 2025
b53c9d7
No need for timeout
estolfo Nov 4, 2025
f9e50e9
Test timeout units in ms
estolfo Nov 4, 2025
2084dc1
Minor updates to specs
estolfo Nov 4, 2025
3d5695f
Update comment
estolfo Nov 4, 2025
131eaa6
Use status code 408 when the request times out
estolfo Nov 4, 2025
9f7d256
Require timeout along with wait_for_status
estolfo Nov 5, 2025
2f4244e
Update docs to be clearer about timeout being required with wait_for_…
estolfo Nov 5, 2025
770cba8
Move before block to shared examples
estolfo Nov 5, 2025
9311b98
Update logstash-core/lib/logstash/api/modules/root.rb
estolfo Nov 24, 2025
6164f5d
Limit the sleep time to max timeout
estolfo Nov 24, 2025
b6d013f
Update logstash-core/lib/logstash/api/modules/root.rb
estolfo Nov 24, 2025
15900be
Updates to docs
estolfo Dec 1, 2025
283dc4b
Add build_date, build_sha, build_snapshot to docs
estolfo Dec 1, 2025
31ccb9f
Update docs to say timeout status code is 408
estolfo Dec 2, 2025
b3c73eb
Fix linting errors in logstash-api.yaml
lcawl Dec 3, 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
82 changes: 82 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,88 @@ 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. Must be an integer with units, for example `3s`. If the target status is not reached before the timeout expires, the request returns status code 408.
- $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: boolean
status:
type: string
build_date:
type: string
build_sha:
type: string
build_snapshot:
type: boolean
pipeline:
type: object
properties:
workers:
type: integer
batch_size:
type: integer
batch_delay:
type: integer
examples:
basicMetadataExample1:
value:
host: "logstash-pipelines.example.com"
version: "9.2.1"
http_address: "127.0.0.1:9600"
id: "58df6f7c-eb5c-5d42-bc20-c7b22779aa12"
name: "logstash-pipelines"
ephemeral_id: "59df6f6c-eb5c-4d42-bc20-c7b44779aa12"
snapshot: true
status: "green"
build_date: "2025-11-20T01:18:55+00:00"
build_sha: "ff3e87d66f10c05a74d0cef7bc2911d60cee1ebc"
build_snapshot: true
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