UNPKG

12.8 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const cluster = require("cluster");
4const hot_shots_1 = require("hot-shots");
5const os = require("os");
6const trace = require("stack-trace");
7const internalGraphql = require("../internal/graph/graphQL");
8const logger_1 = require("../internal/util/logger");
9const shutdown_1 = require("../internal/util/shutdown");
10const AutomationEventListener_1 = require("../server/AutomationEventListener");
11class StatsdAutomationEventListener extends AutomationEventListener_1.AutomationEventListenerSupport {
12 constructor(configuration) {
13 super();
14 this.configuration = configuration;
15 this.registrationName = `${this.configuration.name}/${this.configuration.version}`;
16 this.initStatsd();
17 }
18 registrationSuccessful(handler) {
19 this.increment("counter.registration");
20 this.event("event.registration", `New registration for ${this.registrationName}`);
21 }
22 contextCreated(ctx) {
23 const context = ctx.context;
24 const graphClient = ctx.graphClient;
25 // On the cluster master we don't have a GraphClient
26 if (graphClient) {
27 const tags = [
28 `atomist_operation:${context.operation}`,
29 `atomist_operation_type:command`,
30 ...this.teamDetail(ctx),
31 ];
32 ctx.graphClient = {
33 endpoint: graphClient.endpoint,
34 executeMutation: (mutation, variables, options) => {
35 const start = Date.now();
36 return graphClient.executeMutation(mutation, variables, options)
37 .then(result => {
38 this.statsd.increment("counter.graphql.mutation.success", 1, 1, tags, this.callback);
39 this.statsd.timing("timer.graphql.mutation", Date.now() - start, 1, tags, this.callback);
40 return result;
41 })
42 .catch(err => {
43 this.statsd.increment("counter.graphql.mutation.failure", 1, 1, tags, this.callback);
44 this.statsd.timing("timer.graphql.mutation", Date.now() - start, 1, tags, this.callback);
45 return err;
46 });
47 },
48 executeMutationFromFile: (path, variables, options, current) => {
49 const start = Date.now();
50 return graphClient.executeMutationFromFile(path, variables, options, current)
51 .then(result => {
52 this.statsd.increment("counter.graphql.mutation.success", 1, 1, tags, this.callback);
53 this.statsd.timing("timer.graphql.mutation", Date.now() - start, 1, tags, this.callback);
54 return result;
55 })
56 .catch(err => {
57 this.statsd.increment("counter.graphql.mutation.failure", 1, 1, tags, this.callback);
58 this.statsd.timing("timer.graphql.mutation", Date.now() - start, 1, tags, this.callback);
59 return err;
60 });
61 },
62 mutate: (optionsOrName) => {
63 const start = Date.now();
64 if (typeof optionsOrName === "string") {
65 optionsOrName = {
66 name: optionsOrName,
67 };
68 }
69 const m = internalGraphql.mutate({
70 mutation: optionsOrName.mutation,
71 path: optionsOrName.path,
72 name: optionsOrName.name,
73 moduleDir: trace.get()[1].getFileName(),
74 });
75 return graphClient.executeMutation(m, optionsOrName.variables, optionsOrName.options)
76 .then(result => {
77 this.statsd.increment("counter.graphql.mutation.success", 1, 1, tags, this.callback);
78 this.statsd.timing("timer.graphql.mutation", Date.now() - start, 1, tags, this.callback);
79 return result;
80 })
81 .catch(err => {
82 this.statsd.increment("counter.graphql.mutation.failure", 1, 1, tags, this.callback);
83 this.statsd.timing("timer.graphql.mutation", Date.now() - start, 1, tags, this.callback);
84 return err;
85 });
86 },
87 executeQuery: (query, variables, options) => {
88 const start = Date.now();
89 return graphClient.executeQuery(query, variables, options)
90 .then(result => {
91 this.statsd.increment("counter.graphql.query.success", 1, 1, tags, this.callback);
92 this.statsd.timing("timer.graphql.query", Date.now() - start, 1, tags, this.callback);
93 return result;
94 })
95 .catch(err => {
96 this.statsd.increment("counter.graphql.query.failure", 1, 1, tags, this.callback);
97 this.statsd.timing("timer.graphql.query", Date.now() - start, 1, tags, this.callback);
98 return err;
99 });
100 },
101 executeQueryFromFile: (path, variables, options, current) => {
102 const start = Date.now();
103 return graphClient.executeQueryFromFile(path, variables, options, current)
104 .then(result => {
105 this.statsd.increment("counter.graphql.query.success", 1, 1, tags, this.callback);
106 this.statsd.timing("timer.graphql.query", Date.now() - start, 1, tags, this.callback);
107 return result;
108 })
109 .catch(err => {
110 this.statsd.increment("counter.graphql.query.failure", 1, 1, tags, this.callback);
111 this.statsd.timing("timer.graphql.query", Date.now() - start, 1, tags, this.callback);
112 return err;
113 });
114 },
115 query: (optionsOrName) => {
116 const start = Date.now();
117 if (typeof optionsOrName === "string") {
118 optionsOrName = {
119 name: optionsOrName,
120 };
121 }
122 const q = internalGraphql.query({
123 query: optionsOrName.query,
124 path: optionsOrName.path,
125 name: optionsOrName.name,
126 moduleDir: trace.get()[1].getFileName(),
127 });
128 return graphClient.executeQuery(q, optionsOrName.variables, optionsOrName.options)
129 .then(result => {
130 this.statsd.increment("counter.graphql.query.success", 1, 1, tags, this.callback);
131 this.statsd.timing("timer.graphql.query", Date.now() - start, 1, tags, this.callback);
132 return result;
133 })
134 .catch(err => {
135 this.statsd.increment("counter.graphql.query.failure", 1, 1, tags, this.callback);
136 this.statsd.timing("timer.graphql.query", Date.now() - start, 1, tags, this.callback);
137 return err;
138 });
139 },
140 };
141 }
142 }
143 commandSuccessful(payload, ctx, result) {
144 const tags = [
145 `atomist_operation:${payload.name}`,
146 `atomist_operation_type:command`,
147 ...this.teamDetail(ctx),
148 ];
149 this.increment("counter.operation.success", tags);
150 this.timing("timer.operation", ctx, tags);
151 return Promise.resolve();
152 }
153 commandFailed(payload, ctx, err) {
154 const tags = [
155 `atomist_operation:${payload.name}`,
156 `atomist_operation_type:command`,
157 ...this.teamDetail(ctx),
158 ];
159 this.increment("counter.operation.failure", tags);
160 this.timing("timer.operation", ctx, tags);
161 this.event("event.operation.failure", "Unsuccessfully invoked command", tags);
162 return Promise.resolve();
163 }
164 eventSuccessful(payload, ctx, result) {
165 const tags = [
166 `atomist_operation:${payload.extensions.operationName}`,
167 `atomist_operation_type:event`,
168 ...this.teamDetail(ctx),
169 ];
170 this.increment("counter.operation.success", tags);
171 this.timing("timer.operation", ctx, tags);
172 return Promise.resolve();
173 }
174 eventFailed(payload, ctx, err) {
175 const tags = [
176 `atomist_operation:${payload.extensions.operationName}`,
177 `atomist_operation_type:event`,
178 ...this.teamDetail(ctx),
179 ];
180 this.increment("counter.operation.failure", tags);
181 this.timing("timer.operation", ctx, tags);
182 this.event("event.operation.failure", "Unsuccessfully invoked event", tags);
183 return Promise.resolve();
184 }
185 messageSent(message, destinations, options, ctx) {
186 let type;
187 destinations = Array.isArray(destinations) ? destinations : [destinations];
188 destinations.forEach(d => {
189 if (d.userAgent === "slack") {
190 const sd = d;
191 if (sd.users && sd.users.length > 0) {
192 type = "slack_users";
193 }
194 else if (sd.channels && sd.channels.length > 0) {
195 type = "slack_channels";
196 }
197 else {
198 type = "slack_response";
199 }
200 }
201 });
202 this.increment("counter.message", [
203 `atomist_message_type:${type}`,
204 ...this.teamDetail(ctx),
205 ]);
206 return Promise.resolve();
207 }
208 /** Do-nothing callback */
209 callback(err) {
210 return;
211 }
212 increment(stat, tags) {
213 if (cluster.isMaster) {
214 this.statsd.increment(stat, 1, 1, tags, this.callback);
215 }
216 }
217 event(title, text, tags) {
218 if (cluster.isMaster) {
219 this.statsd.event(`automation_client.${title}`, text, {}, tags, this.callback);
220 }
221 }
222 timing(stat, ctx, tags) {
223 if (cluster.isMaster &&
224 ctx &&
225 ctx.context &&
226 ctx.context.ts) {
227 const context = ctx.context;
228 this.statsd.timing(stat, Date.now() - context.ts, 1, tags, this.callback);
229 }
230 }
231 initStatsd() {
232 const options = {
233 prefix: "automation_client.",
234 host: this.configuration.statsd.host || "localhost",
235 port: this.configuration.statsd.port || 8125,
236 globalTags: [
237 `atomist_name:${this.configuration.name.replace("@", "").replace("/", ".")}`,
238 `atomist_version:${this.configuration.version}`,
239 `atomist_environment:${this.configuration.environment}`,
240 `atomist_application_id:${this.configuration.application}`,
241 `atomist_process_id:${process.pid}`,
242 `atomist_host:${os.hostname()}`,
243 ],
244 };
245 this.statsd = new hot_shots_1.StatsD(options);
246 this.timer = setInterval(() => {
247 this.submitHeapStats();
248 }, 5000);
249 // Register orderly shutdown
250 shutdown_1.registerShutdownHook(() => {
251 this.event("event.shutdown", `Shutting down client ${this.registrationName}`);
252 this.statsd.close(() => {
253 logger_1.logger.debug("Closing StatsD connection");
254 });
255 return Promise.resolve(0);
256 });
257 }
258 teamDetail(ctx) {
259 if (ctx && ctx.context) {
260 const context = ctx.context;
261 const safeTeamName = context.workspaceName ?
262 context.workspaceName.trim().replace(/ /g, "_").replace(/\W/g, "") : undefined;
263 return [
264 `atomist_team_id:${context.workspaceId}`,
265 `atomist_team_name:${safeTeamName}`,
266 ];
267 }
268 else {
269 return [];
270 }
271 }
272 submitHeapStats() {
273 const heap = process.memoryUsage();
274 this.statsd.gauge("heap.rss", heap.rss, 1, [], this.callback);
275 this.statsd.gauge("heap.total", heap.heapTotal, 1, [], this.callback);
276 this.statsd.gauge("heap.used", heap.heapUsed, 1, [], this.callback);
277 }
278}
279exports.StatsdAutomationEventListener = StatsdAutomationEventListener;
280//# sourceMappingURL=statsd.js.map
\No newline at end of file