Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
87dc90d
Support wait_for_status query param on root endpoint
estolfo Oct 27, 2025
93d0692
Use Java::OrgLogstashHealth::Status enum values for status constant
estolfo Oct 28, 2025
01d58bf
Add docs for root api including new query params
estolfo Oct 28, 2025
5f16c88
Be consistent with return statuses definition in specs
estolfo Oct 28, 2025
72e198a
Use org.logstash.health.Status for constant and in tests
estolfo Oct 29, 2025
31a106b
Return http status code 503 when timeout and support target status or…
estolfo Oct 29, 2025
8a82ee7
Update docs with note about returning status code 503
estolfo Oct 29, 2025
163c354
Use Timeout instead while waiting for the status
estolfo Oct 30, 2025
a80b59a
Only use green, yellow, and red statuses in constant (exclude unknown)
estolfo Oct 30, 2025
8dd7bf5
Handle non integer timeout string
estolfo Oct 30, 2025
c938099
Add the loop back in to timeout block
estolfo Oct 30, 2025
52beb65
Update tests
estolfo Oct 30, 2025
02b7106
Refactor and fix tests
estolfo Oct 31, 2025
1715841
Not necessary to handle status code in app helpers anymore
estolfo Oct 31, 2025
b8abfef
Rename method to reflect time units
estolfo Oct 31, 2025
d8c5ad9
Use shared examples in specs
estolfo Oct 31, 2025
9d4a92e
Small update to comment
estolfo Oct 31, 2025
aa032a9
Change variables names for clarity
estolfo Oct 31, 2025
06e3af5
No need to check for nil, the method is called only if the variable i…
estolfo Oct 31, 2025
9167271
Fix shared examples name
estolfo Nov 4, 2025
fbd5a05
Update docs/static/spec/openapi/logstash-api.yaml
estolfo Nov 4, 2025
63f3736
Update docs/static/spec/openapi/logstash-api.yaml
estolfo Nov 4, 2025
2480f7c
Use deadline instead of Timeout
estolfo Nov 4, 2025
09fc5d3
Be more explicit about class being Float
estolfo Nov 4, 2025
a6206ec
No need for timeout
estolfo Nov 4, 2025
aa70564
Test timeout units in ms
estolfo Nov 4, 2025
f630550
Minor updates to specs
estolfo Nov 4, 2025
292c694
Update comment
estolfo Nov 4, 2025
1979b5b
Use status code 408 when the request times out
estolfo Nov 4, 2025
9fdb16f
Require timeout along with wait_for_status
estolfo Nov 5, 2025
de539bd
Update docs to be clearer about timeout being required with wait_for_…
estolfo Nov 5, 2025
ef50070
Move before block to shared examples
estolfo Nov 5, 2025
3d24a47
Update logstash-core/lib/logstash/api/modules/root.rb
estolfo Nov 24, 2025
aba2ffb
Limit the sleep time to max timeout
estolfo Nov 24, 2025
a58a054
Update logstash-core/lib/logstash/api/modules/root.rb
estolfo Nov 24, 2025
1aa3240
Updates to docs
estolfo Dec 1, 2025
6c6034b
Add build_date, build_sha, build_snapshot to docs
estolfo Dec 1, 2025
7f53ecf
Update docs to say timeout status code is 408
estolfo Dec 2, 2025
2eaff59
Fix linting errors in logstash-api.yaml
lcawl Dec 3, 2025
884b513
Use common schema for root response descriptions
estolfo Dec 8, 2025
e7924f2
Sort tags by displayname
lcawl Dec 8, 2025
a289e3b
Handle the case when the current status is unknown
estolfo Dec 9, 2025
fde74b3
Update docs/static/spec/openapi/logstash-api.yaml
estolfo Dec 9, 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
81 changes: 81 additions & 0 deletions docs/static/spec/openapi/logstash-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ tags:
# externalDocs:
# description:
# url:
- name: root
x-displayName: Metadata
description: |
Build and service metadata, including build info, pipeline info and the service's status.
# externalDocs:
# description:
# url:
- name: node info
x-displayName: Node info
description: |
Expand All @@ -66,6 +73,80 @@ tags:
# description:
# url:
paths:
/:
get:
summary: Get build and service 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: Wait (until the timeout expires) for the service changes to a specific health status (or a better status). A green status is better than yellow and yellow is better than red. The `timeout` query parameter is required when you use this parameter.
- 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:
allOf:
- $ref: '#/components/schemas/Common'
- type: object
properties:
build_date:
type: string
description: The timestamp when this Logstash build was created.
build_sha:
type: string
description: The SHA-1 hash of the Logstash build.
build_snapshot:
type: boolean
description: Whether this Logstash build is a snapshot build.
pipeline:
type: object
properties:
workers:
type: integer
description: The number of workers in the pipeline.
batch_size:
type: integer
description: The batch size for the pipeline.
batch_delay:
type: integer
description: The batch delay for the pipeline.
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
76 changes: 75 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,83 @@ 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)
# The current status could be "unknown", which isn't in the HEALTH_STATUS array.
break if current_status && 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