diff options
-rw-r--r-- | share/www/script/test/stats.js | 95 | ||||
-rw-r--r-- | src/couchdb/couch_db.erl | 7 | ||||
-rw-r--r-- | src/couchdb/couch_httpd_db.erl | 18 | ||||
-rw-r--r-- | src/couchdb/couch_stats.hrl | 13 | ||||
-rw-r--r-- | src/couchdb/couch_stats_aggregator.erl | 66 |
5 files changed, 117 insertions, 82 deletions
diff --git a/share/www/script/test/stats.js b/share/www/script/test/stats.js index db0c6573..649007dd 100644 --- a/share/www/script/test/stats.js +++ b/share/www/script/test/stats.js @@ -86,40 +86,40 @@ couchTests.stats = function(debug) { } }; - var document_read_count_tests = { - 'should increase read document counter when a document is read': function(name) { + var database_read_count_tests = { + 'should increase database reads counter when a document is read': function(name) { var db = new CouchDB("test_suite_db"); db.deleteDb(); db.createDb(); db.save({"_id":"test"}); - var reads = requestStatsTest("httpd", "document_reads").current; + var reads = requestStatsTest("couchdb", "database_reads").current; db.open("test"); - var new_reads = requestStatsTest("httpd", "document_reads").current; + var new_reads = requestStatsTest("couchdb", "database_reads").current; TEquals(reads + 1 , new_reads, name); }, - 'should not increase read document counter when a non-document is read': function(name) { + 'should not increase database read counter when a non-document is read': function(name) { var db = new CouchDB("test_suite_db"); db.deleteDb(); db.createDb(); db.save({"_id":"test"}); - var reads = requestStatsTest("httpd", "document_reads").current; + var reads = requestStatsTest("couchdb", "database_reads").current; CouchDB.request("GET", "/"); - var new_reads = requestStatsTest("httpd", "document_reads").current; + var new_reads = requestStatsTest("couchdb", "database_reads").current; TEquals(reads, new_reads, name); }, - 'should increase read document counter when a document\'s revisions are read': function(name) { + 'should increase database read counter when a document\'s revisions are read': function(name) { var db = new CouchDB("test_suite_db"); db.deleteDb(); db.createDb(); db.save({"_id":"test"}); - var reads = requestStatsTest("httpd", "document_reads").current; + var reads = requestStatsTest("couchdb", "database_reads").current; db.open("test", {"open_revs":"all"}); - var new_reads = requestStatsTest("httpd", "document_reads").current; + var new_reads = requestStatsTest("couchdb", "database_reads").current; TEquals(reads + 1 , new_reads, name); } @@ -208,18 +208,18 @@ couchTests.stats = function(debug) { }; var document_write_count_tests = { - 'should increment counter for document creates': function(name) { + 'should increment database changes counter for document creates': function(name) { var db = new CouchDB("test_suite_db"); db.deleteDb(); db.createDb(); - var creates = requestStatsTest("httpd", "document_creates").current; + var creates = requestStatsTest("couchdb", "database_changes").current; db.save({"a":"1"}); - var new_creates = requestStatsTest("httpd", "document_creates").current; + var new_creates = requestStatsTest("couchdb", "database_changes").current; TEquals(creates + 1, new_creates, name); }, - 'should not increment counter for document creates when updating a doc': function(name) { + 'should increment database changes counter for document updates': function(name) { var db = new CouchDB("test_suite_db"); db.deleteDb(); db.createDb(); @@ -227,38 +227,13 @@ couchTests.stats = function(debug) { var doc = {"_id":"test"}; db.save(doc); - var creates = requestStatsTest("httpd", "document_creates").current; + var updates = requestStatsTest("couchdb", "database_changes").current; db.save(doc); - var new_creates = requestStatsTest("httpd", "document_creates").current; - - TEquals(creates, new_creates, name); - }, - 'should increment counter for document updates': function(name) { - var db = new CouchDB("test_suite_db"); - db.deleteDb(); - db.createDb(); - - var doc = {"_id":"test"}; - db.save(doc); - - var updates = requestStatsTest("httpd", "document_updates").current; - db.save(doc); - var new_updates = requestStatsTest("httpd", "document_updates").current; + var new_updates = requestStatsTest("couchdb", "database_changes").current; TEquals(updates + 1, new_updates, name); }, - 'should not increment counter for document updates when creating a document': function(name) { - var db = new CouchDB("test_suite_db"); - db.deleteDb(); - db.createDb(); - - var updates = requestStatsTest("httpd", "document_updates").current; - db.save({"a":"1"}); - var new_updates = requestStatsTest("httpd", "document_updates").current; - - TEquals(updates, new_updates, name); - }, - 'should increment counter for document deletes': function(name) { + 'should increment database changes counter for document deletes': function(name) { var db = new CouchDB("test_suite_db"); db.deleteDb(); db.createDb(); @@ -266,13 +241,13 @@ couchTests.stats = function(debug) { var doc = {"_id":"test"}; db.save(doc); - var deletes = requestStatsTest("httpd", "document_deletes").current; + var deletes = requestStatsTest("couchdb", "database_changes").current; db.deleteDoc(doc); - var new_deletes = requestStatsTest("httpd", "document_deletes").current; + var new_deletes = requestStatsTest("couchdb", "database_changes").current; TEquals(deletes + 1, new_deletes, name); }, - 'should increment the copy counter': function(name) { + 'should increment database changes counter for document copies': function(name) { var db = new CouchDB("test_suite_db"); db.deleteDb(); db.createDb(); @@ -280,15 +255,15 @@ couchTests.stats = function(debug) { var doc = {"_id":"test"}; db.save(doc); - var copies = requestStatsTest("httpd", "document_copies").current; + var copies = requestStatsTest("couchdb", "database_changes").current; CouchDB.request("COPY", "/test_suite_db/test", { headers: {"Destination":"copy_of_test"} }); - var new_copies = requestStatsTest("httpd", "document_copies").current; + var new_copies = requestStatsTest("couchdb", "database_changes").current; TEquals(copies + 1, new_copies, name); }, - 'should increment the move counter': function(name) { + 'should increment database changes counter for document moves': function(name) { var db = new CouchDB("test_suite_db"); db.deleteDb(); db.createDb(); @@ -296,11 +271,11 @@ couchTests.stats = function(debug) { var doc = {"_id":"test"}; db.save(doc); - var moves = requestStatsTest("httpd", "document_moves").current; + var moves = requestStatsTest("couchdb", "database_changes").current; CouchDB.request("MOVE", "/test_suite_db/test?rev=" + doc._rev, { headers: {"Destination":"move_of_test"} }); - var new_moves = requestStatsTest("httpd", "document_moves").current; + var new_moves = requestStatsTest("couchdb", "database_changes").current; TEquals(moves + 1, new_moves, name); }, @@ -318,31 +293,31 @@ couchTests.stats = function(debug) { TEquals(bulks + 1, new_bulks, name); }, - 'should increment counter for document creates using POST': function(name) { + 'should increment database changes counter for document creates using POST': function(name) { var db = new CouchDB("test_suite_db"); db.deleteDb(); db.createDb(); - var creates = requestStatsTest("httpd", "document_creates").current; + var creates = requestStatsTest("couchdb", "database_changes").current; CouchDB.request("POST", "/test_suite_db", {body:'{"a":"1"}'}); - var new_creates = requestStatsTest("httpd", "document_creates").current; + var new_creates = requestStatsTest("couchdb", "database_changes").current; TEquals(creates + 1, new_creates, name); }, - 'should increment document create counter when adding attachment': function(name) { + 'should increment database changes counter when adding attachment': function(name) { var db = new CouchDB("test_suite_db"); db.deleteDb(); db.createDb(); - var creates = requestStatsTest("httpd", "document_creates").current; + var creates = requestStatsTest("couchdb", "database_changes").current; CouchDB.request("PUT", "/test_suite_db/bin_doc2/foo2.txt", { body:"This is no base64 encoded text", headers:{"Content-Type": "text/plain;charset=utf-8"} }); - var new_creates = requestStatsTest("httpd", "document_creates").current; + var new_creates = requestStatsTest("couchdb", "database_changes").current; TEquals(creates + 1, new_creates, name); }, - 'should increment document update counter when adding attachment to existing doc': function(name) { + 'should increment database changes counter when adding attachment to existing doc': function(name) { var db = new CouchDB("test_suite_db"); db.deleteDb(); db.createDb(); @@ -350,12 +325,12 @@ couchTests.stats = function(debug) { var doc = {_id:"test"}; db.save(doc); - var updates = requestStatsTest("httpd", "document_updates").current; + var updates = requestStatsTest("couchdb", "database_changes").current; CouchDB.request("PUT", "/test_suite_db/test/foo2.txt?rev=" + doc._rev, { body:"This is no base64 encoded text", headers:{"Content-Type": "text/plain;charset=utf-8"} }); - var new_updates = requestStatsTest("httpd", "document_updates").current; + var new_updates = requestStatsTest("couchdb", "database_changes").current; TEquals(updates + 1, new_updates, name); } @@ -428,7 +403,7 @@ couchTests.stats = function(debug) { var tests = [ open_databases_tests, request_count_tests, - document_read_count_tests, + database_read_count_tests, view_read_count_tests, http_requests_by_method_tests, document_write_count_tests, diff --git a/src/couchdb/couch_db.erl b/src/couchdb/couch_db.erl index d9caa36f..963c834b 100644 --- a/src/couchdb/couch_db.erl +++ b/src/couchdb/couch_db.erl @@ -92,6 +92,7 @@ open_doc(Db, IdOrDocInfo) -> open_doc(Db, IdOrDocInfo, []). open_doc(Db, Id, Options) -> + couch_stats_collector:increment({couchdb, database_reads}), case open_doc_int(Db, Id, Options) of {ok, #doc{deleted=true}=Doc} -> case lists:member(deleted, Options) of @@ -105,6 +106,7 @@ open_doc(Db, Id, Options) -> end. open_doc_revs(Db, Id, Revs, Options) -> + couch_stats_collector:increment({couchdb, database_reads}), [Result] = open_doc_revs_int(Db, [{Id, Revs}], Options), Result. @@ -284,6 +286,7 @@ update_docs(#db{update_pid=UpdatePid}=Db, Docs, Options) -> update_docs(#db{update_pid=UpdatePid}=Db, Docs, Options, true). update_docs(Db, Docs, Options, false) -> + couch_stats_collector:increment({couchdb, database_changes}), DocBuckets = group_alike_docs(Docs), Ids = [Id || [#doc{id=Id}|_] <- DocBuckets], @@ -320,7 +323,9 @@ update_docs(Db, Docs, Options, false) -> write_and_commit(Db, DocBuckets2, Options); update_docs(Db, Docs, Options, true) -> - % go ahead and generate the new revision ids for the documents. + couch_stats_collector:increment({couchdb, database_changes}), + + % go ahead and generate the new revision ids for the documents. Docs2 = lists:map( fun(#doc{id=Id,revs=Revs}=Doc) -> case Id of diff --git a/src/couchdb/couch_httpd_db.erl b/src/couchdb/couch_httpd_db.erl index 78339911..53eff650 100644 --- a/src/couchdb/couch_httpd_db.erl +++ b/src/couchdb/couch_httpd_db.erl @@ -80,7 +80,7 @@ db_req(#httpd{method='POST',path_parts=[DbName]}=Req, Db) -> Doc = couch_doc:from_json_obj(couch_httpd:json_body(Req)), DocId = couch_util:new_uuid(), {ok, NewRev} = couch_db:update_doc(Db, Doc#doc{id=DocId, revs=[]}, []), - couch_stats_collector:increment({httpd, document_creates}), + % couch_stats_collector:increment({httpd, document_creates}), DocUrl = absolute_uri(Req, binary_to_list(<<"/",DbName/binary,"/",DocId/binary>>)), send_json(Req, 201, [{"Location", DocUrl}], {[ @@ -379,7 +379,7 @@ db_doc_req(#httpd{method='DELETE'}=Req, Db, DocId) -> couch_httpd:send_error(Req, 409, <<"missing_rev">>, <<"Document rev/etag must be specified to delete">>); RevToDelete -> - couch_stats_collector:increment({httpd, document_deletes}), + % couch_stats_collector:increment({httpd, document_deletes}), {ok, NewRev} = couch_db:delete_doc(Db, DocId, [RevToDelete]), send_json(Req, 200, {[ {ok, true}, @@ -394,7 +394,7 @@ db_doc_req(#httpd{method='GET'}=Req, Db, DocId) -> open_revs = Revs, options = Options } = parse_doc_query(Req), - couch_stats_collector:increment({httpd, document_reads}), + % couch_stats_collector:increment({httpd, document_reads}), case Revs of [] -> Doc = couch_doc_open(Db, DocId, Rev, Options), @@ -471,10 +471,10 @@ db_doc_req(#httpd{method='PUT'}=Req, Db, DocId) -> end, case extract_header_rev(Req, ExplicitRev) of missing_rev -> - couch_stats_collector:increment({httpd, document_creates}), + % couch_stats_collector:increment({httpd, document_creates}), Revs = []; Rev -> - couch_stats_collector:increment({httpd, document_updates}), + % couch_stats_collector:increment({httpd, document_updates}), Revs = [Rev] end, {ok, NewRev} = couch_db:update_doc(Db, Doc#doc{id=DocId, revs=Revs}, Options), @@ -498,7 +498,7 @@ db_doc_req(#httpd{method='COPY'}=Req, Db, SourceDocId) -> % save new doc {ok, NewTargetRev} = couch_db:update_doc(Db, Doc#doc{id=TargetDocId, revs=TargetRev}, []), - couch_stats_collector:increment({httpd, document_copies}), + % couch_stats_collector:increment({httpd, document_copies}), send_json(Req, 201, [{"Etag", "\"" ++ binary_to_list(NewTargetRev) ++ "\""}], {[ {ok, true}, @@ -525,7 +525,7 @@ db_doc_req(#httpd{method='MOVE'}=Req, Db, SourceDocId) -> #doc{id=SourceDocId, revs=[SourceRev], deleted=true} ], {ok, ResultRevs} = couch_db:update_docs(Db, Docs, []), - couch_stats_collector:increment({httpd, document_moves}), + % couch_stats_collector:increment({httpd, document_moves}), DocResults = lists:zipwith( fun(FDoc, NewRev) -> @@ -629,10 +629,10 @@ db_attachment_req(#httpd{method=Method}=Req, Db, DocId, FileNameParts) Doc = case extract_header_rev(Req, couch_httpd:qs_value(Req, "rev")) of missing_rev -> % make the new doc - couch_stats_collector:increment({httpd, document_creates}), + % couch_stats_collector:increment({httpd, document_creates}), #doc{id=DocId}; Rev -> - couch_stats_collector:increment({httpd, document_updates}), + % couch_stats_collector:increment({httpd, document_updates}), case couch_db:open_doc_revs(Db, DocId, [Rev], []) of {ok, [{ok, Doc0}]} -> Doc0#doc{revs=[Rev]}; {ok, [Error]} -> throw(Error) diff --git a/src/couchdb/couch_stats.hrl b/src/couchdb/couch_stats.hrl index 7b51aa0c..47a9a86f 100644 --- a/src/couchdb/couch_stats.hrl +++ b/src/couchdb/couch_stats.hrl @@ -11,11 +11,12 @@ % the License. -record(aggregates, { - min=0, - max=0, - mean=0.0, + min = 0, + max = 0, + mean = 0.0, variance = 0.0, - stddev=0.0, - count=0, - last=0 + stddev = 0.0, + count = 0, + last = 0, + description }). diff --git a/src/couchdb/couch_stats_aggregator.erl b/src/couchdb/couch_stats_aggregator.erl index 3d3db0ef..2a1e5797 100644 --- a/src/couchdb/couch_stats_aggregator.erl +++ b/src/couchdb/couch_stats_aggregator.erl @@ -23,7 +23,8 @@ time_passed/0, clear_aggregates/1]). -record(state, { - aggregates = [] + aggregates = [], + descriptions = [] }). -define(COLLECTOR, couch_stats_collector). @@ -61,6 +62,7 @@ all() -> init(_) -> ets:new(?MODULE, [named_table, set, protected]), init_timers(), + init_descriptions(), {ok, #state{}}. handle_call({get, Key}, _, State) -> @@ -141,8 +143,8 @@ do_clear_aggregates(Time, #state{aggregates=Stats}) -> end, Stats), #state{aggregates=NewStats}. -%% default Time is 0, which is when CouchDB started get_aggregate(Key, State) -> + %% default Time is 0, which is when CouchDB started get_aggregate(Key, State, '0'). get_aggregate(Key, #state{aggregates=StatsList}, Time) -> Aggregates = case proplists:lookup(Key, StatsList) of @@ -151,11 +153,17 @@ get_aggregate(Key, #state{aggregates=StatsList}, Time) -> {Key, Stats} -> case proplists:lookup(Time, Stats) of none -> #aggregates{}; % empty record again - {Time, Stat} -> Stat + {Time, Stat} -> Stat#aggregates{description=get_description(Key)} end end, Aggregates. +get_description(Key) -> + case ets:lookup(?MODULE, Key) of + [] -> <<"No description yet.">>; + [{_Key, Description}] -> Description + end. + %% updates all aggregates for Key update_aggregates_loop(Key, Values, State, CounterType) -> #state{aggregates=AllStats} = State, @@ -193,7 +201,9 @@ update_aggregates_loop(Key, Values, State, CounterType) -> % put the newly calculated aggregates into State and delete the previous % entry - #state{aggregates=[{Key, NewStats} | proplists:delete(Key, AllStats)]}. + #state{ + aggregates=[{Key, NewStats} | proplists:delete(Key, AllStats)] + }. % does the actual updating of the aggregate record update_aggregates(Value, Stat, CounterType) -> @@ -241,7 +251,7 @@ update_aggregates(Value, Stat, CounterType) -> end. -aggregate_to_json_term(#aggregates{min=Min,max=Max,mean=Mean,stddev=Stddev,count=Count,last=Last}) -> +aggregate_to_json_term(#aggregates{min=Min,max=Max,mean=Mean,stddev=Stddev,count=Count,last=Last,description=Description}) -> {[ % current is redundant, but reads nicer in JSON {current, Last}, @@ -250,7 +260,8 @@ aggregate_to_json_term(#aggregates{min=Min,max=Max,mean=Mean,stddev=Stddev,count {min, Min}, {max, Max}, {stddev, Stddev}, - {resolution, 1} + {resolution, 1}, + {description, Description} ]}. get_stats(Key, State) -> @@ -275,6 +286,49 @@ do_get_all(#state{aggregates=Stats}=State) -> {[{LastMod, {lists:sort(LastVals)}} | LastRestMods]} end. + +init_descriptions() -> + + % ets is probably overkill here, but I didn't manage to keep the + % descriptions in the gen_server state. Which means there is probably + % a bug in one of the handle_call() functions most likely the one that + % handles the time_passed message. But don't tell anyone, the math is + % correct :) -- Jan + + % please keep this in alphabetical order + ets:insert(?MODULE, {{couchdb, database_changes}, <<"Number of times a database was changed">>}), + ets:insert(?MODULE, {{couchdb, database_reads}, <<"Number of times a document was read from a database">>}), + ets:insert(?MODULE, {{couchdb, open_databases}, <<"Number of open databases">>}), + ets:insert(?MODULE, {{couchdb, request_time}, <<"Length of a request inside CouchDB without Mochiweb">>}), + + ets:insert(?MODULE, {{http_status_codes, '200'}, <<"Number of HTTP 200 OK responses">>}), + ets:insert(?MODULE, {{http_status_codes, '201'}, <<"Number of HTTP 201 Created responses">>}), + ets:insert(?MODULE, {{http_status_codes, '202'}, <<"Number of HTTP 202 Accepted responses">>}), + ets:insert(?MODULE, {{http_status_codes, '301'}, <<"Number of HTTP 301 Moved Permanently responses">>}), + ets:insert(?MODULE, {{http_status_codes, '304'}, <<"Number of HTTP 304 Not Modified responses">>}), + ets:insert(?MODULE, {{http_status_codes, '400'}, <<"Number of HTTP 400 Bad Request responses">>}), + ets:insert(?MODULE, {{http_status_codes, '401'}, <<"Number of HTTP 401 Unauthorized responses">>}), + ets:insert(?MODULE, {{http_status_codes, '403'}, <<"Number of HTTP 403 Forbidden responses">>}), + ets:insert(?MODULE, {{http_status_codes, '404'}, <<"Number of HTTP 404 Not Found responses">>}), + ets:insert(?MODULE, {{http_status_codes, '405'}, <<"Number of HTTP 405 Method Not Allowed responses">>}), + ets:insert(?MODULE, {{http_status_codes, '409'}, <<"Number of HTTP 409 Conflict responses">>}), + ets:insert(?MODULE, {{http_status_codes, '412'}, <<"Number of HTTP 412 Precondition Failed responses">>}), + ets:insert(?MODULE, {{http_status_codes, '500'}, <<"Number of HTTP 500 Internal Server Error responses">>}), + + ets:insert(?MODULE, {{httpd, bulk_requests}, <<"Number of bulk requests">>}), + ets:insert(?MODULE, {{httpd, copy_requests}, <<"Number of HTTP COPY requests">>}), + ets:insert(?MODULE, {{httpd, delete_requests}, <<"Number of HTTP DELETE requests">>}), + ets:insert(?MODULE, {{httpd, get_requests}, <<"Number of HTTP GET requests">>}), + ets:insert(?MODULE, {{httpd, head_requests}, <<"Number of HTTP HEAD requests">>}), + ets:insert(?MODULE, {{httpd, move_requests}, <<"Number of HTTP MOVE requests">>}), + ets:insert(?MODULE, {{httpd, post_requests}, <<"Number of HTTP POST requests">>}), + ets:insert(?MODULE, {{httpd, requests}, <<"Number of HTTP requests">>}), + ets:insert(?MODULE, {{httpd, temporary_view_reads}, <<"Number of temporary view reads">>}), + ets:insert(?MODULE, {{httpd, view_reads}, <<"Number of view reads">>}), + ets:insert(?MODULE, {{httpd, put_requests}, <<"Number of HTTP PUT requests">>}). + % please keep this in alphabetical order + + % Timer init_timers() -> |