From ff72b730fd1dba5b23d8754a668605639ce50725 Mon Sep 17 00:00:00 2001 From: Alexandre Terrasa Date: Mon, 4 Jul 2016 19:26:29 -0400 Subject: [PATCH] nitweb: introduce metrics API Signed-off-by: Alexandre Terrasa --- src/nitweb.nit | 1 + src/web/api_metrics.nit | 245 +++++++++++++++++++++++++++++++++++++++++++++++ src/web/web.nit | 1 + 3 files changed, 247 insertions(+) create mode 100644 src/web/api_metrics.nit diff --git a/src/nitweb.nit b/src/nitweb.nit index af58044..7c6cdc1 100644 --- a/src/nitweb.nit +++ b/src/nitweb.nit @@ -113,6 +113,7 @@ class APIRouter use("/inheritance/:id", new APIEntityInheritance(model, mainmodule)) use("/graph/", new APIGraphRouter(model, mainmodule)) use("/docdown/", new APIDocdown(model, mainmodule, modelbuilder)) + use("/metrics/", new APIMetricsRouter(model, mainmodule)) end end diff --git a/src/web/api_metrics.nit b/src/web/api_metrics.nit new file mode 100644 index 0000000..30a53f1 --- /dev/null +++ b/src/web/api_metrics.nit @@ -0,0 +1,245 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module api_metrics + +import web_base +import metrics + +# Group all api handlers in one router. +class APIMetricsRouter + super Router + + # Model to pass to handlers. + var model: Model + + # Mainmodule to pass to handlers. + var mainmodule: MModule + + init do + use("/structural/:id", new APIStructuralMetrics(model, mainmodule)) + end +end + +class APIStructuralMetrics + super APIHandler + + private fun mclasses_metrics: MetricSet do + var metrics = new MetricSet + metrics.register(new CNOA(mainmodule, view)) + metrics.register(new CNOP(mainmodule, view)) + metrics.register(new CNOC(mainmodule, view)) + metrics.register(new CNOD(mainmodule, view)) + metrics.register(new CNOAC(mainmodule, view)) + metrics.register(new CNOAA(mainmodule, view)) + metrics.register(new CNOAI(mainmodule, view)) + metrics.register(new CDIT(mainmodule, view)) + metrics.register(new CNBP(mainmodule, view)) + metrics.register(new CNBA(mainmodule, view)) + metrics.register(new CNBM(mainmodule, view)) + metrics.register(new CNBI(mainmodule, view)) + metrics.register(new CNBV(mainmodule, view)) + metrics.register(new CNBIP(mainmodule, view)) + metrics.register(new CNBRP(mainmodule, view)) + metrics.register(new CNBHP(mainmodule, view)) + metrics.register(new CNBLP(mainmodule, view)) + return metrics + end + + private fun mmodules_metrics: MetricSet do + var metrics = new MetricSet + metrics.register(new MNOA(mainmodule, view)) + metrics.register(new MNOP(mainmodule, view)) + metrics.register(new MNOC(mainmodule, view)) + metrics.register(new MNOD(mainmodule, view)) + metrics.register(new MDIT(mainmodule, view)) + metrics.register(new MNBD(mainmodule, view)) + metrics.register(new MNBI(mainmodule, view)) + metrics.register(new MNBR(mainmodule, view)) + metrics.register(new MNBCC(mainmodule, view)) + metrics.register(new MNBAC(mainmodule, view)) + metrics.register(new MNBIC(mainmodule, view)) + return metrics + end + + redef fun get(req, res) do + var mentity = mentity_from_uri(req, res) + if mentity == null then + res.error 404 + return + end + var metrics = mentity.collect_metrics(self) + if metrics == null then + res.error 404 + return + end + res.json metrics + end +end + +redef class MEntity + private fun collect_metrics(h: APIStructuralMetrics): nullable JsonObject do return null +end + +redef class MPackage + redef fun collect_metrics(h) do + var mclasses = new HashSet[MClass] + for mgroup in self.mgroups do + for mmodule in mgroup.mmodules do mclasses.add_all mmodule.intro_mclasses + end + + var mclasses_metrics = h.mclasses_metrics + mclasses_metrics.collect(new HashSet[MClass].from(mclasses)) + + var mmodules = new HashSet[MModule] + for mgroup in self.mgroups do + mmodules.add_all mgroup.mmodules + end + + var mmodules_metrics = h.mmodules_metrics + mmodules_metrics.collect(new HashSet[MModule].from(mmodules)) + + var metrics = new JsonObject + metrics["mclasses"] = mclasses_metrics + metrics["mmodules"] = mmodules_metrics + return metrics + end +end + +redef class MGroup + redef fun collect_metrics(h) do + var mclasses = new HashSet[MClass] + for mmodule in self.mmodules do mclasses.add_all mmodule.intro_mclasses + + var mclasses_metrics = h.mclasses_metrics + mclasses_metrics.collect(new HashSet[MClass].from(mclasses)) + + var mmodules_metrics = h.mmodules_metrics + mmodules_metrics.collect(new HashSet[MModule].from(mmodules)) + + var metrics = new JsonObject + metrics["mclasses"] = mclasses_metrics + metrics["mmodules"] = mmodules_metrics + return metrics + end +end + +redef class MModule + redef fun collect_metrics(h) do + var mclasses_metrics = h.mclasses_metrics + mclasses_metrics.collect(new HashSet[MClass].from(intro_mclasses)) + + var mmodule_metrics = h.mmodules_metrics + mmodule_metrics.collect(new HashSet[MModule].from([self])) + + var metrics = new JsonObject + metrics["mclasses"] = mclasses_metrics + metrics["mmodule"] = mmodule_metrics + return metrics + end +end + +redef class MClass + redef fun collect_metrics(h) do + var mclass_metrics = h.mclasses_metrics + mclass_metrics.collect(new HashSet[MClass].from([self])) + + var metrics = new JsonObject + metrics["mclass"] = mclass_metrics + return metrics + end +end + +redef class MetricSet + super Jsonable + + fun json: JsonObject do + var obj = new JsonObject + for metric in metrics do + obj[metric.name] = metric + end + return obj + end + + redef fun to_json do return json.to_json +end + +redef class Metric + super Jsonable + + fun json: JsonObject do + var obj = new JsonObject + obj["name"] = name + obj["desc"] = desc + obj["empty"] = values.is_empty + if values.not_empty then obj["avg"] = avg + if values.not_empty then obj["std_dev"] = std_dev + if values.not_empty then obj["threshold"] = threshold + return obj + end + + redef fun to_json do return json.to_json +end + +redef class IntMetric + redef fun json do + var obj = super + if values.not_empty then obj["sum"] = sum + return obj + end +end + +redef class FloatMetric + redef fun json do + var obj = super + if values.not_empty then obj["sum"] = sum + return obj + end +end + +redef class MModuleMetric + redef fun json do + var obj = super + if values.not_empty then obj["min"] = min + if values.not_empty then obj["max"] = max + var values = new JsonObject + for value in sort do + var v = self[value] + var vobj = new JsonObject + vobj["mentity"] = value + vobj["value"] = if v isa Jsonable then v else v.to_s + values[value.full_name] = vobj + end + obj["values"] = values + return obj + end +end + +redef class MClassMetric + redef fun json do + var obj = super + if values.not_empty then obj["min"] = min + if values.not_empty then obj["max"] = max + var values = new JsonObject + for value in sort do + var v = self[value] + var vobj = new JsonObject + vobj["mentity"] = value + vobj["value"] = if v isa Jsonable then v else v.to_s + values[value.full_name] = vobj + end + obj["values"] = values + return obj + end +end diff --git a/src/web/web.nit b/src/web/web.nit index c6bb476..63571c0 100644 --- a/src/web/web.nit +++ b/src/web/web.nit @@ -19,4 +19,5 @@ import api_model import api_catalog import api_graph import api_docdown +import api_metrics import api_feedback -- 1.7.9.5