forked from elastic/logstash
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
support multiple pipelines in one logstash instance
* add multi_local source for multi pipelines * introduce pipelines.yml * introduce PipelineSettings class * support reloading of pipeline parameters * fix pipeline api call for _node/pipelines * inform user pipelines.yml is ignored if -e or -f is enabled
- Loading branch information
Showing
36 changed files
with
578 additions
and
144 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# List of pipelines to be loaded by Logstash | ||
# | ||
# This document must be a list of dictionaries/hashes, where the keys/values are pipeline settings. | ||
# Default values for ommitted settings are read from the `logstash.yml` file. | ||
# When declaring multiple pipelines, each MUST have its own `pipeline.id`. | ||
# | ||
# Example of two pipelines: | ||
# | ||
# - pipeline.id: test | ||
# pipeline.workers: 1 | ||
# pipeline.batch.size: 1 | ||
# config.string: "input { generator {} } filter { sleep { time => 1 } } output { stdout { codec => dots } } | ||
# - pipeline.id: another_test | ||
# queue.type: persisted | ||
# path.config: "/tmp/logstash/*.config" | ||
# | ||
# Available options: | ||
# | ||
# # name of the pipeline | ||
# pipeline.id: mylogs | ||
# | ||
# # The configuration string to be used by this pipeline | ||
# config.string: "input { generator {} } filter { sleep { time => 1 } } output { stdout { codec => dots } }" | ||
# | ||
# # The path from where to read the configuration text | ||
# path.config: "/etc/conf.d/logstash/myconfig.cfg" | ||
# | ||
# # How many worker threads execute the Filters+Outputs stage of the pipeline | ||
# pipeline.workers: 1 (actually defaults to number of CPUs) | ||
# | ||
# # How many events to retrieve from inputs before sending to filters+workers | ||
# pipeline.batch.size: 125 | ||
# | ||
# # How long to wait before dispatching an undersized batch to filters+workers | ||
# pipeline.batch.delay: 5 | ||
# | ||
# # How many workers should be used per output plugin instance | ||
# pipeline.output.workers: 1 | ||
# | ||
# # Internal queuing model, "memory" for legacy in-memory based queuing and | ||
# # "persisted" for disk-based acked queueing. Defaults is memory | ||
# queue.type: memory | ||
# | ||
# # If using queue.type: persisted, the page data files size. The queue data consists of | ||
# # append-only data files separated into pages. Default is 250mb | ||
# queue.page_capacity: 250mb | ||
# | ||
# # If using queue.type: persisted, the maximum number of unread events in the queue. | ||
# # Default is 0 (unlimited) | ||
# queue.max_events: 0 | ||
# | ||
# # If using queue.type: persisted, the total capacity of the queue in number of bytes. | ||
# # Default is 1024mb or 1gb | ||
# queue.max_bytes: 1024mb | ||
# | ||
# # If using queue.type: persisted, the maximum number of acked events before forcing a checkpoint | ||
# # Default is 1024, 0 for unlimited | ||
# queue.checkpoint.acks: 1024 | ||
# | ||
# # If using queue.type: persisted, the maximum number of written events before forcing a checkpoint | ||
# # Default is 1024, 0 for unlimited | ||
# queue.checkpoint.writes: 1024 | ||
# | ||
# # If using queue.type: persisted, the interval in milliseconds when a checkpoint is forced on the head page | ||
# # Default is 1000, 0 for no periodic checkpoint. | ||
# queue.checkpoint.interval: 1000 | ||
# | ||
# # Enable Dead Letter Queueing for this pipeline. | ||
# dead_letter_queue.enable: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
[[multiple-pipelines]] | ||
=== Multiple Pipelines | ||
|
||
If you need to run more than one pipeline in the same process, Logstash provides a way to do it through a configuration file called `pipelines.yml`. | ||
This file must be placed in the `path.settings` folder and follows this structure: | ||
|
||
```yaml | ||
- pipeline.id: my-pipeline_1 | ||
path.config: "/etc/path/to/p1.config" | ||
pipeline.workers: 3 | ||
- pipeline.id: my-other-pipeline | ||
path.config: "/etc/different/path/p2.cfg" | ||
queue.type: persisted | ||
``` | ||
|
||
This file is formatted in YAML and contains a list of dictionaries where each dictionary describes a pipeline and each key/value pair a setting for that pipeline. In the example above, we describe two pipelines by stating their ids and their configuration paths. Also, for the first pipeline we set the value of `pipeline.workers` to 3, while in the other we enable Persistent Queue. | ||
The value of a setting that is not explictly set in this file will fall back to the defaults described in the `logstash.yml` file. | ||
|
||
Starting Logstash without arguments will make it read the `pipelines.yml` file and instantiate the multiple pipelines. On the other hand, using -e or -f will make Logstash ignore the `pipelines.yml` file and log a warning about it. | ||
|
||
[[multiple-pipeline-usage]] | ||
==== Usage Considerations | ||
|
||
Using multiple pipelines is specially useful if your current configuration has event flows that don't share the same inputs/filters and outputs and are being separated from each other using tags and conditionals. | ||
|
||
Having multiple pipelines in a single instances also allows these event flows to have different performance and durability parameters (e.g. pipeline.workers and persistent queues). this separation means that a blocked output in one pipeline won't exert backpressure in the other. | ||
|
||
That said, it's important to take into account resource competition between the pipelines, given that the default values are tuned for a single pipeline. So, for example, consider reducing the number of pipeline workers used by each pipeline, as by default each will use 1 worker per CPU core. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# encoding: utf-8 | ||
require "logstash/config/source/local" | ||
require "logstash/util/loggable" | ||
require "logstash/pipeline_settings" | ||
|
||
module LogStash module Config module Source | ||
class MultiLocal < Local | ||
include LogStash::Util::Loggable | ||
|
||
def initialize(settings) | ||
@original_settings = settings | ||
super(settings) | ||
end | ||
|
||
def pipeline_configs | ||
pipelines = retrieve_yaml_pipelines() | ||
pipelines_settings = pipelines.map do |pipeline_settings| | ||
::LogStash::PipelineSettings.from_settings(@original_settings.clone).merge(pipeline_settings) | ||
end | ||
detect_duplicate_pipelines(pipelines_settings) | ||
pipelines_settings.map do |pipeline_settings| | ||
@settings = pipeline_settings | ||
# this relies on instance variable @settings and the parent class' pipeline_configs | ||
# method. The alternative is to refactor most of the Local source methods to accept | ||
# a settings object instead of relying on @settings. | ||
super # create a PipelineConfig object based on @settings | ||
end.flatten | ||
end | ||
|
||
def match? | ||
uses_config_string = @original_settings.get_setting("config.string").set? | ||
uses_path_config = @original_settings.get_setting("path.config").set? | ||
return true if !uses_config_string && !uses_path_config | ||
if uses_path_config | ||
logger.warn("Ignoring the 'pipelines.yml' file because 'path.config' (-f) is being used.") | ||
elsif uses_config_string | ||
logger.warn("Ignoring the 'pipelines.yml' file because 'config.string' (-e) is being used.") | ||
end | ||
false | ||
end | ||
|
||
def retrieve_yaml_pipelines | ||
result = read_pipelines_from_yaml(pipelines_yaml_location) | ||
case result | ||
when Array | ||
result | ||
when false | ||
raise ConfigurationError.new("Pipelines YAML file is empty. Path: #{pipelines_yaml_location}") | ||
else | ||
raise ConfigurationError.new("Pipelines YAML file must contain an array of pipeline configs. Found \"#{result.class}\" in #{pipelines_yaml_location}") | ||
end | ||
end | ||
|
||
def read_pipelines_from_yaml(yaml_location) | ||
logger.debug("Reading pipeline configurations from YAML", :location => pipelines_yaml_location) | ||
::YAML.load(IO.read(yaml_location)) | ||
rescue => e | ||
raise ConfigurationError.new("Failed to read pipelines yaml file. Location: #{yaml_location}, Exception: #{e.inspect}") | ||
end | ||
|
||
def pipelines_yaml_location | ||
::File.join(@original_settings.get("path.settings"), "pipelines.yml") | ||
end | ||
|
||
def detect_duplicate_pipelines(pipelines) | ||
duplicate_ids = pipelines.group_by {|pipeline| pipeline.get("pipeline.id") }.select {|k, v| v.size > 1 }.map {|k, v| k} | ||
if duplicate_ids.any? | ||
raise ConfigurationError.new("Pipelines YAML file contains duplicate pipeline ids: #{duplicate_ids.inspect}. Location: #{pipelines_yaml_location}") | ||
end | ||
end | ||
end | ||
end end end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.