Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add html template support

  • Loading branch information...
commit 96cd926dedc09d92f9f8f64b8913f661e96a545e 1 parent 10a0fca
@bcui6611 authored
View
22 Makefile.am
@@ -0,0 +1,22 @@
+COUCHBASE_PYTHON_LIB = ../couchbase-python-client/couchbase
+
+default:
+
+pythonlibdir=$(libdir)/python
+
+pythonlib_SCRIPTS= cbworkloadgen
+
+PYTHON_TOOLS= wrapper/cbworkloadgen
+
+${PYTHON_TOOLS}: wrapper/wrapper
+ cp $< $@
+
+CLEANFILES = ${PYTHON_TOOLS}
+bin_SCRIPTS = ${PYTHON_TOOLS}
+
+EXTRA_DIST = $(pythonlib_SCRIPTS)
+
+install-data-hook:
+ cp -rf $(COUCHBASE_PYTHON_LIB) $(pythonlibdir)
+
+
View
28 analyzer.py
@@ -32,6 +32,7 @@
node_symptoms = {}
indicator_error = {}
indicator_warn = {}
+node_disparate = {}
def format_output(counter, result):
if len(result) == 1:
@@ -88,12 +89,15 @@ def run_analysis(self):
for bucket, values in result.iteritems():
if bucket == "cluster":
continue
- if values[-1][0] == "total":
- bucket_symptoms[bucket].append({"description" : counter["description"], "value" : values[-1][1]})
- for val in values[:-1]:
- if bucket_node_symptoms[bucket].has_key(val[0]) == False:
- bucket_node_symptoms[bucket][val[0]] = []
- bucket_node_symptoms[bucket][val[0]].append({"description" : counter["description"], "value" : val[1]})
+ for val in values:
+ if val[0] == "variance":
+ continue
+ elif val[0] == "total":
+ bucket_symptoms[bucket].append({"description" : counter["description"], "value" : values[-1][1]})
+ else:
+ if bucket_node_symptoms[bucket].has_key(val[0]) == False:
+ bucket_node_symptoms[bucket][val[0]] = []
+ bucket_node_symptoms[bucket][val[0]].append({"description" : counter["description"], "value" : val[1]})
if pill.has_key("perNode") and pill["perNode"] :
node_symptoms[counter["name"]] = {"description" : counter["description"], "value":result}
@@ -108,6 +112,16 @@ def run_analysis(self):
if values.has_key("warn"):
indicator_warn[counter["name"]] = {"description" : counter["description"], "bucket": bucket, "value":values["warn"]}
+ if pill.has_key("nodeDisparate") and pill["nodeDisparate"] :
+ for bucket,values in result.iteritems():
+ if bucket == "cluster":
+ continue
+ for val in values:
+ if val[0] == "total":
+ continue;
+ if val[0] == "variance" and val[1] != 0:
+ node_disparate[counter["name"]] = {"description" : counter["description"], "bucket": bucket, "value":values}
+
self.accessor.close()
self.accessor.remove_db()
@@ -143,4 +157,6 @@ def run_report(self):
util.pretty_print(indicator_error)
util.pretty_print(indicator_warn)
+ print "Node disparate"
+ util.pretty_print(node_disparate)
#print Template(file="report-htm.tmpl", searchList=[dict])
View
19 bucket_stats.py
@@ -98,11 +98,18 @@ def run(self, accessor):
class NumVbuckt:
def run(self, accessor):
- trend = []
- for bucket, stats_info in stats_buffer.buckets_summary.iteritems():
+ result = {}
+ for bucket, stats_info in stats_buffer.buckets.iteritems():
+ num_error = []
total, values = stats_buffer.retrieveSummaryStats(bucket, accessor["counter"])
- trend.append((bucket, values[-1]))
- return trend
+ values = stats_info[accessor["scale"]][accessor["counter"]]
+ nodeStats = values["nodeStats"]
+ for node, vals in nodeStats.iteritems():
+ if vals[-1] < accessor["threshold"]:
+ num_error.append({"node":node, "value":vals[-1]})
+ if len(num_error) > 0:
+ result[bucket] = {"error" : num_error}
+ return result
BucketCapsule = [
{"name" : "bucketList",
@@ -178,14 +185,14 @@ def run(self, accessor):
"description" : "Active VBucket number",
"counter" : "vb_active_num",
"type" : "python",
- "scale" : "minute",
+ "scale" : "hour",
"code" : "NumVbuckt"
},
{
"description" : "Replica VBucket number",
"counter" : "vb_replica_num",
"type" : "python",
- "scale" : "minute",
+ "scale" : "hour",
"code" : "NumVbuckt"
},
]
View
56 cluster_stats.py
@@ -103,18 +103,42 @@ def run(self, accessor):
samplesCount = values["samplesCount"]
trend = []
total = 0
+ data = []
for node, vals in nodeStats.iteritems():
a, b = util.linreg(timestamps, vals)
value = a * timestamps[-1] + b
total += value
trend.append((node, util.pretty_float(value)))
+ data.append(value)
total /= len(nodeStats)
trend.append(("total", util.pretty_float(total)))
+ trend.append(("variance", util.two_pass_variance(data)))
cluster += total
result[bucket] = trend
result["cluster"] = util.pretty_float(cluster / len(stats_buffer.buckets))
return result
+class MemUsed:
+ def run(self, accessor):
+ result = {}
+ cluster = 0
+ for bucket, stats_info in stats_buffer.buckets.iteritems():
+ values = stats_info[accessor["scale"]][accessor["counter"]]
+ timestamps = values["timestamp"]
+ timestamps = [x - timestamps[0] for x in timestamps]
+ nodeStats = values["nodeStats"]
+ samplesCount = values["samplesCount"]
+ trend = []
+ total = 0
+ data = []
+ for node, vals in nodeStats.iteritems():
+ avg = sum(vals) / samplesCount
+ trend.append((node, util.pretty_float(avg)))
+ data.append(avg)
+ trend.append(("variance", util.two_pass_variance(data)))
+ result[bucket] = trend
+ return result
+
class ItemGrowth:
def run(self, accessor):
result = {}
@@ -144,10 +168,15 @@ def run(self, accessor):
class NumVbuckt:
def run(self, accessor):
result = {}
- for bucket, stats_info in stats_buffer.buckets_summary.iteritems():
- total, values = stats_buffer.retrieveSummaryStats(bucket, accessor["counter"])
- if values[-1] < accessor["threshold"]:
- result[bucket] = values[-1]
+ for bucket, stats_info in stats_buffer.buckets.iteritems():
+ num_error = []
+ values = stats_info[accessor["scale"]][accessor["counter"]]
+ nodeStats = values["nodeStats"]
+ for node, vals in nodeStats.iteritems():
+ if vals[-1] < accessor["threshold"]:
+ num_error.append({"node":node, "value":vals[-1]})
+ if len(num_error) > 0:
+ result[bucket] = {"error" : num_error}
return result
ClusterCapsule = [
@@ -198,6 +227,7 @@ def run(self, accessor):
"perNode" : True,
"perBucket" : True,
"indicator" : False,
+ "nodeDisparate" : True,
},
{"name" : "DGM",
"ingredients" : [
@@ -270,7 +300,7 @@ def run(self, accessor):
"description" : "Active VBucket number is less than expected",
"counter" : "vb_active_num",
"type" : "python",
- "scale" : "summary",
+ "scale" : "hour",
"code" : "NumVbuckt",
"threshold" : 1024,
},
@@ -279,13 +309,27 @@ def run(self, accessor):
"description" : "Replica VBucket number is less than expected",
"counter" : "vb_replica_num",
"type" : "python",
- "scale" : "summary",
+ "scale" : "hour",
"code" : "NumVbuckt",
"threshold" : 1024,
},
],
"indicator" : True,
},
+ {"name" : "MemoryUsage",
+ "ingredients" : [
+ {
+ "name" : "memoryUsage",
+ "description" : "Check if memory usage and/or fragmentaion",
+ "type" : "python",
+ "counter" : "mem_used",
+ "scale" : "hour",
+ "code" : "MemUsed",
+ },
+ ],
+ "perNode" : True,
+ "nodeDisparate" : True,
+ },
]
View
81 config/autorun.sh
@@ -0,0 +1,81 @@
+#!/bin/sh
+
+AUTOMAKE_FLAGS="--add-missing --copy --force --foreign --warning=portability"
+ACLOCAL_FLAGS="-I m4"
+AUTOCONF_CLAGS="--warnings=error --force"
+
+ARGV0=$0
+ARGS="$@"
+
+die() { echo "$@"; exit 1; }
+
+run() {
+ echo "$ARGV0: running \`$@' $ARGS"
+ $@ $ARGS
+}
+
+# Try to locate a program by using which, and verify that the file is an
+# executable
+locate_binary() {
+ for f in $@
+ do
+ file=`which $f 2>/dev/null | grep -v '^no '`
+ if test -n "$file" -a -x "$file"; then
+ echo $file
+ return 0
+ fi
+ done
+
+ echo ""
+ return 1
+}
+
+if test -f config/pre_hook.sh
+then
+ . config/pre_hook.sh
+fi
+
+if [ -d .git ]
+then
+ mkdir m4 > /dev/zero 2>&1
+ perl config/version.pl || die "Failed to run config/version.pl"
+fi
+
+# Try to detect the supported binaries if the user didn't
+# override that by pushing the environment variable
+if test x$ACLOCAL = x; then
+ ACLOCAL=`locate_binary aclocal-1.11 aclocal-1.10 aclocal`
+ if test x$ACLOCAL = x; then
+ die "Did not find a supported aclocal"
+ fi
+fi
+
+if test x$AUTOMAKE = x; then
+ AUTOMAKE=`locate_binary automake-1.11 automake-1.10 automake`
+ if test x$AUTOMAKE = x; then
+ die "Did not find a supported automake"
+ fi
+fi
+
+if test x$AUTOCONF = x; then
+ AUTOCONF=`locate_binary autoconf`
+ if test x$AUTOCONF = x; then
+ die "Did not find a supported autoconf"
+ fi
+fi
+
+run $ACLOCAL $ACLOCAL_FLAGS || die "Can't execute aclocal"
+run $AUTOMAKE $AUTOMAKE_FLAGS || die "Can't execute automake"
+run $AUTOCONF $AUTOCONF_FLAGS || die "Can't execute autoconf"
+
+if test -f config/post_hook.sh
+then
+ . config/post_hook.sh
+fi
+
+echo "---"
+echo "Configured with the following tools:"
+echo " * `$ACLOCAL --version | head -1`"
+echo " * `$AUTOMAKE --version | head -1`"
+echo " * `$AUTOCONF --version | head -1`"
+echo "---"
View
52 config/version.pl
@@ -0,0 +1,52 @@
+#!/usr/bin/perl
+# If you think this is stupid/overkill, blame dormando
+
+use warnings;
+use strict;
+
+my $version = `git describe`;
+chomp $version;
+# Test the various versions.
+#my $version = 'foob';
+#my $version = '1.4.2-30-gf966dba';
+#my $version = '1.4.3-rc1';
+#my $version = '1.4.3';
+unless ($version =~ m/^\d+\.\d+\.\d+/) {
+ write_file('m4/version.m4', "m4_define([VERSION_NUMBER], [UNKNOWN])\n");
+ exit;
+}
+
+$version =~ s/-/_/g;
+write_file('m4/version.m4', "m4_define([VERSION_NUMBER], [$version])\n");
+my ($VERSION, $FULLVERSION, $RELEASE);
+
+if ($version =~ m/^(\d+\.\d+\.\d+)_rc(\d+)$/) {
+ $VERSION = $1;
+ $FULLVERSION = $version;
+ $RELEASE = '0.1.rc' . $2;
+} elsif ($version =~ m/^(\d+\.\d+\.\d+)_(.+)$/) {
+ $VERSION = $1;
+ $FULLVERSION = $version;
+ $RELEASE = '1.' . $2;
+} elsif ($version =~ m/^(\d+\.\d+\.\d+)$/) {
+ $VERSION = $1;
+ $FULLVERSION = $version;
+ $RELEASE = '1';
+}
+
+sub write_file {
+ my $file = shift;
+ my $data = shift;
+ open(my $fh, "> $file") or die "Can't open $file: $!";
+ print $fh $data;
+ close($fh);
+}
+
+sub read_file {
+ my $file = shift;
+ local $/ = undef;
+ open(my $fh, "< $file") or die "Can't open $file: $!";
+ my $data = <$fh>;
+ close($fh);
+ return $data;
+}
View
12 configure.ac
@@ -0,0 +1,12 @@
+# workload-generator
+# Copyright (C) 2011 Couchbase, INC
+# All rights reserved.
+#
+AC_PREREQ(2.59)
+m4_include([m4/version.m4])
+AC_INIT(workload-generator, VERSION_NUMBER, bin@couchbase.com)
+AC_CONFIG_AUX_DIR(config)
+AM_INIT_AUTOMAKE
+AC_CONFIG_FILES(Makefile wrapper/wrapper)
+
+AC_OUTPUT
View
59 diskqueue_stats.py
@@ -9,7 +9,7 @@ def run(self, accessor):
for bucket, stats_info in stats_buffer.buckets.iteritems():
#print bucket, stats_info
disk_queue_avg_error = []
- dsik_queue_avg_warn = []
+ disk_queue_avg_warn = []
values = stats_info[accessor["scale"]][accessor["counter"]]
nodeStats = values["nodeStats"]
samplesCount = values["samplesCount"]
@@ -18,10 +18,10 @@ def run(self, accessor):
if avg > accessor["threshold"]["high"]:
disk_queue_avg_error.append({"node":node, "level":"red", "value":avg})
elif avg > accessor["threshold"]["low"]:
- dsik_queue_avg_warn.append({"node":node, "level":"yellow", "value":avg})
+ disk_queue_avg_warn.append({"node":node, "level":"yellow", "value":avg})
if len(disk_queue_avg_error) > 0:
result[bucket] = {"error" : disk_queue_avg_error}
- if len(dsik_queue_avg_warn) > 0:
+ if len(disk_queue_avg_warn) > 0:
result[bucket] = {"warn" : disk_queue_avg_warn}
return result
@@ -71,6 +71,27 @@ def run(self, accessor):
result[bucket] = {"warn" : trend_warn}
return result
+class DiskQueueDrainingRate:
+ def run(self, accessor):
+ result = {}
+ for bucket, stats_info in stats_buffer.buckets.iteritems():
+ #print bucket, stats_info
+ disk_queue_avg_error = []
+ disk_queue_avg_warn = []
+ drain_values = stats_info[accessor["scale"]][accessor["counter"][0]]
+ len_values = stats_info[accessor["scale"]][accessor["counter"][1]]
+ nodeStats = drain_values["nodeStats"]
+ samplesCount = drain_values["samplesCount"]
+ for node, vals in nodeStats.iteritems():
+ avg = sum(vals) / samplesCount
+ disk_len_vals = len_values["nodeStats"][node]
+ len_avg = sum(disk_len_vals) / samplesCount
+ if avg < accessor["threshold"]["drainRate"] and len_avg > accessor["threshold"]["diskLength"]:
+ disk_queue_avg_error.append({"node":node, "level":"red", "value":avg})
+ if len(disk_queue_avg_error) > 0:
+ result[bucket] = {"error" : disk_queue_avg_error}
+ return result
+
DiskQueueCapsule = [
{"name" : "DiskQueueDiagnosis",
"description" : "",
@@ -122,4 +143,36 @@ def run(self, accessor):
],
"indicator" : True,
},
+ {"name" : "DiskQueueDrainingAnalysis",
+ "description" : "",
+ "ingredients" : [
+ {
+ "name" : "activeDiskQueueDrainRate",
+ "description" : "Persistence severely behind - active disk queue draining rate is below threshold",
+ "counter" : ["vb_active_queue_drain", "disk_write_queue"],
+ "pernode" : True,
+ "scale" : "minute",
+ "type" : "python",
+ "code" : "DiskQueueDrainingRate",
+ "threshold" : {
+ "drainRate" : 0,
+ "diskLength" : 100000,
+ },
+ },
+ {
+ "name" : "replicaDiskQueueDrainRate",
+ "description" : "Persistence severely behind - replica disk queue draining rate is below threshold",
+ "counter" : ["vb_replica_queue_drain", "disk_write_queue"],
+ "pernode" : True,
+ "scale" : "minute",
+ "type" : "python",
+ "code" : "DiskQueueDrainingRate",
+ "threshold" : {
+ "drainRate" : 0,
+ "diskLength" : 100000,
+ },
+ },
+ ],
+ "indicator" : True,
+ },
]
View
4 healthChecker.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# -*- coding: utf-8 -*-
import getopt
@@ -146,7 +146,7 @@ def collect_data():
cmd = 'bucket-node-stats'
for scale, stat_set in stats_buffer.buckets[bucket_name].iteritems():
for stat in stat_set.iterkeys():
- #print "retieving: ", stat, " scale:", scale
+ print "retieving: ", stat, " scale:", scale
c = buckets.BucketNodeStats(bucket_name, stat, scale)
json = c.runCmd(cmd, server, port, user, password, opts)
stats_buffer.buckets[bucket_name][scale][stat] = json
View
237 htmlreport.tmpl
@@ -0,0 +1,237 @@
+<HTML>
+<HEAD><TITLE>sample-report-v2</TITLE>
+<STYLE type="text/css">
+
+body {margin-top: 0px;margin-left: 0px;}
+
+#page_1 {position:relative; overflow: hidden;margin-top: 96px;margin-left: 94px;margin-bottom: 73px;width: 620px;background-image: url(sample-report-v2_images/sample-report-v21.jpg);background-position: 0px 48px;background-size: 604px 704px;background-repeat: no-repeat;}
+
+
+
+#page_2 {position:relative; overflow: hidden;margin-top: 128px;margin-left: 96px;margin-bottom: 107px;width: 607px;background-image: url(sample-report-v2_images/sample-report-v22.jpg);background-position: 60px 362px;background-size: 128px 362px;background-repeat: no-repeat;}
+
+
+
+#page_3 {position:relative; overflow: hidden;margin-top: 63px;margin-left: 120px;margin-bottom: 71px;width: 583px;background-image: url(sample-report-v2_images/sample-report-v23.jpg);background-position: 84px 148px;background-size: 43px 726px;background-repeat: no-repeat;}
+
+
+
+#page_4 {position:relative; overflow: hidden;margin-top: 63px;margin-left: 96px;margin-bottom: 335px;width: 607px;background-image: url(sample-report-v2_images/sample-report-v24.jpg);background-position: 108px 206px;background-size: 23px 19px;background-repeat: no-repeat;}
+
+
+
+.ft0{font: 35px 'Arial';color: #17365d;line-height: 40px;}
+.ft1{font: italic 19px 'Arial';color: #345a8a;line-height: 23px;}
+.ft2{font: bold 16px 'Arial';line-height: 19px;}
+.ft3{font: 16px 'Arial';line-height: 18px;}
+.ft4{font: bold 21px 'Arial';color: #345a8a;line-height: 24px;}
+.ft5{font: bold 17px 'Arial';color: #4f81bd;line-height: 19px;}
+.ft6{font: 16px 'Arial';line-height: 18px;white-space: nowrap;}
+.ft7{font: 13px 'Courier New';line-height: 16px;white-space: nowrap;position: relative; bottom: -18px;}
+.ft8{font: bold 16px 'Arial';line-height: 19px;white-space: nowrap;}
+.ft9{font: 15px 'Arial';line-height: 17px;white-space: nowrap;}
+.ft10{font: 13px 'Courier New';line-height: 15px;}
+.ft11{font: 16px 'Arial';margin-left: 16px;line-height: 17px;}
+.ft12{font: 10px 'Symbol';line-height: 12px;}
+.ft13{font: 16px 'Arial';margin-left: 18px;line-height: 18px;}
+.ft14{font: 16px 'Symbol';line-height: 20px;}
+.ft15{font: bold 16px 'Arial';line-height: 17px;white-space: nowrap;}
+.ft16{font: 16px 'Symbol';line-height: 29px;}
+.ft17{font: 16px 'Arial';line-height: 27px;}
+.ft18{font: 16px 'Courier New';line-height: 27px;}
+.ft19{font: 16px 'Courier New';line-height: 38px;}
+.ft20{font: 16px 'Arial';line-height: 38px;}
+.ft21{font: 15px 'Arial';line-height: 17px;}
+.ft22{font: 16px 'Arial';margin-left: 4px;line-height: 18px;}
+.ft23{font: 10px 'Symbol';line-height: 4px;}
+.ft24{font: 16px 'Arial';margin-left: 18px;line-height: 36px;}
+
+.p0{text-align: left;padding-left: 2px;margin-top: 0px;margin-bottom: 0px;}
+.p1{text-align: left;padding-left: 2px;margin-top: 40px;margin-bottom: 0px;}
+.p2{text-align: left;padding-left: 2px;margin-top: 3px;margin-bottom: 0px;}
+.p3{text-align: left;padding-left: 2px;margin-top: 85px;margin-bottom: 0px;}
+.p4{text-align: left;padding-left: 2px;margin-top: 34px;margin-bottom: 0px;}
+.p5{text-align: justify;padding-left: 74px;margin-top: 0px;margin-bottom: 0px;}
+.p6{text-align: justify;padding-left: 26px;margin-top: 0px;margin-bottom: 0px;}
+.p7{text-align: left;padding-left: 26px;margin-top: 6px;margin-bottom: 0px;}
+.p8{text-align: left;padding-left: 74px;padding-right: 306px;margin-top: 0px;margin-bottom: 0px;text-indent: -47px;}
+.p9{text-align: left;padding-left: 74px;padding-right: 302px;margin-top: 0px;margin-bottom: 0px;}
+.p10{text-align: left;margin-top: 0px;margin-bottom: 0px;}
+.p11{text-align: left;margin-top: 70px;margin-bottom: 0px;}
+.p12{text-align: left;margin-top: 38px;margin-bottom: 0px;}
+.p13{text-align: left;margin-top: 50px;margin-bottom: 0px;}
+.p14{text-align: left;margin-top: 34px;margin-bottom: 0px;}
+.p15{text-align: justify;margin-top: 0px;margin-bottom: 0px;}
+.p16{text-align: justify;padding-left: 24px;margin-top: 6px;margin-bottom: 0px;}
+.p17{text-align: justify;padding-left: 24px;margin-top: 0px;margin-bottom: 0px;}
+.p18{text-align: justify;padding-left: 48px;padding-right: 27px;margin-top: 0px;margin-bottom: 0px;text-indent: -24px;}
+
+.td0{text-align: left;padding-left: 0px;padding-right: 0px;width: 15px;vertical-align: bottom;}
+.td1{text-align: left;padding-left: 9px;padding-right: 0px;width: 251px;vertical-align: bottom;}
+.td2{text-align: left;padding-left: 2px;padding-right: 0px;width: 110px;vertical-align: bottom;}
+.td3{text-align: left;padding-left: 57px;padding-right: 0px;width: 203px;vertical-align: bottom;}
+.td4{text-align: left;padding-left: 0px;padding-right: 0px;width: 112px;vertical-align: bottom;}
+.td5{border-left: #000000 1pt solid;border-right: #000000 1pt solid;border-top: #000000 1pt solid;border-bottom: #000000 1pt solid;text-align: left;padding-left: 7px;padding-right: 0px;width: 140px;vertical-align: bottom;}
+.td6{border-right: #000000 1pt solid;border-top: #000000 1pt solid;border-bottom: #000000 1pt solid;text-align: left;padding-left: 7px;padding-right: 0px;width: 332px;vertical-align: bottom;}
+.td7{border-right: #000000 1pt solid;border-top: #000000 1pt solid;border-bottom: #000000 1pt solid;text-align: left;padding-left: 7px;padding-right: 0px;width: 89px;vertical-align: bottom;}
+.td8{border-left: #000000 1pt solid;border-right: #000000 1pt solid;border-bottom: #000000 1pt solid;text-align: left;padding-left: 7px;padding-right: 0px;width: 140px;vertical-align: bottom;}
+.td9{border-right: #000000 1pt solid;border-bottom: #000000 1pt solid;text-align: left;padding-left: 7px;padding-right: 0px;width: 332px;vertical-align: bottom;}
+.td10{border-right: #000000 1pt solid;border-bottom: #000000 1pt solid;text-align: left;padding-left: 7px;padding-right: 0px;width: 89px;vertical-align: bottom;}
+.td11{border-left: #000000 1pt solid;border-right: #000000 1pt solid;border-top: #000000 1pt solid;border-bottom: #000000 1pt solid;text-align: left;padding-left: 7px;padding-right: 0px;width: 311px;vertical-align: bottom;}
+.td12{border-right: #000000 1pt solid;border-top: #000000 1pt solid;border-bottom: #000000 1pt solid;text-align: left;padding-left: 7px;padding-right: 0px;width: 258px;vertical-align: bottom;}
+.td13{border-left: #000000 1pt solid;border-right: #000000 1pt solid;border-bottom: #000000 1pt solid;text-align: left;padding-left: 7px;padding-right: 0px;width: 311px;vertical-align: bottom;}
+.td14{border-right: #000000 1pt solid;border-bottom: #000000 1pt solid;text-align: left;padding-left: 7px;padding-right: 0px;width: 258px;vertical-align: bottom;}
+.td15{border-left: #000000 1pt solid;border-right: #000000 1pt solid;text-align: left;padding-left: 7px;padding-right: 0px;width: 311px;vertical-align: bottom;}
+.td16{border-right: #000000 1pt solid;text-align: left;padding-left: 7px;padding-right: 0px;width: 258px;vertical-align: bottom;}
+.td17{border-left: #000000 1pt solid;border-right: #000000 1pt solid;border-bottom: #000000 1pt solid;text-align: left;padding-left: 0px;padding-right: 0px;width: 318px;vertical-align: bottom;}
+.td18{border-right: #000000 1pt solid;text-align: left;padding-left: 0px;padding-right: 0px;width: 24px;vertical-align: bottom;}
+.td19{border-right: #000000 1pt solid;border-top: #000000 1pt solid;border-bottom: #000000 1pt solid;text-align: left;padding-left: 7px;padding-right: 0px;width: 311px;vertical-align: bottom;}
+.td20{border-right: #000000 1pt solid;border-bottom: #000000 1pt solid;text-align: left;padding-left: 7px;padding-right: 0px;width: 311px;vertical-align: bottom;}
+.td21{border-right: #000000 1pt solid;text-align: left;padding-left: 7px;padding-right: 0px;width: 311px;vertical-align: bottom;}
+.td22{border-right: #000000 1pt solid;border-bottom: #000000 1pt solid;text-align: left;padding-left: 0px;padding-right: 0px;width: 318px;vertical-align: bottom;}
+.td23{text-align: left;padding-left: 0px;padding-right: 0px;width: 342px;vertical-align: bottom;}
+.td24{text-align: left;padding-left: 0px;padding-right: 0px;width: 265px;vertical-align: bottom;}
+.td25{text-align: left;padding-left: 0px;padding-right: 0px;width: 24px;vertical-align: bottom;}
+.td26{text-align: left;padding-left: 24px;padding-right: 0px;width: 294px;vertical-align: bottom;}
+.td27{border-bottom: #000000 1pt solid;text-align: left;padding-left: 0px;padding-right: 0px;line-height: 17px;width: 318px;vertical-align: bottom;}
+.td28{border-bottom: #000000 1pt solid;text-align: left;padding-left: 0px;padding-right: 0px;line-height: 17px;width: 265px;vertical-align: bottom;}
+
+.tr0{height: 54px;}
+.tr1{height: 19px;}
+.tr2{height: 21px;}
+.tr3{height: 20px;}
+.tr4{height: 41px;}
+.tr5{height: 18px;}
+.tr6{height: 40px;}
+.tr7{height: 55px;}
+.tr8{height: 56px;}
+.tr9{height: 53px;}
+.tr10{height: 74px;}
+.tr11{height: 22px;}
+.tr12{height: 34px;}
+.tr13{height: 89px;}
+
+.t0{width: 387px;margin-left: 26px;margin-top: 5px;font: 13px 'Symbol';line-height: 16px;}
+.t1{width: 582px;margin-left: 26px;margin-top: 51px;font: 16px 'Arial';line-height: 18px;}
+.t2{width: 583px;margin-left: 24px;font: 16px 'Arial';line-height: 18px;}
+.t3{width: 607px;font: 16px 'Arial';line-height: 18px;}
+.t4{width: 583px;font: 16px 'Arial';line-height: 18px;}
+
+</STYLE>
+</HEAD>
+
+<BODY>
+<DIV id="page_1">
+
+<P class="p0"><FONT class="ft0">Couchbase Cluster Health Check Report</FONT></P>
+<P class="p1"><FONT class="ft1">Tool Version: $globals['versions']</FONT></P>
+<P class="p0"><FONT class="ft1">Execution Time: $globals['report_time']</FONT></P>
+<P class="p2"><FONT class="ft2">Overall cluster health: </FONT><FONT class="ft3">$globals.cluster_health</FONT></P>
+<P class="p3"><FONT class="ft4">Section 1 - Couchbase &#8211; Alerts</FONT></P>
+<P class="p4"><FONT class="ft5">Cluster-wide metrics</FONT></P>
+
+<P class="p0"><FONT class="ft2">1. </FONT><FONT class="ft3">Persistence severely behind - Immediate Action Needed</FONT></P>
+<TABLE cellpadding=0 cellspacing=0 class="t0">
+<TR class="tr0">
+ <TD class="td0">&#8226;</TD>
+ <TD class="td1"><FONT class="ft6">Symptom</FONT><FONT class="ft7">o</FONT></TD>
+ <TD class="td2"><FONT class="ft8">1 million items</FONT></TD>
+</TR>
+<TR class="tr1">
+ <TD class="td0">&nbsp;</TD>
+ <TD class="td3"><FONT class="ft9">Disk write queue has reached</FONT></TD>
+ <TD class="td4">&nbsp;</TD>
+</TR>
+</TABLE>
+<P class="p5"><FONT class="ft10">o</FONT><FONT class="ft11">Drain rate has slowed down to</FONT></P>
+<P class="p6"><FONT class="ft12">&#8226;</FONT><FONT class="ft13">Causes - Disk write queue is backed-up, I/O rates unable to sustain write rates</FONT></P>
+<P class="p6"><FONT class="ft12">&#8226;</FONT><FONT class="ft13">Impact - If the node goes down, data will be lost</FONT></P>
+<P class="p6"><FONT class="ft12">&#8226;</FONT><FONT class="ft13">Action -</FONT></P>
+<P class="p4"><FONT class="ft4">Section 2 - Couchbase Cluster Overview</FONT></P>
+<P class="p7"><FONT class="ft14">&#8226; </FONT><FONT class="ft3">Node list</FONT></P>
+<TABLE cellpadding=0 cellspacing=0 class="t1">
+<TR class="tr2">
+ <TD class="td5"><FONT class="ft15">Node IP</FONT></TD>
+ <TD class="td6"><FONT class="ft15">Couchbase Server Version</FONT></TD>
+ <TD class="td7"><FONT class="ft15">Status</FONT></TD>
+</TR>
+#for $node in $node_list["nodeList"]["value"]
+<TR class="tr3">
+ <TD class="td8">$node["ip"]</TD>
+ <TD class="td9">$node["version"]</TD>
+ <TD class="td10">$node["status"]</TD>
+</TR>
+#end for
+</TABLE>
+<P class="p8"><FONT class="ft16">&#8226; </FONT><FONT class="ft17">Total number of nodes in the cluster: $node_list["numNodes"]["value"] </FONT><FONT class="ft18">o </FONT><FONT class="ft17">Number of nodes down: $node_list["numDownNodes"]["value"]</FONT></P>
+<P class="p9"><FONT class="ft19">o </FONT><FONT class="ft20">Number of nodes warming up: $node_list["numWarmupNodes"]["value"] </FONT><FONT class="ft19">o </FONT><FONT class="ft20">Number of nodes failed over: $node_list["numFailedOverNodes"]["value"]</FONT></P>
+</DIV>
+<DIV id="page_2">
+
+<P class="p10"><FONT class="ft5">Cluster-wide metrics</FONT></P>
+<TABLE cellpadding=0 cellspacing=0 class="t2">
+#for $key, $value in $cluster_symptoms.iteritems()
+<TR class="tr4">
+ <TD class="td11">$value["description"]</TD>
+ <TD class="td12">$value["value"]</TD>
+</TR>
+#end for
+</TABLE>
+<P class="p11"><FONT class="ft5">Bucket metrics</FONT></P>
+#for $bucket in $bucket_list
+<P class="p10"><FONT class="ft2">Bucket name: </FONT><FONT class="ft3">$bucket</FONT></P>
+<P class="p12"><FONT class="ft2">Status &#8211; Attention needed</FONT></P>
+<TABLE cellpadding=0 cellspacing=0 class="t3">
+#for $symptom in $bucket_symptoms[$bucket]
+<TR class="tr6">
+ <TD class="td18">&nbsp;</TD>
+ <TD class="td19">$symptom["description"]</TD>
+ <TD class="td12">$symptom["value"]</TD>
+</TR>
+#end for
+#for $node, $node_values in $bucket_node_symptoms[$bucket].iteritems()
+<TR class="tr1">
+ <TD class="td25">&nbsp;</TD>
+ <TD class="td26"><FONT class="ft8">Node-level information</FONT></TD>
+ <TD class="td24">&nbsp;</TD>
+</TR>
+<TR class="tr8">
+ <TD class="td25">&nbsp;</TD>
+ <TD class="td26"><FONT class="ft8">IP address: </FONT>$node</TD>
+ <TD class="td24">&nbsp;</TD>
+</TR>
+<TR class="tr2">
+ <TD class="td25">&nbsp;</TD>
+ <TD class="td26"><FONT class="ft8">Status &#8211; OK</FONT></TD>
+ <TD class="td24">&nbsp;</TD>
+</TR>
+</DIV>
+<DIV id="page_3">
+<TR class="tr5">
+ <TD class="td25">&nbsp;</TD>
+ <TD class="td27">&nbsp;</TD>
+ <TD class="td28">&nbsp;</TD>
+</TR>
+#for $node_value in $node_values
+<TR class="tr3">
+ <TD class="td18">&nbsp;</TD>
+ <TD class="td20">$node_value["description"]</TD>
+ <TD class="td14">$node_value["value"]</TD>
+</TR>
+</DIV>
+</TABLE>
+#end for
+#end for
+<DIV id="page_4">
+#end for
+
+<P class="p13"><FONT class="ft4">Section 3 - Couchbase &#8211; Warning Indicators</FONT></P>
+<P class="p14"><FONT class="ft5">Cluster-wide metrics</FONT></P>
+<P class="p15"><FONT class="ft21">1.</FONT><FONT class="ft22">Replica Resident ratio approaching alert levels</FONT></P>
+<P class="p16"><FONT class="ft12">&#8226;</FONT><FONT class="ft13">Symptom - Replica Resident ratio decreased over 24 hours to </FONT><FONT class="ft2">0.50</FONT></P>
+<P class="p17"><FONT class="ft12">&#8226;</FONT><FONT class="ft13">Cause -</FONT></P>
+<P class="p18"><FONT class="ft23">&#8226;</FONT><FONT class="ft24">Impact - Failing over a node will slow down cluster severely because a backfill from disk will be required and will result in eviction of active items on node)</FONT></P>
+<P class="p17"><FONT class="ft12">&#8226;</FONT><FONT class="ft13">Action -</FONT></P>
+</DIV>
+</body>
+</HTML>
View
10 stats_buffer.py
@@ -1,8 +1,8 @@
buckets_summary = {}
stats_summary = {
- 'vb_active_num' : {},
- 'vb_replica_num' : {},
+ #'vb_active_num' : {},
+ #'vb_replica_num' : {},
}
buckets = {}
@@ -15,6 +15,9 @@
'curr_items' : {},
'vb_replica_curr_items' : {},
'curr_connections' : {},
+ 'vb_active_queue_drain' : {},
+ 'vb_replica_queue_drain' : {},
+ 'disk_write_queue' : {},
},
"hour" : {
'disk_write_queue' : {},
@@ -23,6 +26,9 @@
'ep_oom_errors' : {},
'ep_tmp_oom_errors' : {},
'ep_overhead' : {},
+ 'vb_active_num' : {},
+ 'vb_replica_num' : {},
+ "mem_used" : {},
},
"day" : {
'curr_items' : {},
View
19 util.py
@@ -25,6 +25,25 @@ def linreg(X, Y):
a, b = (Sxy * N - Sy * Sx)/det, (Sxx * Sy - Sx * Sxy)/det
return a, b
+def two_pass_variance(data):
+ n = 0
+ sum1 = 0
+ sum2 = 0
+
+ for x in data:
+ n = n + 1
+ sum1 = sum1 + x
+
+ mean = sum1/n
+
+ for x in data:
+ sum2 = sum2 + (x - mean)*(x - mean)
+ if n <= 1:
+ return 0
+
+ variance = sum2/(n - 1)
+ return variance
+
def pretty_float(number, precision=2):
return '%.*f' % (precision, number)
Please sign in to comment.
Something went wrong with that request. Please try again.