GitHub PullRequestReviewCommentEvent at 2014-12-18 19:42:13
Repository: logstash
Actor: untergeek
Payload: {"action":"created","comment":{"url":"https://api.github.com/repos/elasticsearch/logstash/pulls/comments/22065915","id":22065915,"diff_hunk":"@@ -0,0 +1,387 @@\n+== Adding a filter to Logstash\n+\n+This HOWTO will walk you through the process of developing a new filter plugin for Logstash. The workflow has changed as of version 1.5 of Logstash, so you'll want to follow these new and improved steps to contribute a new plugin!\n+\n+For this example, we are going to create a new filter which will replace the 'message' field in the event with the string \"Hello world!\" (or any other string of your choosing - just specify in the Logstash \"new_message\" configuration).\n+\n+=== Create a new GitHub repo\n+As of version 1.5 of Logstash, the code for each plugin lives in its own GitHub repository. So first, you'll need to create a new repo as a home for your nascent filter. When logged into GitHub, click on the \"Repositories\" tab. You may see a list of repositories you've forked and/or contributed to, or it may be blank. Either way, you're fine! Now click on the green \"New\" button near the top right of the page.\n+\n+Choose the following settings on your new repo:\n+\n+* Repository name should be similar to \"logstash-filter-myfilter\"\n+* Public or Private - up to you (but will need to be Public to submit as an official plugin)\n+* Click the box \"Initialize this repository with a README\"\n+\n+You can pick a default .gitignore, or leave it as \"None\". Eventually, you'll want to add one which looks something like this:\n+\n+[source,sh]\n+----------------------------------\n+*.gem\n+Gemfile.lock\n+.bundle\n+vendor\n+----------------------------------\n+\n+=== write the filter code\n+First, you'll need to clone the new repo you just created. Use a command something like this:\n+\n+[source,sh]\n+----------------------------------\n+git clone git@github.com:myuser/logstash-filter-helloworld.git\n+----------------------------------\n+\n+Now let's write the code for the 'hello world' filter. First, we'll need to make the directory structure for the Ruby file to live in:\n+\n+[source,sh]\n+----------------------------------\n+mkdir -p lib/logstash/filters\n+----------------------------------\n+\n+Then, add the following ruby code to a file named 'helloworld.rb' in the directory you just created, e.g. `lib/logstash/filters/helloworld.rb`:\n+\n+[source,js]\n+----------------------------------\n+# encoding: utf-8\n+# Call this file 'helloworld.rb'\n+require \"logstash/filters/base\"\n+require \"logstash/namespace\"\n+\n+class LogStash::Filters::Helloworld < LogStash::Filters::Base\n+\n+  # Setting the config_name here is required. This is how you\n+  # configure this filter from your Logstash config.\n+  #\n+  # filter {\n+  #   helloworld { new_message => \"Hello World\" }\n+  # }\n+  config_name \"helloworld\"\n+\n+  # New plugins should start life at milestone 1.\n+  milestone 1\n+\n+  # Replace the message with this value.\n+  config :new_message, :validate => :string\n+\n+  public\n+  def register\n+    # nothing to do\n+  end # def register\n+\n+  public\n+  def filter(event)\n+    if @new_message\n+      # Replace the event message with our message as configured in the\n+      # config file.\n+      event[\"message\"] = @new_message\n+    end\n+\n+    # filter_matched should go in the last line of our successful code\n+    filter_matched(event)\n+  end # def filter\n+end # class LogStash::Filters::Helloworld\n+----------------------------------\n+\n+\n+=== Anatomy of a filter plugin\n+\n+Now let's take a line-by-line look at this new example plugin. Clicking the links will take you to highlighted parts of the code.\n+\n+==== Encoding\n+\n+It seems like a small thing, but please don’t omit adding\n+\n+[source,sh]\n+----------------------------------\n+# encoding: utf-8\n+----------------------------------\n+\n+to the top of your input plugin. Logstash depends on things being in UTF-8, so we put this here to tell the Ruby interpreter that we’re going to be using the UTF-8 encoding.\n+\n+==== Require\n+\n+A Logstash filter plugin requires some parent classes that can be referenced through the indicated statements. The following require statements are mandatory:\n+\n+[source,ruby]\n+----------------------------------\n+require \"logstash/filters/base\"\n+require \"logstash/namespace\"\n+----------------------------------\n+\n+Of course, the plugin you build may depend on other code, or even gems. Just put them here along with these Logstash dependencies.\n+\n+=== Plugin Body\n+\n+Let's go through the various elements of the plugin itself.\n+\n+==== class declaration\n+[source,ruby]\n+----------------------------------\n+class LogStash::Filters::Helloworld < LogStash::Filters::Base\n+----------------------------------\n+\n+The class name will need to be a sub-class of `LogStash::Filters::Base`, and it should extend it as shown in the line above. You should name your class in a way that closely mirrors the plugin name, e.g. `LogStash::Filters::Helloworld` in this case.\n+\n+==== config name\n+[source,ruby]\n+----------------------------------\n+  config_name \"helloworld\"\n+----------------------------------\n+This is the name your input plugin will call inside the input block.\n+\n+For this example, if we set config_name \"helloworld\", the corresponding Logstash configuration block would look like this:\n+ \n+[source,js]\n+----------------------------------\n+input {\n+  helloworld {...}\n+}\n+----------------------------------\n+\n+==== milestone\n+[source,ruby]\n+----------------------------------\n+  milestone 1\n+----------------------------------\n+Milestones are defined in https://github.com/elasticsearch/logstash/blob/master/docs/plugin-milestones.md[Logstash milestones]. Basically,\n+\n+* Milestone 1: it’s new and under development and may change\n+* Milestone 2: more stable, more backwards-compatible, more-widely used\n+* Milestone 3: even more backward compatible & this is likely enforced by automated tests.\n+* Milestone 0: Infrequently used, means that the plugin is under-supported.\n+\n+Since we're writing a brand-new plugin, it should initially be set to `milestone 1`.\n+\n+==== configuration parameters\n+[source,ruby]\n+----------------------------------\n+  config :new_message, :validate => :string\n+----------------------------------\n+This section will allow us to define as many (or as few) parameters as we need to communicate to Logstash how it should process the events. In this example, we'll just set one configuration, `new_message`, which allows the user to describe the string which will replace the original message provided to Logstash. As you can see, it is also possible to specify a data type for validation (in this case, we ensure that the parameter arrives in Logstash as a string).\n+\n+There are several configuration attributes:\n+\n+* `:validate` - allows developers to enforce a particular data type is passed to Logstash for this configuration option\n+* `:default` - lets you specify a default value for a parameter\n+* `:required` - whether or not this parameter is mandatory (a Boolean true or false)\n+* `:deprecated` - informational (also a Boolean)\n+\n+=== plugin methods\n+Logstash filters contain two main methods: `register` and `filter`.\n+\n+==== register method\n+The Logstash `register` method is like an `initialize` method. It was originally created to enforce having `super` called, preventing headaches for newbies. (Note: It may go away in favor of `initialize`, in conjunction with some enforced testing to ensure `super` is called.)\n+\n+`public` means the method can be called anywhere, not just within the class. This is the default behavior for methods in Ruby, but it is called explicitly here anyway.\n+\n+You may also assign instance variables here. Configuration variables are now in scope as instance variables, e.g. `@new_message`\n+\n+==== filter method\n+The plugin's `filter` method is where the actual filtering work takes place! Inside the `filter` method you can refer to the event data using the `event` hash. Configuration variables are now in scope as instance variables, e.g. `@new_message`\n+\n+For example, to modify the `message` field directly in the event, we can use this code:\n+\n+[source,ruby]\n+----------------------------------\n+  event[\"message\"] = @new_message\n+----------------------------------\n+After this line of code is executed, the original message in the event will be replaced by whatever was specified in the `new_message` configuration when Logstash was run.\n+\n+[source,ruby]\n+----------------------------------\n+  filter_matched(event)\n+----------------------------------\n+Calling the `filter_matched` method upon succesful execution of the plugin will ensure that any fields or tags added through the Logstash configuration for this filter will be handled correctly. For example, any `add_field`, `remove_field`, `add_tag` and/or `remove_tag` actions will be performed at this time.\n+\n+Event methods such as `event.cancel` are now available to control the workflow of the event being processed.\n+\n+=== add a Gemfile\n+Gemfiles allow Ruby's Bundler to maintain the dependencies for your plugin. Currently, all we'll need is the Logstash gem, for testing, but if you require other gems, you should add them in here. See http://bundler.io/gemfile.html[Bundler's Gemfile page] for more details.\n+\n+[source,ruby]\n+----------------------------------\n+source 'https://rubygems.org'\n+gemspec\n+gem \"logstash\", :github => \"elasticsearch/logstash\", :branch => \"1.5\"\n+----------------------------------\n+\n+=== add a gemspec file\n+Gemspecs define the Ruby gem which will be built and contain your plugin. More information can be found on the http://guides.rubygems.org/specification-reference/[Rubygems Specification page].\n+\n+[source,ruby]\n+----------------------------------\n+Gem::Specification.new do |s|\n+  s.name = 'logstash-filter-helloworld'\n+  s.version = '0.1.1'\n+  s.licenses = ['Apache License (2.0)']\n+  s.summary = \"This filter generates a hello world message in Logstash\"\n+  s.description = \"This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program\"\n+  s.authors = [\"Elasticsearch\"]\n+  s.email = 'info@elasticsearch.com'\n+  s.homepage = \"http://www.elasticsearch.org/guide/en/logstash/current/index.html\"\n+  s.require_paths = [\"lib\"]\n+\n+  # Files\n+  s.files = `git ls-files`.split($\\)\n+   # Tests\n+  s.test_files = s.files.grep(%r{^(test|spec|features)/})\n+\n+  # Special flag to let us know this is actually a logstash plugin\n+  s.metadata = { \"logstash_plugin\" => \"true\", \"logstash_group\" => \"filter\" }\n+\n+  # Gem dependencies\n+  s.add_runtime_dependency 'logstash', '>= 1.4.0', '< 2.0.0'\n+  s.add_development_dependency 'logstash-devutils'\n+end\n+----------------------------------\n+\n+=== add some specs\n+Logstash loves tests. Lots of tests. If you're using this new filter in any sort of production environment, you'll want to have some tests to ensure you are not breaking any existing functionality.\n+\n+So, with that in mind, let's create some Rspec tests. First, make the directory to contain the rspec file:\n+[source,ruby]\n+----------------------------------\n+mkdir -p spec/filters\n+----------------------------------\n+\n+Then, create a file in this directory, e.g. `spec/filters/helloworld_spec.rb`. The contents should be something like this:\n+\n+[source,ruby]\n+----------------------------------\n+require \"logstash/devutils/rspec/spec_helper\"\n+require \"logstash/filters/helloworld\"\n+\n+describe LogStash::Filters::Helloworld do\n+  describe \"Set to Hello World\" do\n+    config <<-CONFIG\n+      filter {\n+        helloworld {\n+          new_message => \"Hello World\"\n+        }\n+      }\n+    CONFIG\n+\n+    sample(\"message\" => \"some text\") do\n+      insist { subject }.include?(\"message\")\n+      insist { subject[\"message\"] } == \"Hello World\"\n+    end\n+  end\n+end\n+----------------------------------\n+If you read through the above file, you can see it does several things:\n+\n+* Require the rspec/spec_helper class, which runs rspec tests\n+* Require the actual filter we're testing\n+* Describe a test scenario for the filter\n+** Give the test a description (\"Set to Hello World\")\n+** Define the Logstash configuration to use when running this test\n+** Provide some sample data. In this case, set the \"message\" field to \"some text\"\n+** Check (insist) that the \"message\" field exists after the test runs\n+** Insist that the \"message\" field has successfully been set to \"Hello World\"\n+\n+=== Clone and test!\n+Now let's start with a fresh clone of the plugin, build it and run the tests.\n+\n+[source,sh]\n+----------------------------------\n+git clone git@github.com:gitusername/logstash-filter-helloworld.git\n+cd logstash-filter-helloworld\n+----------------------------------\n+\n+Then, you'll need to install the bundle:\n+[source,sh]\n+----------------------------------\n+bundle install\n+----------------------------------","path":"docs/asciidoc/static/dev-logstash-filter-plugin.asciidoc","position":295,"original_position":295,"commit_id":"b738ad87d94bb564f90cefc7bc4a1b11910f8e4e","original_commit_id":"cb2fff9fb46966c50da5e9027da7491c8a922fa8","user":{"login":"untergeek","id":1020383,"avatar_url":"https://avatars.githubusercontent.com/u/1020383?v=3","gravatar_id":"","url":"https://api.github.com/users/untergeek","html_url":"https://github.com/untergeek","followers_url":"https://api.github.com/users/untergeek/followers","following_url":"https://api.github.com/users/untergeek/following{/other_user}","gists_url":"https://api.github.com/users/untergeek/gists{/gist_id}","starred_url":"https://api.github.com/users/untergeek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/untergeek/subscriptions","organizations_url":"https://api.github.com/users/untergeek/orgs","repos_url":"https://api.github.com/users/untergeek/repos","events_url":"https://api.github.com/users/untergeek/events{/privacy}","received_events_url":"https://api.github.com/users/untergeek/received_events","type":"User","site_admin":false},"body":":+1: to @ph's suggestion.","created_at":"2014-12-18T19:42:13Z","updated_at":"2014-12-18T19:42:13Z","html_url":"https://github.com/elasticsearch/logstash/pull/2259#discussion_r22065915","pull_request_url":"https://api.github.com/repos/elasticsearch/logstash/pulls/2259","_links":{"self":{"href":"https://api.github.com/repos/elasticsearch/logstash/pulls/comments/22065915"},"html":{"href":"https://github.com/elasticsearch/logstash/pull/2259#discussion_r22065915"},"pull_request":{"href":"https://api.github.com/repos/elasticsearch/logstash/pulls/2259"}}},"pull_request":{"url":"https://api.github.com/repos/elasticsearch/logstash/pulls/2259","id":26252539,"html_url":"https://github.com/elasticsearch/logstash/pull/2259","diff_url":"https://github.com/elasticsearch/logstash/pull/2259.diff","patch_url":"https://github.com/elasticsearch/logstash/pull/2259.patch","issue_url":"https://api.github.com/repos/elasticsearch/logstash/issues/2259","number":2259,"state":"open","locked":false,"title":"Filter development HOWTO","user":{"login":"kurtado","id":1161427,"avatar_url":"https://avatars.githubusercontent.com/u/1161427?v=3","gravatar_id":"","url":"https://api.github.com/users/kurtado","html_url":"https://github.com/kurtado","followers_url":"https://api.github.com/users/kurtado/followers","following_url":"https://api.github.com/users/kurtado/following{/other_user}","gists_url":"https://api.github.com/users/kurtado/gists{/gist_id}","starred_url":"https://api.github.com/users/kurtado/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kurtado/subscriptions","organizations_url":"https://api.github.com/users/kurtado/orgs","repos_url":"https://api.github.com/users/kurtado/repos","events_url":"https://api.github.com/users/kurtado/events{/privacy}","received_events_url":"https://api.github.com/users/kurtado/received_events","type":"User","site_admin":false},"body":"Step-by-step guide for developers to write and deploy filters.\r\n","created_at":"2014-12-17T20:09:27Z","updated_at":"2014-12-18T19:42:13Z","closed_at":null,"merged_at":null,"merge_commit_sha":"bfca87d08a774abe41eb57edabf10ed1c128fda4","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/elasticsearch/logstash/pulls/2259/commits","review_comments_url":"https://api.github.com/repos/elasticsearch/logstash/pulls/2259/comments","review_comment_url":"https://api.github.com/repos/elasticsearch/logstash/pulls/comments/{number}","comments_url":"https://api.github.com/repos/elasticsearch/logstash/issues/2259/comments","statuses_url":"https://api.github.com/repos/elasticsearch/logstash/statuses/b738ad87d94bb564f90cefc7bc4a1b11910f8e4e","head":{"label":"kurtado:doc/asciidoc/dev-filter","ref":"doc/asciidoc/dev-filter","sha":"b738ad87d94bb564f90cefc7bc4a1b11910f8e4e","user":{"login":"kurtado","id":1161427,"avatar_url":"https://avatars.githubusercontent.com/u/1161427?v=3","gravatar_id":"","url":"https://api.github.com/users/kurtado","html_url":"https://github.com/kurtado","followers_url":"https://api.github.com/users/kurtado/followers","following_url":"https://api.github.com/users/kurtado/following{/other_user}","gists_url":"https://api.github.com/users/kurtado/gists{/gist_id}","starred_url":"https://api.github.com/users/kurtado/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kurtado/subscriptions","organizations_url":"https://api.github.com/users/kurtado/orgs","repos_url":"https://api.github.com/users/kurtado/repos","events_url":"https://api.github.com/users/kurtado/events{/privacy}","received_events_url":"https://api.github.com/users/kurtado/received_events","type":"User","site_admin":false},"repo":{"id":14541131,"name":"logstash","full_name":"kurtado/logstash","owner":{"login":"kurtado","id":1161427,"avatar_url":"https://avatars.githubusercontent.com/u/1161427?v=3","gravatar_id":"","url":"https://api.github.com/users/kurtado","html_url":"https://github.com/kurtado","followers_url":"https://api.github.com/users/kurtado/followers","following_url":"https://api.github.com/users/kurtado/following{/other_user}","gists_url":"https://api.github.com/users/kurtado/gists{/gist_id}","starred_url":"https://api.github.com/users/kurtado/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kurtado/subscriptions","organizations_url":"https://api.github.com/users/kurtado/orgs","repos_url":"https://api.github.com/users/kurtado/repos","events_url":"https://api.github.com/users/kurtado/events{/privacy}","received_events_url":"https://api.github.com/users/kurtado/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/kurtado/logstash","description":"logstash - logs/event transport, processing, management, search.","fork":true,"url":"https://api.github.com/repos/kurtado/logstash","forks_url":"https://api.github.com/repos/kurtado/logstash/forks","keys_url":"https://api.github.com/repos/kurtado/logstash/keys{/key_id}","collaborators_url":"https://api.github.com/repos/kurtado/logstash/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/kurtado/logstash/teams","hooks_url":"https://api.github.com/repos/kurtado/logstash/hooks","issue_events_url":"https://api.github.com/repos/kurtado/logstash/issues/events{/number}","events_url":"https://api.github.com/repos/kurtado/logstash/events","assignees_url":"https://api.github.com/repos/kurtado/logstash/assignees{/user}","branches_url":"https://api.github.com/repos/kurtado/logstash/branches{/branch}","tags_url":"https://api.github.com/repos/kurtado/logstash/tags","blobs_url":"https://api.github.com/repos/kurtado/logstash/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/kurtado/logstash/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/kurtado/logstash/git/refs{/sha}","trees_url":"https://api.github.com/repos/kurtado/logstash/git/trees{/sha}","statuses_url":"https://api.github.com/repos/kurtado/logstash/statuses/{sha}","languages_url":"https://api.github.com/repos/kurtado/logstash/languages","stargazers_url":"https://api.github.com/repos/kurtado/logstash/stargazers","contributors_url":"https://api.github.com/repos/kurtado/logstash/contributors","subscribers_url":"https://api.github.com/repos/kurtado/logstash/subscribers","subscription_url":"https://api.github.com/repos/kurtado/logstash/subscription","commits_url":"https://api.github.com/repos/kurtado/logstash/commits{/sha}","git_commits_url":"https://api.github.com/repos/kurtado/logstash/git/commits{/sha}","comments_url":"https://api.github.com/repos/kurtado/logstash/comments{/number}","issue_comment_url":"https://api.github.com/repos/kurtado/logstash/issues/comments/{number}","contents_url":"https://api.github.com/repos/kurtado/logstash/contents/{+path}","compare_url":"https://api.github.com/repos/kurtado/logstash/compare/{base}...{head}","merges_url":"https://api.github.com/repos/kurtado/logstash/merges","archive_url":"https://api.github.com/repos/kurtado/logstash/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/kurtado/logstash/downloads","issues_url":"https://api.github.com/repos/kurtado/logstash/issues{/number}","pulls_url":"https://api.github.com/repos/kurtado/logstash/pulls{/number}","milestones_url":"https://api.github.com/repos/kurtado/logstash/milestones{/number}","notifications_url":"https://api.github.com/repos/kurtado/logstash/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/kurtado/logstash/labels{/name}","releases_url":"https://api.github.com/repos/kurtado/logstash/releases{/id}","created_at":"2013-11-19T23:27:50Z","updated_at":"2014-04-29T18:39:06Z","pushed_at":"2014-12-18T19:30:46Z","git_url":"git://github.com/kurtado/logstash.git","ssh_url":"git@github.com:kurtado/logstash.git","clone_url":"https://github.com/kurtado/logstash.git","svn_url":"https://github.com/kurtado/logstash","homepage":"http://logstash.net/","size":70670,"stargazers_count":0,"watchers_count":0,"language":"Ruby","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"elasticsearch:master","ref":"master","sha":"f83652aada01acbcaa5a5c6cb23df2856483eb6d","user":{"login":"elasticsearch","id":141304,"avatar_url":"https://avatars.githubusercontent.com/u/141304?v=3","gravatar_id":"","url":"https://api.github.com/users/elasticsearch","html_url":"https://github.com/elasticsearch","followers_url":"https://api.github.com/users/elasticsearch/followers","following_url":"https://api.github.com/users/elasticsearch/following{/other_user}","gists_url":"https://api.github.com/users/elasticsearch/gists{/gist_id}","starred_url":"https://api.github.com/users/elasticsearch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/elasticsearch/subscriptions","organizations_url":"https://api.github.com/users/elasticsearch/orgs","repos_url":"https://api.github.com/users/elasticsearch/repos","events_url":"https://api.github.com/users/elasticsearch/events{/privacy}","received_events_url":"https://api.github.com/users/elasticsearch/received_events","type":"Organization","site_admin":false},"repo":{"id":1090311,"name":"logstash","full_name":"elasticsearch/logstash","owner":{"login":"elasticsearch","id":141304,"avatar_url":"https://avatars.githubusercontent.com/u/141304?v=3","gravatar_id":"","url":"https://api.github.com/users/elasticsearch","html_url":"https://github.com/elasticsearch","followers_url":"https://api.github.com/users/elasticsearch/followers","following_url":"https://api.github.com/users/elasticsearch/following{/other_user}","gists_url":"https://api.github.com/users/elasticsearch/gists{/gist_id}","starred_url":"https://api.github.com/users/elasticsearch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/elasticsearch/subscriptions","organizations_url":"https://api.github.com/users/elasticsearch/orgs","repos_url":"https://api.github.com/users/elasticsearch/repos","events_url":"https://api.github.com/users/elasticsearch/events{/privacy}","received_events_url":"https://api.github.com/users/elasticsearch/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/elasticsearch/logstash","description":"logstash - logs/event transport, processing, management, search.","fork":false,"url":"https://api.github.com/repos/elasticsearch/logstash","forks_url":"https://api.github.com/repos/elasticsearch/logstash/forks","keys_url":"https://api.github.com/repos/elasticsearch/logstash/keys{/key_id}","collaborators_url":"https://api.github.com/repos/elasticsearch/logstash/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/elasticsearch/logstash/teams","hooks_url":"https://api.github.com/repos/elasticsearch/logstash/hooks","issue_events_url":"https://api.github.com/repos/elasticsearch/logstash/issues/events{/number}","events_url":"https://api.github.com/repos/elasticsearch/logstash/events","assignees_url":"https://api.github.com/repos/elasticsearch/logstash/assignees{/user}","branches_url":"https://api.github.com/repos/elasticsearch/logstash/branches{/branch}","tags_url":"https://api.github.com/repos/elasticsearch/logstash/tags","blobs_url":"https://api.github.com/repos/elasticsearch/logstash/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/elasticsearch/logstash/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/elasticsearch/logstash/git/refs{/sha}","trees_url":"https://api.github.com/repos/elasticsearch/logstash/git/trees{/sha}","statuses_url":"https://api.github.com/repos/elasticsearch/logstash/statuses/{sha}","languages_url":"https://api.github.com/repos/elasticsearch/logstash/languages","stargazers_url":"https://api.github.com/repos/elasticsearch/logstash/stargazers","contributors_url":"https://api.github.com/repos/elasticsearch/logstash/contributors","subscribers_url":"https://api.github.com/repos/elasticsearch/logstash/subscribers","subscription_url":"https://api.github.com/repos/elasticsearch/logstash/subscription","commits_url":"https://api.github.com/repos/elasticsearch/logstash/commits{/sha}","git_commits_url":"https://api.github.com/repos/elasticsearch/logstash/git/commits{/sha}","comments_url":"https://api.github.com/repos/elasticsearch/logstash/comments{/number}","issue_comment_url":"https://api.github.com/repos/elasticsearch/logstash/issues/comments/{number}","contents_url":"https://api.github.com/repos/elasticsearch/logstash/contents/{+path}","compare_url":"https://api.github.com/repos/elasticsearch/logstash/compare/{base}...{head}","merges_url":"https://api.github.com/repos/elasticsearch/logstash/merges","archive_url":"https://api.github.com/repos/elasticsearch/logstash/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/elasticsearch/logstash/downloads","issues_url":"https://api.github.com/repos/elasticsearch/logstash/issues{/number}","pulls_url":"https://api.github.com/repos/elasticsearch/logstash/pulls{/number}","milestones_url":"https://api.github.com/repos/elasticsearch/logstash/milestones{/number}","notifications_url":"https://api.github.com/repos/elasticsearch/logstash/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/elasticsearch/logstash/labels{/name}","releases_url":"https://api.github.com/repos/elasticsearch/logstash/releases{/id}","created_at":"2010-11-18T01:31:50Z","updated_at":"2014-12-18T17:42:12Z","pushed_at":"2014-12-18T01:56:41Z","git_url":"git://github.com/elasticsearch/logstash.git","ssh_url":"git@github.com:elasticsearch/logstash.git","clone_url":"https://github.com/elasticsearch/logstash.git","svn_url":"https://github.com/elasticsearch/logstash","homepage":"http://logstash.net/","size":87342,"stargazers_count":3397,"watchers_count":3397,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1287,"mirror_url":null,"open_issues_count":578,"forks":1287,"open_issues":578,"watchers":3397,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/elasticsearch/logstash/pulls/2259"},"html":{"href":"https://github.com/elasticsearch/logstash/pull/2259"},"issue":{"href":"https://api.github.com/repos/elasticsearch/logstash/issues/2259"},"comments":{"href":"https://api.github.com/repos/elasticsearch/logstash/issues/2259/comments"},"review_comments":{"href":"https://api.github.com/repos/elasticsearch/logstash/pulls/2259/comments"},"review_comment":{"href":"https://api.github.com/repos/elasticsearch/logstash/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/elasticsearch/logstash/pulls/2259/commits"},"statuses":{"href":"https://api.github.com/repos/elasticsearch/logstash/statuses/b738ad87d94bb564f90cefc7bc4a1b11910f8e4e"}}}}