From a7b759680c4373963fb6530d572260aba1f5db5f Mon Sep 17 00:00:00 2001 From: Jordan Sissel Date: Tue, 3 Jan 2017 14:29:02 -0800 Subject: [PATCH 1/2] New `write_behavior` setting. This setting introduces a new behavior to allow each event to overwrite the entire file. The default behavior (append) is unchanged. Fixes #24 --- lib/logstash/outputs/file.rb | 20 +++++++++++++++- logstash-output-file.gemspec | 1 + spec/outputs/file_spec.rb | 44 ++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/lib/logstash/outputs/file.rb b/lib/logstash/outputs/file.rb index 86c3000..f2100db 100644 --- a/lib/logstash/outputs/file.rb +++ b/lib/logstash/outputs/file.rb @@ -1,6 +1,7 @@ # encoding: utf-8 require "logstash/namespace" require "logstash/outputs/base" +require "flores/random" require "logstash/errors" require "zlib" @@ -66,6 +67,16 @@ class LogStash::Outputs::File < LogStash::Outputs::Base # Example: `"file_mode" => 0640` config :file_mode, :validate => :number, :default => -1 + + # How should the file be written? + # + # If `append`, the file will be opened for appending and each new event will + # be written at the end of the file. + # + # If `overwrite`, the file will be truncated before writing and only the most + # recent event will appear in the file. + config :write_behavior, :validate => [ "overwrite", "append" ], :default => "append" + default :codec, "json_lines" public @@ -130,7 +141,14 @@ def multi_receive_encoded(events_and_encoded) @io_mutex.synchronize do encoded_by_path.each do |path,chunks| fd = open(path) - chunks.each {|chunk| fd.write(chunk) } + if @write_behavior == "overwrite" + fd.truncate(0) + fd.seek(0, IO::SEEK_SET) + fd.write(chunks.last) + else + # append to the file + chunks.each {|chunk| fd.write(chunk) } + end fd.flush end diff --git a/logstash-output-file.gemspec b/logstash-output-file.gemspec index 76fee9a..c4f385a 100644 --- a/logstash-output-file.gemspec +++ b/logstash-output-file.gemspec @@ -25,5 +25,6 @@ Gem::Specification.new do |s| s.add_runtime_dependency 'logstash-codec-line' s.add_development_dependency 'logstash-devutils' + s.add_development_dependency 'flores' s.add_development_dependency 'logstash-input-generator' end diff --git a/spec/outputs/file_spec.rb b/spec/outputs/file_spec.rb index eee9739..a4ab6fc 100644 --- a/spec/outputs/file_spec.rb +++ b/spec/outputs/file_spec.rb @@ -2,6 +2,7 @@ require "logstash/devutils/rspec/spec_helper" require "logstash/outputs/file" require "logstash/codecs/line" +require "logstash/codecs/json_lines" require "logstash/event" require "logstash/json" require "stud/temporary" @@ -111,6 +112,49 @@ describe "receiving events" do + context "when write_behavior => 'overwrite'" do + let(:tmp) { Stud::Temporary.pathname } + let(:config) { + { + "write_behavior" => "overwrite", + "path" => tmp, + "codec" => LogStash::Codecs::JSONLines.new + } + } + let(:output) { LogStash::Outputs::File.new(config) } + + let(:count) { Flores::Random.integer(1..10) } + let(:events) do + Flores::Random.iterations(1..10).collect do |i| + LogStash::Event.new("value" => i) + end + end + + before do + output.register + end + + after do + File.unlink(tmp) if File.exist?(tmp) + end + + it "should write only the last event of a batch" do + output.multi_receive(events) + result = LogStash::Json.load(File.read(tmp)) + expect(result["value"]).to be == events.last.get("value") + end + + context "the file" do + it "should only contain the last event received" do + events.each do |event| + output.multi_receive([event]) + result = LogStash::Json.load(File.read(tmp)) + expect(result["value"]).to be == event.get("value") + end + end + end + end + context "when the output file is deleted" do let(:temp_file) { Tempfile.new('logstash-spec-output-file_deleted') } From 7b7eb7b38086127fe967738e92fa0b4e81dcb3eb Mon Sep 17 00:00:00 2001 From: Jordan Sissel Date: Tue, 3 Jan 2017 16:00:50 -0800 Subject: [PATCH 2/2] Version bump --- CHANGELOG.md | 5 +++++ logstash-output-file.gemspec | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90c8f7a..2fdb7bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 4.1.0 + - New `write_behavior` feature. Value can be "append" (default) or + "overwrite". If "append", events will be appended to the end of the file. + If "overwrite", the file will only contain the last event written. + ## 4.0.1 - Move one log message from info to debug to avoid noise diff --git a/logstash-output-file.gemspec b/logstash-output-file.gemspec index c4f385a..2e9065b 100644 --- a/logstash-output-file.gemspec +++ b/logstash-output-file.gemspec @@ -1,7 +1,7 @@ Gem::Specification.new do |s| s.name = 'logstash-output-file' - s.version = '4.0.1' + s.version = '4.1.0' s.licenses = ['Apache License (2.0)'] s.summary = "This output will write events to files on disk" s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"