├── .gitignore ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin └── zabbix_graph ├── lib ├── zabbix_graph.rb └── zabbix_graph │ └── version.rb └── zabbix_graph.gemspec /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | *.bundle 11 | *.so 12 | *.o 13 | *.a 14 | mkmf.log 15 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in zabbix_graph.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Ryota Arai 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ZabbixGraph [![Gem Version](https://badge.fury.io/rb/zabbix_graph.svg)](http://badge.fury.io/rb/zabbix_graph) 2 | 3 | Select hosts and items with peco, and open adhoc graph. 4 | 5 | ## Installation 6 | 7 | $ gem install zabbix_graph 8 | 9 | ## Usage 10 | 11 | ``` 12 | $ export ZABBIX_URL=https://your-zabbix.example.com 13 | $ export ZABBIX_USER=... 14 | $ export ZABBIX_PASSWORD=... 15 | $ zabbix_graph 16 | ``` 17 | 18 | ### --item-graph and --host-graph 19 | 20 | You can view graphs per item or host. 21 | 22 | ``` 23 | $ zabbix_graph --item-graph 24 | $ zabbix_graph --host-graph 25 | $ zabbix_graph --item-graph --period=1d1h1m1s 26 | $ zabbix_graph --host-graph --period=1d1h1m1s 27 | ``` 28 | 29 | ## Contributing 30 | 31 | 1. Fork it ( https://github.com/[my-github-username]/zabbix_graph/fork ) 32 | 2. Create your feature branch (`git checkout -b my-new-feature`) 33 | 3. Commit your changes (`git commit -am 'Add some feature'`) 34 | 4. Push to the branch (`git push origin my-new-feature`) 35 | 5. Create a new Pull Request 36 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | -------------------------------------------------------------------------------- /bin/zabbix_graph: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'zabbix_graph' 3 | ZabbixGraph::CLI.start(ARGV) 4 | -------------------------------------------------------------------------------- /lib/zabbix_graph.rb: -------------------------------------------------------------------------------- 1 | require "zabbix_graph/version" 2 | require "zabbixapi" 3 | require "peco_selector" 4 | require "optparse" 5 | require "fileutils" 6 | require "launchy" 7 | 8 | module ZabbixGraph 9 | class CLI 10 | def self.start(argv) 11 | Opener.new(parse_argv(argv)).select_and_open 12 | end 13 | 14 | def self.parse_argv(argv) 15 | options = {} 16 | 17 | parser = OptionParser.new 18 | parser.on('--host-graph') { options[:host_graph] = true } 19 | parser.on('--item-graph') { options[:item_graph] = true } 20 | parser.on('--period=VAL') {|v| options[:period] = v } 21 | parser.parse!(argv) 22 | 23 | options 24 | end 25 | end 26 | 27 | class Opener 28 | def initialize(options) 29 | @options = options 30 | @all_hosts = zbx.hosts.get({}) 31 | end 32 | 33 | def select_and_open 34 | hosts = PecoSelector.select_from(@all_hosts.sort_by do |h| 35 | h['host'] 36 | end.map do |h| 37 | [h['host'], h] 38 | end) 39 | 40 | items = zbx.client.api_request( 41 | method: 'item.get', 42 | params: { 43 | hostids: hosts.map {|h| h['hostid'] }, 44 | sortfield: 'name', 45 | sortorder: 'ASC', 46 | }, 47 | ) 48 | 49 | selected = PecoSelector.select_from(items.map do |i| 50 | [i['name'], i['key_']] 51 | end.uniq.map do |name, key| 52 | ["#{name} (#{key})", [name, key]] 53 | end) 54 | 55 | selected_items = items.select do |i| 56 | selected.any? do |name, key| 57 | i['name'] == name && i['key_'] == key 58 | end 59 | end 60 | 61 | if @options[:host_graph] 62 | open_host_graph(selected_items) 63 | elsif @options[:item_graph] 64 | open_item_graph(selected_items) 65 | else 66 | open_history(selected_items) 67 | end 68 | end 69 | 70 | private 71 | 72 | def open_history(items) 73 | url = URI.join(zabbix_url, "/history.php?#{query_string_from_items(items)}") 74 | 75 | Launchy.open url.to_s 76 | end 77 | 78 | def open_host_graph(items) 79 | host_items = items.group_by do |i| 80 | i['hostid'] 81 | end 82 | 83 | grouped_items = host_items.map do |hostid, items| 84 | host = @all_hosts.find {|h| h['hostid'] == hostid } 85 | [host['name'], items] 86 | end.sort_by do |hostname, _| 87 | hostname 88 | end 89 | 90 | open_grouped_items(grouped_items) 91 | end 92 | 93 | def open_item_graph(items) 94 | key_items = items.group_by do |i| 95 | [i['name'], i['key_']] 96 | end 97 | 98 | grouped_items = key_items.sort_by do |name_key, _| 99 | name_key.join 100 | end.map do |name_key, items| 101 | ["#{name_key[0]} (#{name_key[1]})", items] 102 | end 103 | 104 | open_grouped_items(grouped_items) 105 | end 106 | 107 | def open_grouped_items(grouped_items) 108 | html = "" 109 | grouped_items.each do |name, items| 110 | src = URI.join(zabbix_url, "/chart.php?#{query_string_from_items(items)}").to_s 111 | html << "
" 112 | html << "

" << name << "

" 113 | html << %{} 114 | html << "
" 115 | end 116 | 117 | path = File.join(temp_html_dir, "#{Time.now.to_f.to_s}.html") 118 | open(path, 'w') do |f| 119 | f.write html 120 | end 121 | 122 | Launchy.open path 123 | end 124 | 125 | def temp_html_dir 126 | dir = "/tmp/zabbix_graph" 127 | FileUtils.mkdir_p(dir) 128 | 129 | dir 130 | end 131 | 132 | def query_string_from_items(items) 133 | query = [['action', 'batchgraph'], ['graphtype', '0'], ['period', period.to_s]] 134 | items.each do |i| 135 | query << ['itemids[]', i['itemid']] 136 | end 137 | 138 | URI.encode_www_form(query) 139 | end 140 | 141 | def period 142 | return 3600 unless @options[:period] 143 | 144 | @options[:period].scan(/(\d+)([smhd])/).map do |part| 145 | scale = case part[1] 146 | when "s" 147 | 1 148 | when "m" 149 | 60 150 | when "h" 151 | 60 * 60 152 | when "d" 153 | 60 * 60 * 24 154 | end 155 | part[0].to_i * scale 156 | end.inject(0) {|sum, i| sum + i } 157 | end 158 | 159 | def zbx 160 | @zbx ||= ZabbixApi.connect( 161 | url: URI.join(zabbix_url, '/api_jsonrpc.php').to_s, 162 | user: zabbix_user, 163 | password: zabbix_password, 164 | ) 165 | end 166 | 167 | def zabbix_url 168 | env('ZABBIX_URL') 169 | end 170 | 171 | def zabbix_user 172 | env('ZABBIX_USER') 173 | end 174 | 175 | def zabbix_password 176 | env('ZABBIX_PASSWORD') 177 | end 178 | 179 | def env(key) 180 | ret = ENV[key] 181 | 182 | unless ret 183 | $stderr.puts "#{key} is not set." 184 | abort 185 | end 186 | 187 | ret 188 | end 189 | end 190 | end 191 | -------------------------------------------------------------------------------- /lib/zabbix_graph/version.rb: -------------------------------------------------------------------------------- 1 | module ZabbixGraph 2 | VERSION = "0.0.5" 3 | end 4 | -------------------------------------------------------------------------------- /zabbix_graph.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'zabbix_graph/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "zabbix_graph" 8 | spec.version = ZabbixGraph::VERSION 9 | spec.authors = ["Ryota Arai"] 10 | spec.email = ["ryota.arai@gmail.com"] 11 | spec.summary = %q{Open Zabbix adhoc graph} 12 | spec.homepage = "https://github.com/ryotarai/zabbix_graph" 13 | spec.license = "MIT" 14 | 15 | spec.files = `git ls-files -z`.split("\x0") 16 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 17 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 18 | spec.require_paths = ["lib"] 19 | 20 | spec.add_dependency "zabbixapi", "~> 2.4.2" 21 | spec.add_dependency "peco_selector", "~> 0.0.3" 22 | spec.add_dependency "launchy" 23 | 24 | spec.add_development_dependency "bundler", "~> 1.7" 25 | spec.add_development_dependency "rake", "~> 10.0" 26 | end 27 | --------------------------------------------------------------------------------