@atomist/automation-client
Version:
Atomist API for software low-level client
195 lines • 7.93 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const cluster = require("cluster");
const hot_shots_1 = require("hot-shots");
const os = require("os");
const logger_1 = require("../internal/util/logger");
const shutdown_1 = require("../internal/util/shutdown");
const AutomationEventListener_1 = require("../server/AutomationEventListener");
class StatsdAutomationEventListener extends AutomationEventListener_1.AutomationEventListenerSupport {
constructor(configuration) {
super();
this.configuration = configuration;
this.registrationName = `${this.configuration.name}/${this.configuration.version}`;
this.initStatsd();
}
registrationSuccessful(handler) {
this.increment("counter.registration");
this.event("event.registration", `New registration for ${this.registrationName}`);
}
contextCreated(ctx) {
const context = ctx.context;
const graphClient = ctx.graphClient;
// On the cluster master we don't have a GraphClient
if (graphClient) {
const tags = [
`atomist_operation:${context.operation}`,
`atomist_operation_type:command`,
];
ctx.graphClient = {
endpoint: graphClient.endpoint,
mutate: (optionsOrName) => {
const start = Date.now();
return graphClient.mutate(optionsOrName)
.then(result => {
this.statsd.increment("counter.graphql.mutation.success", 1, 1, tags, this.callback);
this.statsd.timing("timer.graphql.mutation", Date.now() - start, 1, tags, this.callback);
return result;
})
.catch(err => {
this.statsd.increment("counter.graphql.mutation.failure", 1, 1, tags, this.callback);
this.statsd.timing("timer.graphql.mutation", Date.now() - start, 1, tags, this.callback);
return err;
});
},
query: (optionsOrName) => {
const start = Date.now();
return graphClient.query(optionsOrName)
.then(result => {
this.statsd.increment("counter.graphql.query.success", 1, 1, tags, this.callback);
this.statsd.timing("timer.graphql.query", Date.now() - start, 1, tags, this.callback);
return result;
})
.catch(err => {
this.statsd.increment("counter.graphql.query.failure", 1, 1, tags, this.callback);
this.statsd.timing("timer.graphql.query", Date.now() - start, 1, tags, this.callback);
return err;
});
},
};
}
}
commandSuccessful(payload, ctx, result) {
const tags = [
`atomist_operation_type:command`,
];
this.increment("counter.operation.success", tags);
this.timing("timer.operation", ctx, tags);
return Promise.resolve();
}
commandFailed(payload, ctx, err) {
const tags = [
`atomist_operation:${payload.name}`,
`atomist_operation_type:command`,
...this.teamDetail(ctx),
];
this.increment("counter.operation.failure", tags);
this.timing("timer.operation", ctx, tags);
this.event("event.operation.failure", "Unsuccessfully invoked command", tags);
return Promise.resolve();
}
eventSuccessful(payload, ctx, result) {
const tags = [
`atomist_operation_type:event`,
];
this.increment("counter.operation.success", tags);
this.timing("timer.operation", ctx, tags);
return Promise.resolve();
}
eventFailed(payload, ctx, err) {
const tags = [
`atomist_operation:${payload.extensions.operationName}`,
`atomist_operation_type:event`,
...this.teamDetail(ctx),
];
this.increment("counter.operation.failure", tags);
this.timing("timer.operation", ctx, tags);
this.event("event.operation.failure", "Unsuccessfully invoked event", tags);
return Promise.resolve();
}
messageSent(message, destinations, options, ctx) {
let type;
destinations = Array.isArray(destinations) ? destinations : [destinations];
destinations.forEach(d => {
if (d.userAgent === "slack") {
const sd = d;
if (sd.users && sd.users.length > 0) {
type = "slack_users";
}
else if (sd.channels && sd.channels.length > 0) {
type = "slack_channels";
}
else {
type = "slack_response";
}
}
});
this.increment("counter.message", [
`atomist_message_type:${type}`,
...this.teamDetail(ctx),
]);
return Promise.resolve();
}
/** Do-nothing callback */
callback(err) {
return;
}
increment(stat, tags) {
if (cluster.isMaster) {
this.statsd.increment(stat, 1, 1, tags, this.callback);
}
}
event(title, text, tags) {
if (cluster.isMaster) {
this.statsd.event(`automation_client.${title}`, text, {}, tags, this.callback);
}
}
timing(stat, ctx, tags) {
if (cluster.isMaster &&
ctx &&
ctx.context &&
ctx.context.ts) {
const context = ctx.context;
this.statsd.timing(stat, Date.now() - context.ts, 1, tags, this.callback);
}
}
initStatsd() {
const options = {
prefix: "automation_client.",
host: this.configuration.statsd.host || "localhost",
port: this.configuration.statsd.port || 8125,
globalTags: [
`atomist_name:${this.configuration.name.replace("@", "").replace("/", ".")}`,
`atomist_version:${this.configuration.version}`,
`atomist_environment:${this.configuration.environment}`,
`atomist_application_id:${this.configuration.application}`,
`atomist_process_id:${process.pid}`,
`atomist_host:${os.hostname()}`,
],
};
this.statsd = new hot_shots_1.StatsD(options);
this.timer = setInterval(() => {
this.submitHeapStats();
}, 5000);
// Register orderly shutdown
shutdown_1.registerShutdownHook(() => {
this.event("event.shutdown", `Shutting down client ${this.registrationName}`);
this.statsd.close(() => {
logger_1.logger.debug("Closing StatsD connection");
});
return Promise.resolve(0);
});
}
teamDetail(ctx) {
if (ctx && ctx.context) {
const context = ctx.context;
const safeTeamName = context.workspaceName ?
context.workspaceName.trim().replace(/ /g, "_").replace(/\W/g, "") : undefined;
return [
`atomist_team_id:${context.workspaceId}`,
`atomist_team_name:${safeTeamName}`,
];
}
else {
return [];
}
}
submitHeapStats() {
const heap = process.memoryUsage();
this.statsd.gauge("heap.rss", heap.rss, 1, [], this.callback);
this.statsd.gauge("heap.total", heap.heapTotal, 1, [], this.callback);
this.statsd.gauge("heap.used", heap.heapUsed, 1, [], this.callback);
}
}
exports.StatsdAutomationEventListener = StatsdAutomationEventListener;
//# sourceMappingURL=statsd.js.map