00001 var Emitter = require('events').EventEmitter;
00002 var daqmon = new Emitter();
00003 var net = require('net');
00004
00005 var config = {
00006 durationToStore: 300
00007 }
00008
00009 var database = {
00010 data: {
00011 nodes: [
00012 { name: "EventBuilders", width: 1, lastUpdate: Date.now(), repvalue: 0, unit: "Fragments/s" },
00013 { name: "Data_Logger", width: 1, lastUpdate: Date.now(), repvalue: 0, unit: "Fragments/s" },
00014 { name: "Online_Monitor", width: 1, lastUpdate: Date.now(), repvalue: 0, unit: "Fragments/s" }
00015 ],
00016 links: [
00017 { source: "Data_Logger", target: "Online_Monitor", value: 1 }
00018 ],
00019 metrics: {},
00020 avgFragRate: -1.0,
00021 fragRateCount: 0
00022 }
00023 };
00024 var locked = false;
00025
00026 function checkMetrics() {
00027 var now = Date.now();
00028 var then = now - config.durationToStore * 1000;
00029 for (var h in database.metrics) {
00030 if (database.metrics.hasOwnProperty(h)) {
00031 var metrics = database.metrics[h];
00032 for (var m in metrics) {
00033 if (metrics.hasOwnProperty(m)) {
00034 var metric = metrics[m];
00035 for (var i in metric) {
00036 if (metric.hasOwnProperty(i)) {
00037 if (metric[i].date < then) {
00038 delete database.metrics[h][m][i];
00039 } else {
00040 break;
00041 }
00042 }
00043 }
00044 }
00045 }
00046 }
00047 }
00048 }
00049
00050 function IndexOfSink(sinkName) {
00051 for (var i = 0; i < database.data.links.length; i++) {
00052 if (database.data.links[i].target === sinkName) { return i; }
00053 }
00054 return -1;
00055 }
00056
00057 function IndexOfLink(sourceName) {
00058 for (var i = 0; i < database.data.links.length; i++) {
00059 if (database.data.links[i].source === sourceName) { return i; }
00060 }
00061 return -1;
00062 }
00063
00064 function IndexOfNode(nodeName) {
00065 for (var i = 0; i < database.data.nodes.length; i++) {
00066 if (database.data.nodes[i].name === nodeName) { return i; }
00067 }
00068 return -1;
00069 }
00070
00071 function startGraphiteListener() {
00072 var server = net.createServer(function (socket) {
00073 socket.name = socket.remoteAddress + ":" + socket.remotePort;
00074 console.log("Received Graphite Client connection from " + socket.name);
00075
00076 socket.on('data', function (data) {
00077 locked = true;
00078
00079 var strdata = "" + data;
00080 var mm = strdata.split("\n");
00081 for (var m in mm) {
00082 if (mm.hasOwnProperty(m)) {
00083 var arr = mm[m].trim().split(" ", 3);
00084 if (arr[0] !== undefined && arr[1] !== undefined && arr[2] !== undefined) {
00085 var dotNot = arr[0].split('.');
00086 var appName = dotNot.shift();
00087 var value = parseFloat(arr[1]);
00088 if (dotNot.length > 0 && dotNot[0].search(/^[0-9]*$/) >= 0) {
00089 appName += "." + dotNot.shift();
00090 }
00091 var metricName = "" + dotNot.join('.');
00092 console.log("Application: " + appName + ", Metric: " + metricName + ": " + arr[1] + " at " + arr[2]);
00093 if (database.data.metrics[appName] === undefined) {
00094 database.data.metrics[appName] = {};
00095 }
00096 if (database.data.metrics[appName][metricName] === undefined) {
00097 database.data.metrics[appName][metricName] = [];
00098 }
00099 database.data.metrics[appName][metricName].push({ value: arr[1], date: new Date(arr[2] * 1000) });
00100 var br = appName.search("BoardReader") >= 0;
00101 var eb = appName.search("EventBuilder") >= 0;
00102 var nodeIndex = IndexOfNode(appName);
00103 if (nodeIndex < 0) {
00104 database.data.nodes.push({ name: appName, width: 1, lastUpdate: Date.now(), repvalue: 0, unit: "Fragments/s" });
00105 if (br) {
00106 database.data.links.push({ source: appName, target: "EventBuilders", value: 1 });
00107 }
00108 else if (eb) {
00109 database.data.links.push({ source: "EventBuilders", target: appName, value: 1 });
00110 database.data.links.push({ source: appName, target: "Data_Logger", value: 1 });
00111 }
00112 nodeIndex = IndexOfNode(appName);
00113 }
00114
00115
00116 database.data.nodes[nodeIndex].lastUpdate = Date.now();
00117
00118
00119 if (metricName.search("Data_Rate") >= 0) {
00120
00121 var link = IndexOfLink(appName);
00122
00123 if (link >= 0) {
00124
00125 database.data.links[link].value = value;
00126 }
00127 if (eb) {
00128 var sink = IndexOfSink(appName);
00129 if (sink >= 0) {
00130 database.data.links[sink].value = value;
00131 }
00132 }
00133 }
00134 if (metricName.search("Fragment_Rate") >= 0) {
00135
00136 if (nodeIndex >= 0) {
00137 if (!eb) {
00138 if (database.data.avgFragRate === -1) {
00139 database.data.avgFragRate = value;
00140 database.data.fragRateCount = 1;
00141 } else {
00142 database.data.avgFragRate = (database.data.avgFragRate * database.data.fragRateCount + value) / (database.data.fragRateCount + 1);
00143 database.data.fragRateCount += 1;
00144 }
00145 database.data.nodes[nodeIndex].width = value / database.data.avgFragRate;
00146 database.data.nodes[nodeIndex].repvalue = value;
00147 }
00148 }
00149 }
00150 if (metricName.search("Incomplete_Event_Count") >= 0) {
00151 if (nodeIndex >= 0) {
00152 database.data.nodes[nodeIndex].width = value / database.data.avgFragRate;
00153 database.data.nodes[nodeIndex].repvalue = value;
00154 database.data.nodes[nodeIndex].unit = "Incomplete Events";
00155 }
00156 }
00157 }
00158 }
00159 }
00160 locked = false;
00161 checkMetrics();
00162 daqmon.emit('message', { name: "artdaq-daqmon", target: "data", data: database.data });
00163 });
00164
00165 socket.on('end', function () {
00166 console.log("Graphite Client Disconnected: " + socket.name);
00167 });
00168 });
00169
00170 server.on("error", function (err) {
00171 console.log("artdaq-daqmon listen server error:\n" + err.stack);
00172 server.close();
00173 });
00174
00175 console.log("Binding Server to port 2003 (Graphite Listen)");
00176 server.listen(2003);
00177 }
00178
00179 daqmon.Update = function (workerData) {
00180 if (!locked) {
00181
00182 database = workerData;
00183 }
00184 }
00185
00186 daqmon.GET_Json = function (workerData) {
00187
00188 return JSON.stringify(workerData.data);
00189 }
00190
00191 daqmon.MasterInitFunction = function (workerData) {
00192
00193 workerData["artdaq-daqmon"] = database;
00194 }
00195
00196 daqmon.WorkerInitFunction = function (workerData) {
00197 startGraphiteListener();
00198 return null;
00199 }
00200
00201 module.exports = function (module_holder) {
00202 module_holder["artdaq-daqmon"] = daqmon;
00203 };