# fluent-plugin-geoip [![Build Status](https://travis-ci.org/y-ken/fluent-plugin-geoip.png?branch=master)](https://travis-ci.org/y-ken/fluent-plugin-geoip)
Fluentd Filter/Output plugin to add information about geographical location of IP addresses with Maxmind GeoIP databases.
fluent-plugin-geoip has bundled cost-free [GeoLite2 Free Downloadable Databases](https://dev.maxmind.com/geoip/geoip2/geolite2/) and [GeoLite City database](http://dev.maxmind.com/geoip/legacy/geolite/) by default.
Also you can use purchased [GeoIP City database](http://www.maxmind.com/en/city) ([lang:ja](http://www.maxmind.com/ja/city)) which costs starting from $50.
The accuracy details for GeoLite City (free) and GeoIP City (purchased) has described at the page below.
* http://www.maxmind.com/en/geolite_city_accuracy ([lang:ja](http://www.maxmind.com/ja/geolite_city_accuracy))
* http://www.maxmind.com/en/city_accuracy ([lang:ja](http://www.maxmind.com/ja/city_accuracy))
## Requirements
| fluent-plugin-geoip | fluentd | ruby |
|---------------------|------------|--------|
| >= 1.0.0 | >= v1.0.2 | >= 2.1 |
| < 1.0.0 | >= v0.12.0 | >= 1.9 |
If you want to use this plugin with Fluentd v0.12.x or earlier use 0.8.x.
### Compatibility notice
We've used Fluentd v1 API in this plugin since 1.0.0.
So we have dropped some features from GeoipOutput.
See also [official document](http://docs.fluentd.org/v1.0/articles/plugin-update-from-v12)
#### Fluent::Mixin::RewriteTagName
* `${tag}`, `__TAG__`
Alternative: Use `${tag}` placeholder
* `${tag_parts[n]}`, `__TAG_PARTS[n]__`
Alternative: Use `${tag[n]}` placeholder
* `${hostname}`, `__HOSTNAME__`
Alternative1: Use filter before this plugin and chunk keys:
```
@type record_transformer
hostname ${hostname}
@type geoip
tag geoip.${tag[1]}.${hostname}
city ${city["host"]}
flush_interval 1s
```
Alternative2: Just inject hostname into record you can use `` section instead:
```
@type geoip
tag geoip.${tag[1]}.${hostname}
city ${city["host"]}
hostname_key hostname
```
## Dependency
before use, install dependent library as:
```bash
# for RHEL/CentOS
$ sudo yum group install "Development Tools"
$ sudo yum install geoip-devel --enablerepo=epel
# for Ubuntu/Debian
$ sudo apt-get install build-essential
$ sudo apt-get install libgeoip-dev
# for OS X
$ brew install geoip
$ bundle config build.geoip-c --with-geoip-dir=/usr/local/include/
```
## Installation
install with `gem` or td-agent provided command as:
```bash
# for fluentd
$ gem install fluent-plugin-geoip
# for td-agent
$ sudo /usr/lib64/fluent/ruby/bin/fluent-gem install fluent-plugin-geoip
# for td-agent2
$ sudo td-agent-gem install fluent-plugin-geoip
```
## Usage
### For GeoipFilter
Note that filter version of geoip plugin does not have handling tag feature.
```xml
@type geoip
# Specify one or more geoip lookup field which has ip address (default: host)
# in the case of accessing nested value, delimit keys by dot like 'host.ip'.
geoip_lookup_key host
# Specify optional geoip database (using bundled GeoLiteCity databse by default)
# geoip_database "/path/to/your/GeoIPCity.dat"
# Specify optional geoip2 database
# geoip2_database "/path/to/your/GeoLite2-City.mmdb" (using bundled GeoLite2-City.mmdb by default)
# Specify backend library (geoip2_c, geoip, geoip2_compat)
backend_library geoip2_c
# Set adding field with placeholder (more than one settings are required.)
city ${city.names.en["host"]}
latitude ${location.latitude["host"]}
longitude ${location.longitude["host"]}
country ${country.iso_code["host"]}
country_name ${country.names.en["host"]}
postal_code ${postal.code["host"]}
# To avoid get stacktrace error with `[null, null]` array for elasticsearch.
skip_adding_null_record true
# Set @log_level (default: warn)
@log_level info
```
#### Tips: how to geolocate multiple key
```xml
@type geoip
geoip_lookup_key user1_host, user2_host
user1_city ${city.names.en["user1_host"]}
user2_city ${city.names.en["user2_host"]}
```
#### Advanced config samples
It is a sample to get friendly geo point recdords for elasticsearch with Yajl (JSON) parser.
```
@type geoip
geoip_lookup_key host
# lat lon as properties
# ex. {"lat" => 37.4192008972168, "lon" => -122.05740356445312 }
location_properties '{ "lat" : ${location.latitude["host"]}, "lon" : ${location.longitude["host"]} }'
# lat lon as string
# ex. "37.4192008972168,-122.05740356445312"
location_string ${location.latitude["host"]},${location.longitude["host"]}
# GeoJSON (lat lon as array) is useful for Kibana's bettermap.
# ex. [-122.05740356445312, 37.4192008972168]
location_array '[${location.longitude["host"]},${location.latitude["host"]}]'
# To avoid get stacktrace error with `[null, null]` array for elasticsearch.
skip_adding_null_record true
```
On the case of using td-agent3 (v1-config), it have to quote `{ ... }` or `[ ... ]` block with quotation like below.
```
@type geoip
geoip_lookup_key host
location_properties '{ "lat" : ${location.latitude["host"]}, "lon" : ${location.longitude["host"]} }'
location_string ${location.latitude["host"]},${location.longitude["host"]}
location_array '[${location.longitude["host"]},${location.latitude["host"]}]'
skip_adding_null_record true
```
### For GeoipOutput
```xml
@type geoip
# Specify one or more geoip lookup field which has ip address (default: host)
# in the case of accessing nested value, delimit keys by dot like 'host.ip'.
geoip_lookup_key host
# Specify optional geoip database (using bundled GeoLiteCity databse by default)
geoip_database "/path/to/your/GeoIPCity.dat"
# Specify optional geoip2 database
# geoip2_database "/path/to/your/GeoLite2-City.mmdb"
# Specify backend library (geoip, geoip2_compat, geoip2_c)
backend_library geoip
# Set adding field with placeholder (more than one settings are required.)
latitude ${location.latitude["host"]}
longitude ${location.longitude["host"]}
country ${country.iso_code["host"]}
country_name ${country.names.en["host"]}
postal_code ${postal.code["host"]}
region ${subdivisions.0.iso_code["host"]}
region_name ${subdivisions.0.names.en["host"]}
city ${city.names.en["host"]}
# Settings for tag
tag geoip.${tag[1]}
# To avoid get stacktrace error with `[null, null]` array for elasticsearch.
skip_adding_null_record true
# Set @log_level (default: warn)
@log_level info
# Set buffering time (default: 0s)
flush_interval 1s
```
## Tutorial
### For GeoipFilter
#### configuration
```xml
@type geoip
geoip_lookup_key host
city ${city.names.en["host"]}
lat ${location.latitude["host"]}
lon ${location.longitude["host"]}
@type stdout
```
#### result
```bash
# forward record with Google's ip address.
$ echo '{"host":"66.102.9.80","message":"test"}' | fluent-cat test.geoip
# check the result at stdout
$ tail /var/log/td-agent/td-agent.log
2016-02-01 12:04:37 +0900 test.geoip: {"host":"66.102.9.80","message":"test","city":"Mountain View","lat":37.4192008972168,"lon":-122.05740356445312}
```
You can check geoip data format using [utils/dump.rb](https://github.com/okkez/fluent-plugin-geoip/utils/dump.rb).
```
$ bundle exec ruby urils/dump.rb geoip2 66.102.3.80
$ bundle exec ruby urils/dump.rb geoip2_compat 66.102.3.80
$ bundle exec ruby urils/dump.rb geoip 66.102.3.80
```
### For GeoipOutput
#### configuration
```xml
@type copy
@type stdout
@type geoip
geoip_lookup_key host
lat ${location.latitude["host"]}
lon ${location.longitude["host"]}
country ${country.iso_code["host"]}
tag debug.${tag[1]}
@type stdout
```
#### result
```bash
# forward record with Google's ip address.
$ echo '{"host":"66.102.9.80","message":"test"}' | fluent-cat test.geoip
# check the result at stdout
$ tail /var/log/td-agent/td-agent.log
2013-08-04 16:21:32 +0900 test.geoip: {"host":"66.102.9.80","message":"test"}
2013-08-04 16:21:32 +0900 debug.geoip: {"host":"66.102.9.80","message":"test","lat":37.4192008972168,"lon":-122.05740356445312,"country":"US"}
```
You can check geoip data format using [utils/dump.rb](https://github.com/okkez/fluent-plugin-geoip/utils/dump.rb).
```
$ bundle exec ruby urils/dump.rb geoip2 66.102.3.80
$ bundle exec ruby urils/dump.rb geoip2_compat 66.102.3.80
$ bundle exec ruby urils/dump.rb geoip 66.102.3.80
```
## Placeholders
### GeoIP2
You can get any fields in the
[GeoLite2](http://dev.maxmind.com/geoip/geoip2/geolite2/) database and
[GeoIP2 Downloadable Databases](http://dev.maxmind.com/geoip/geoip2/downloadable/).
For example(geoip2_c backend):
| placeholder attributes | output example | note |
|------------------------------------------|--------------------|------|
| ${city.names.en[lookup_field]} | "Mountain View" | - |
| ${location.latitude[lookup_field]} | 37.419200000000004 | - |
| ${location.longitude[lookup_field]} | -122.0574 | - |
| ${country.iso_code[lookup_field]} | "US" | - |
| ${country.names.en[lookup_field]} | "United States" | - |
| ${postal.code[lookup_field]} | "94043" | - |
| ${subdivisions.0.iso_code[lookup_field]} | "CA" | - |
| ${subdivisions.0.names.en[lookup_field]} | "California" | - |
For example(geoip2_compat backend):
| placeholder attributes | output example | note |
|-------------------------------|--------------------|------|
| ${city[lookup_field]} | "Mountain View" | - |
| ${latitude[lookup_field]} | 37.419200000000004 | - |
| ${longitude[lookup_field]} | -122.0574 | - |
| ${country_code[lookup_field]} | "US" | - |
| ${country_name[lookup_field]} | "United States" | - |
| ${postal_code[lookup_field]} | "94043" | |
| ${region[lookup_field]} | "CA" | - |
| ${region_name[lookup_field]} | "California" | - |
**NOTE**: geoip2_compat backend supports only above fields.
Related configurations:
* `backend_library`: `geoip2_compat` or `geoip2_c`
* `geoip2_database`: path to your GeoLite2-City.mmdb
### GeoIP legacy
Provides these placeholders for adding field of geolocate results.
For more example of geolocating, you can try these websites like [Geo IP Address View](http://www.geoipview.com/) or [View my IP information](http://www.geoiptool.com/en/).
| placeholder attributes | output example | type | note |
|--------------------------------|-------------------|--------------|------|
| ${city[lookup_field]} | "Ithaca" | varchar(255) | - |
| ${latitude[lookup_field]} | 42.4277992248535 | decimal | - |
| ${longitude[lookup_field]} | -76.4981994628906 | decimal | - |
| ${country_code3[lookup_field]} | "USA" | varchar(3) | - |
| ${country_code[lookup_field]} | "US" | varchar(2) | A two-character ISO 3166-1 country code |
| ${country_name[lookup_field]} | "United States" | varchar(50) | - |
| ${dma_code[lookup_field]} | 555 | unsigned int | **only for US** |
| ${area_code[lookup_field]} | 607 | char(3) | **only for US** |
| ${region[lookup_field]} | "NY" | char(2) | A two character ISO-3166-2 or FIPS 10-4 code |
Further more specification available at http://dev.maxmind.com/geoip/legacy/csv/#GeoIP_City_Edition_CSV_Database_Fields
Related configurations:
* `backend_library`: `geoip` (default)
* `geoip_database`: path to your GeoLiteCity.dat
## Parameters
### GeoipFilter
Note that filter version of `geoip` plugin does not have handling `tag` feature.
#### Plugin helpers
* [compat_parameters](https://docs.fluentd.org/v1.0/articles/api-plugin-helper-compat_parameters)
* [inject](https://docs.fluentd.org/v1.0/articles/api-plugin-helper-inject)
See also [Filter Plugin Overview](https://docs.fluentd.org/v1.0/articles/filter-plugin-overview)
#### Supported sections
* [Inject section configurations](https://docs.fluentd.org/v1.0/articles/inject-section)
#### Parameters
[Plugin Common Paramteters](https://docs.fluentd.org/v1.0/articles/plugin-common-parameters)
**geoip_database** (string) (optional)
* Default value: bundled database `GeoLiteCity.dat`
Path to GeoIP database file.
**geoip2_database** (string) (optional)
* Default value: bundled database `GeoLite2-City.mmdb`.
Path to GeoIP2 database file.
**geoip_lookup_key** (string) (optional)
* Default value: `host`.
Specify one or more geoip lookup field which has IP address.
**skip_adding_null_record** (bool) (optional)
* Default value: `nil`
Skip adding geoip fields when this valaues to `true`.
On the case of getting nothing of GeoIP info (such as local IP), it will output the original record without changing anything.
**backend_library** (enum) (optional)
* Available values: `geoip`, `geoip2_compat`, `geoip2_c`
* Default value: `geoip2_c`.
Set backend library.
### GeoipOutput
#### Plugin helpers
* [event_emitter](https://docs.fluentd.org/v1.0/articles/api-plugin-helper-event_emitter)
* [compat_parameters](https://docs.fluentd.org/v1.0/articles/api-plugin-helper-compat_parameters)
* [inject](https://docs.fluentd.org/v1.0/articles/api-plugin-helper-inject)
See also [Output Plugin Overview](https://docs.fluentd.org/v1.0/articles/output-plugin-overview)
#### Sections
* [Inject section configurations](https://docs.fluentd.org/v1.0/articles/inject-section)
* [Buffer section configurations](https://docs.fluentd.org/v1.0/articles/buffer-section)
#### Parameters
[Plugin Common Paramteters](https://docs.fluentd.org/v1.0/articles/plugin-common-parameters)
**geoip_database** (string) (optional)
* Default value: bundled database `GeoLiteCity.dat`
Path to GeoIP database file.
**geoip2_database** (string) (optional)
* Default value: bundled database `GeoLite2-City.mmdb`.
Path to GeoIP2 database file.
**geoip_lookup_key** (string) (optional)
* Default value: `host`.
Specify one or more geoip lookup field which has IP address.
**skip_adding_null_record** (bool) (optional)
* Default value: `nil`
Skip adding geoip fields when this valaues to `true`.
On the case of getting nothing of GeoIP info (such as local IP), it will output the original record without changing anything.
**backend_library** (enum) (optional)
* Available values: `geoip`, `geoip2_compat`, `geoip2_c`
* Default value: `geoip2_c`.
Set backend library.
**tag** (string) (optional)
On using this option with tag placeholder like `tag geoip.${tag}` (test code is available at [test_out_geoip.rb](https://github.com/y-ken/fluent-plugin-geoip/blob/master/test/plugin/test_out_geoip.rb)).
## Articles
* [IPアドレスを元に位置情報をリアルタイムに付与する fluent-plugin-geoip v0.0.1をリリースしました #fluentd - Y-Ken Studio](http://y-ken.hatenablog.com/entry/fluent-plugin-geoip-has-released)
http://y-ken.hatenablog.com/entry/fluent-plugin-geoip-has-released
* [初の安定版 fluent-plugin-geoip v0.0.3 をリリースしました #fluentd- Y-Ken Studio](http://y-ken.hatenablog.com/entry/fluent-plugin-geoip-v0.0.3)
http://y-ken.hatenablog.com/entry/fluent-plugin-geoip-v0.0.3
* [fluent-plugin-geoip v0.0.4 をリリースしました。ElasticSearch+Kibanaの世界地図に位置情報をプロットするために必要なFluentdの設定サンプルも紹介します- Y-Ken Studio](http://y-ken.hatenablog.com/entry/fluent-plugin-geoip-v0.0.4)
http://y-ken.hatenablog.com/entry/fluent-plugin-geoip-v0.0.4
* [Released GeoIP plugin to work together with ElasticSearch + Kibana v3](https://groups.google.com/d/topic/fluentd/OVIcH_SKBwM/discussion)
https://groups.google.com/d/topic/fluentd/OVIcH_SKBwM/discussion
* [Fluentd、Amazon RedshiftとTableauを用いたカジュアルなデータ可視化 | SmartNews開発者ブログ](http://developer.smartnews.be/blog/2013/10/03/easy-data-analysis-using-fluentd-redshift-and-tableau/)
http://developer.smartnews.be/blog/2013/10/03/easy-data-analysis-using-fluentd-redshift-and-tableau/
## TODO
Pull requests are very welcome!!
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
## Copyright
Copyright (c) 2013- Kentaro Yoshida ([@yoshi_ken](https://twitter.com/yoshi_ken))
## License
Apache License, Version 2.0
This product includes GeoLite data created by MaxMind, available from
http://www.maxmind.com.