Advertisement
Guest User

Untitled

a guest
Apr 14th, 2017
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.32 KB | None | 0 0
  1. #!/usr/bin/perl
  2.  
  3. =encoding utf8
  4.  
  5. =head1 NAME
  6.  
  7. nzedb_ - Munin plugin to display misc nzedb stats.
  8.  
  9. =head1 CONFIGURATION
  10.  
  11. This script is used to generate data for several graphs. To generate
  12. data for one specific graph, you need to create a symbolic link with a
  13. name like nzedb_<GRAPH> to this script.
  14.  
  15. To get a graph over numbers of users use nzedb_users
  16. =head1 APPLICABLE SYSTEMS
  17.  
  18. Any MySQL platform, tested by the author on MySQL 5.1.29 and 5.0.51
  19.  
  20. =head1 CONFIGURATION
  21.  
  22. This script is used to generate data for several graphs. To generate
  23. data for one specific graph, you need to create a symbolic link with a
  24. name like nzedb_<GRAPH> to this script.
  25.  
  26. connection parameters - use this in your plugin configuration file.
  27.  
  28. [nzedb_*]
  29. env.mysqlconnection DBI:mysql:<yourdatabase>;host=127.0.0.1;port=3306
  30. env.mysqluser <user>
  31. env.mysqlpassword <password>
  32.  
  33. When createing syminks in your servicedir, use the following:
  34. nzedb_releases Graph of current nuber of releases
  35. nzedb_category Graph of current number of releases per category
  36. nzedb_category_short Graph of current number of releases per parent category
  37. nzedb_api Graph of API requests and NZB downloads
  38. nzedb_users Graph of current registered user accounts
  39. nzedb_cbp Graph of current number of Collections, Binaries, and Parts
  40. nzedb_predb Graph of current PreDB tables, and the number that has been matched.
  41.  
  42.  
  43. =head1 DEPENDENCIES
  44.  
  45. =over
  46.  
  47. =item DBD::mysql
  48.  
  49. =back
  50.  
  51. =head1 THANKS
  52. Code Originally writen by Jan Astrup (cryzeck@synIRC), adapted by ThePeePs
  53. for nZEDb. This is still a work in progress.
  54.  
  55. A special thanks to Kjell-Magne Øierud for the mysql_ plugin in munin which
  56. gave me the inspiration and reusable code to create this plugin.
  57.  
  58. =head1 LICENSE
  59.  
  60. Copyright (C) 2012 Jan Astrup (cryzeck@synIRC)
  61.  
  62. This program is free software; you can redistribute it and/or modify
  63. it under the terms of the GNU General Public License as published by
  64. the Free Software Foundation; version 2 dated June, 1991.
  65.  
  66. This program is distributed in the hope that it will be useful, but
  67. WITHOUT ANY WARRANTY; without even the implied warranty of
  68. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  69. General Public License for more details.
  70.  
  71. You should have received a copy of the GNU General Public License
  72. along with this program; if not, write to the Free Software
  73. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  74. USA.
  75.  
  76. =cut
  77.  
  78. use warnings;
  79. use strict;
  80. use utf8;
  81.  
  82. use DBI;
  83. use Data::Dumper;
  84. use File::Basename;
  85.  
  86. use Munin::Plugin;
  87.  
  88. #-- CONFIG --#
  89.  
  90. my %config = (
  91. 'dsn' => $ENV{'mysqlconnection'} || 'dbi:mysql:nzedb',
  92. 'user' => $ENV{'mysqluser'} || 'test',
  93. 'password' => $ENV{'mysqlpassword'} || 'test1',
  94. );
  95.  
  96. my %defaults = (
  97. global_attrs => {
  98. args => '--base 1000 -l 0',
  99. scale => 'no',
  100. },
  101. data_source_attrs => {
  102. draw => 'AREA',
  103. },
  104. );
  105.  
  106. my %graphs = ();
  107.  
  108. $graphs{releases} = {
  109. config => {
  110. global_attrs => {
  111. title => 'Releases',
  112. vlabel => 'Releases',
  113. },
  114. data_source_attrs => {
  115. min => '0',
  116.  
  117. },
  118. },
  119. data_sources => [
  120. {name => 'releases', label => 'Releases'},
  121. {name => 'nfo', label => 'Releases with NFO', draw => 'LINE1'},
  122. {name => 'renamed', label => 'Releases Renamed', draw => 'LINE1'},
  123. ],
  124. };
  125. $graphs{category} = {
  126. config => {
  127. global_attrs => {
  128. title => 'Releases by Category',
  129. vlabel => 'Releases',
  130. },
  131. data_source_attrs => {
  132. min => '0',
  133. draw => 'LINE1',
  134. type => 'GAUGE',
  135. },
  136. },
  137. data_sources => [
  138. {name => '3000', label => 'Audio'},
  139. {name => '3010', label => 'Audio - MP3'},
  140. {name => '3020', label => 'Audio - Video'},
  141. {name => '3030', label => 'Audio - Audiobook'},
  142. {name => '3040', label => 'Audio - Lossless'},
  143. {name => '3060', label => 'Audio - Foreign'},
  144. {name => '3999', label => 'Audio - Other'},
  145. {name => '7000', label => 'Books'},
  146. {name => '7010', label => 'Books - Magazines'},
  147. {name => '7020', label => 'Books - Ebook'},
  148. {name => '7030', label => 'Books - Comics'},
  149. {name => '7040', label => 'Books - Technical'},
  150. {name => '7060', label => 'Books - Foreign'},
  151. {name => '7999', label => 'Books - Other'},
  152. {name => '1000', label => 'Console'},
  153. {name => '1010', label => 'Console - NDS'},
  154. {name => '1020', label => 'Console - PSP'},
  155. {name => '1030', label => 'Console - Wii'},
  156. {name => '1040', label => 'Console - Xbox'},
  157. {name => '1050', label => 'Console - Xbox 360'},
  158. {name => '1060', label => 'Console - WiiWare/VC'},
  159. {name => '1070', label => 'Console - XBOX 360 DLC'},
  160. {name => '1080', label => 'Console - PS3'},
  161. {name => '1110', label => 'Console - 3DS'},
  162. {name => '1120', label => 'Console - PS Vita'},
  163. {name => '1130', label => 'Console - WiiU'},
  164. {name => '1140', label => 'Console - Xbox One'},
  165. {name => '1180', label => 'Console - PS4'},
  166. {name => '1999', label => 'Console - Other'},
  167. {name => '0', label => 'Other'},
  168. {name => '10', label => 'Other - Misc'},
  169. {name => '20', label => 'Other - Hashed'},
  170. {name => '2000', label => 'Movies'},
  171. {name => '2010', label => 'Movies - Foreign'},
  172. {name => '2030', label => 'Movies - SD'},
  173. {name => '2040', label => 'Movies - HD'},
  174. {name => '2045', label => 'Movies - UHD'},
  175. {name => '2050', label => 'Movies - 3D'},
  176. {name => '2060', label => 'Movies - BluRay'},
  177. {name => '2070', label => 'Movies - DVD'},
  178. {name => '2080', label => 'Movies - WEB-DL'},
  179. {name => '2999', label => 'Movies - Other'},
  180. {name => '4000', label => 'PC'},
  181. {name => '4010', label => 'PC - 0day'},
  182. {name => '4020', label => 'PC - ISO'},
  183. {name => '4030', label => 'PC - Mac'},
  184. {name => '4050', label => 'PC - Games'},
  185. {name => '4060', label => 'PC - Phone-IOS'},
  186. {name => '4070', label => 'PC - Phone-Android'},
  187. {name => '4999', label => 'PC - Phone-Other'},
  188. {name => '5000', label => 'TV'},
  189. {name => '5010', label => 'TV - WEB-DL'},
  190. {name => '5020', label => 'TV - Foreign'},
  191. {name => '5030', label => 'TV - SD'},
  192. {name => '5040', label => 'TV - HD'},
  193. {name => '5045', label => 'TV - UHD'},
  194. {name => '5060', label => 'TV - Sport'},
  195. {name => '5070', label => 'TV - Anime'},
  196. {name => '5080', label => 'TV - Documentary'},
  197. {name => '5999', label => 'TV - Other'},
  198. {name => '6000', label => 'XXX'},
  199. {name => '6010', label => 'XXX - DVD'},
  200. {name => '6020', label => 'XXX - WMV'},
  201. {name => '6030', label => 'XXX - XviD'},
  202. {name => '6040', label => 'XXX - x264'},
  203. {name => '6045', label => 'XXX - UHD'},
  204. {name => '6060', label => 'XXX - Imageset'},
  205. {name => '6070', label => 'XXX - Packs'},
  206. {name => '6080', label => 'XXX - SD'},
  207. {name => '6090', label => 'XXX - WEB-DL'},
  208. {name => '6999', label => 'XXX - Other'},
  209. ],
  210. };
  211.  
  212. $graphs{category_short} = {
  213. config => {
  214. global_attrs => {
  215. title => 'Releases by Parent Category',
  216. vlabel => 'Releases',
  217. },
  218. data_source_attrs => {
  219. min => '0',
  220. draw => 'LINE1',
  221. type => 'GAUGE',
  222. },
  223. },
  224. data_sources => [
  225. {name => 'audio', label => 'Audio'},
  226. {name => 'books', label => 'Books'},
  227. {name => 'console', label => 'Console'},
  228. {name => 'misc', label => 'Misc'},
  229. {name => 'movies', label => 'Movies'},
  230. {name => 'pc', label => 'PC'},
  231. {name => 'tv', label => 'TV'},
  232. {name => 'xxx', label => 'XXX'},
  233. ],
  234. };
  235.  
  236.  
  237. $graphs{api} = {
  238. config => {
  239. global_attrs => {
  240. title => 'API Requests / Downloads',
  241. vlabel => 'API / DOWNLOAD',
  242. },
  243. data_source_attrs => {
  244. min => '0',
  245. draw => 'LINE1',
  246. type => 'GAUGE',
  247. },
  248. },
  249. data_sources => [
  250. {name => 'request', label => 'API Requests'},
  251. {name => 'download', label => 'Downloads'},
  252. ],
  253. };
  254.  
  255. $graphs{cbp} = {
  256. config => {
  257. global_attrs => {
  258. title => 'Collections, Binaries, and Parts Counts',
  259. vlabel => 'Number of Records',
  260. args => '--base 1000 --logarithmic'
  261. },
  262. data_source_attrs => {
  263. min => '0',
  264. draw => 'AREA',
  265. type => 'GAUGE',
  266. },
  267. },
  268. data_sources => [
  269. {name => 'col', label => 'Collections'},
  270. {name => 'bin', label => 'Binaries', draw => 'STACK'},
  271. {name => 'part', label => 'Parts', draw => 'STACK'},
  272. {name => 'missed', label => 'Missing Parts', draw => 'LINE1'},
  273. {name => 'repair', label => 'Parts Repair', draw => 'LINE1'},
  274. ],
  275. };
  276.  
  277. $graphs{users} = {
  278. config => {
  279. global_attrs => {
  280. title => 'Registered Users',
  281. vlabel => 'Usercount',
  282. },
  283. data_source_attrs => {
  284. min => '0',
  285. },
  286. },
  287. data_sources => [
  288. {name => 'users', label => 'Users'},
  289. ],
  290. };
  291.  
  292. $graphs{predb} = {
  293. config => {
  294. global_attrs => {
  295. title => 'PreDB',
  296. vlabel => 'Count',
  297. args => '--base 1000 --logarithmic',
  298. },
  299. data_source_attrs => {
  300. min => '0',
  301. },
  302. },
  303. data_sources => [
  304. {name => 'punmatched', label => 'Unmatched PreDB'},
  305. {name => 'pmatched', label => 'Matched Pr-eDB', draw => 'LINE1'},
  306. ],
  307. };
  308.  
  309. our $data;
  310. sub config {
  311. my $graph_name = shift;
  312. die 'Unknown graph ' . ($graph_name ? $graph_name : '')
  313. unless $graphs{$graph_name};
  314.  
  315. my $graph = $graphs{$graph_name};
  316.  
  317. my %conf = (%{$defaults{global_attrs}}, %{$graph->{config}{global_attrs}});
  318. while (my ($k, $v) = each %conf) {
  319. print "graph_$k $v\n";
  320. }
  321. print "graph_category nzedb\n";
  322.  
  323. my $i = 0;
  324. for my $ds (@{$graph->{data_sources}}) {
  325. my %ds_spec = (
  326. %{$defaults{data_source_attrs}},
  327. %{$graph->{config}{data_source_attrs}},
  328. %$ds,
  329. );
  330. while (my ($k, $v) = each %ds_spec) {
  331. # 'name' is only used internally in this script, not
  332. # understood by munin.
  333. next if ($k eq 'name');
  334.  
  335. if ($k eq 'draw' && $v eq 'AREASTACK') {
  336. printf("%s.%s %s\n",
  337. clean_fieldname($ds->{label}), $k, ($i ? 'STACK' : 'AREA'));
  338. }
  339. else {
  340. printf("%s.%s %s\n", clean_fieldname($ds->{label}), $k, $v);
  341. }
  342. $i++;
  343. }
  344. }
  345. return 0;
  346. }
  347.  
  348. sub main {
  349. my $graph = substr(basename($0), length('nzedb_'));
  350. my $command = $ARGV[0] || 'show';
  351.  
  352. my %commands = (
  353. 'config' => \&config,
  354. 'show' => \&show,
  355. );
  356.  
  357. die "Unknown command: $command" unless exists $commands{$command};
  358. return $commands{$command}->($graph);
  359. }
  360.  
  361. sub show {
  362. my $graph_name = shift;
  363. die 'Unknown graph ' . ($graph_name ? $graph_name : '')
  364. unless $graphs{$graph_name};
  365.  
  366. my $graph = $graphs{$graph_name};
  367. run_queries($graph_name);
  368. for my $ds (@{$graph->{data_sources}}) {
  369. printf "%s.value %s\n", clean_fieldname($ds->{label}), ($data->{$ds->{name}} ? $data->{$ds->{name}} : '0');
  370. }
  371. return 0;
  372. }
  373.  
  374. sub db_connect {
  375. my $dsn = "$config{dsn};mysql_connect_timeout=5";
  376.  
  377. return DBI->connect($dsn, $config{user}, $config{password}, {
  378. RaiseError => 1,
  379. PrintError => 0,
  380. FetchHashKeyName => 'NAME_lc',
  381. });
  382.  
  383. }
  384.  
  385. sub run_queries {
  386. my $updater = shift;
  387. $data = {};
  388. my $dbh = db_connect();
  389. my %updaters = (
  390. 'releases' => \&update_releases,
  391. 'users' => \&update_users,
  392. 'api' => \&update_requests,
  393. 'category' => \&update_category,
  394. 'category_short' => \&update_category_short,
  395. 'cbp' => \&update_cbp,
  396. 'predb' => \&update_predb,
  397. );
  398. die "Unknown updater: $updater" unless exists $updaters{$updater};
  399. $updaters{$updater}->($dbh);
  400. }
  401.  
  402. sub update_requests {
  403. my ($dbh) = @_;
  404. my %queries = (
  405. request => 'select count(*) as requests from user_requests where timestamp > now() - INTERVAL 5 MINUTE;',
  406. download => 'select count(*) as downloads from user_downloads where timestamp > now() - INTERVAL 5 MINUTE;',
  407. );
  408. for my $name ( qw(request download) ) {
  409. my $query = $queries{$name};
  410. my $sth = $dbh->prepare($query);
  411. $sth->execute();
  412. while (my $row = $sth->fetch) {
  413. $data->{$name} = $row->[0];
  414. }
  415. $sth->finish();
  416. }
  417. }
  418.  
  419. sub update_category {
  420. my ($dbh) = @_;
  421. my $sth = $dbh->prepare('select count(*) as releases, categories.title, categories.id from releases LEFT JOIN categories ON releases.categories_id = categories.ID group by releases.categories_id');
  422. $sth->execute();
  423. if ($@) { die $@; }
  424. while (my $row = $sth->fetch) {
  425. $data->{$row->[2]} = $row->[0];
  426. }
  427.  
  428. }
  429.  
  430. sub update_category_short {
  431. my ($dbh) = @_;
  432. my $sth = $dbh->prepare('SELECT PARTITION_NAME AS category, SUM(TABLE_ROWS) AS count FROM information_schema.PARTITIONS WHERE TABLE_NAME = \'releases\' AND TABLE_SCHEMA = \'nzedb\' GROUP BY PARTITION_NAME');
  433. $sth->execute();
  434. if ($@) { die $@; }
  435. while (my $row = $sth->fetch) {
  436. $data->{$row->[0]} = $row->[1];
  437. }
  438.  
  439. }
  440.  
  441. sub update_releases {
  442. my ($dbh) = @_;
  443. my $sth = $dbh->prepare('SELECT (SELECT TABLE_ROWS FROM information_schema.TABLES WHERE TABLE_NAME = \'releases\' AND TABLE_SCHEMA = \'nzedb\') AS releases, SUM(IF(nzbstatus = 1 AND nfostatus = 1,1,0)) AS nfo,SUM(IF(isrenamed = 1,1,0)) AS renamed
  444. FROM releases');
  445. eval {
  446. $sth->execute();
  447. };
  448. if ($@) { die $@; }
  449. my $row = $sth->fetchrow_hashref();
  450. $data->{'releases'} = $row->{'releases'};
  451. $data->{'nfo'} = $row->{'nfo'};;
  452. $data->{'renamed'} = $row->{'renamed'};
  453. $sth->finish();
  454. }
  455.  
  456. sub update_users {
  457. my ($dbh) = @_;
  458. my $sth = $dbh->prepare('SELECT count(*) as users from users');
  459. eval {
  460. $sth->execute();
  461. };
  462. if ($@) { die $@; }
  463. my $row = $sth->fetchrow_hashref();
  464. $data->{users} = $row->{'users'};
  465. $sth->finish();
  466. }
  467.  
  468. sub update_cbp {
  469. my ($dbh) = @_;
  470. my $collections = 0;
  471. my $binaries = 0;
  472. my $parts = 0;
  473. my $repair = 0;
  474. my $missed = 0;
  475. my $sth = $dbh->prepare('SELECT TABLE_NAME AS name, TABLE_ROWS As count FROM information_schema.TABLES WHERE TABLE_SCHEMA = \'nzedb\'');
  476. eval {
  477. $sth->execute();
  478. };
  479. if ($@) {die $@; }
  480. while (my $row = $sth->fetch) {
  481. if ($row->[0] =~ /collections_/) {
  482. $collections += $row->[1];
  483. } elsif ($row->[0] =~ /binaries_/) {
  484. $binaries += $row->[1];
  485. } elsif ($row->[0] =~ /^parts_/) {
  486. $parts += $row->[1];
  487. } elsif ($row->[0] =~ /missed_parts_/) {
  488. $missed += $row->[1];
  489. } elsif ($row->[0] =~ /partrepair_/) {
  490. $repair += $row->[1];
  491. }
  492. }
  493. $data->{'col'} = $collections;
  494. $data->{'bin'} = $binaries;
  495. $data->{'part'} = $parts;
  496. $data->{'repair'} = $repair;
  497. $data->{'missed'} = $missed;
  498. $sth->finish;
  499. }
  500.  
  501. sub update_predb {
  502. my ($dbh) = @_;
  503. my $sth = $dbh->prepare('SELECT (SELECT TABLE_ROWS FROM information_schema.TABLES WHERE table_name = \'predb\' AND TABLE_SCHEMA = \'nzedb\') AS predb, SUM(IF(predb_id > 0,1,0)) AS predb_matched, COUNT(DISTINCT(predb_id)) AS distinct_predb_matched
  504. FROM releases r');
  505. eval {
  506. $sth->execute();
  507. };
  508. my $row = $sth->fetchrow_hashref();
  509. $data->{'punmatched'} = $row->{'predb'} - $row->{'distinct_predb_matched'};
  510. $data->{'pmatched'} = $row->{'predb_matched'};
  511. $sth->finish;
  512. }
  513.  
  514. exit main() unless caller;
  515.  
  516.  
  517. 1;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement