Skip to content

Commit 9c478c6

Browse files
committed
Merge branch 'headless' of https://github.com/sjanuary/appmetrics into headless
2 parents b33812a + 749a2ed commit 9c478c6

File tree

6 files changed

+223
-1
lines changed

6 files changed

+223
-1
lines changed

binding.gyp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
"target_name": "appmetrics",
6868
"sources": [
6969
"<(INTERMEDIATE_DIR)/appmetrics.cpp",
70+
"<(srcdir)/headlessutils.cpp",
7071
"<(srcdir)/objecttracker.cpp",
7172
],
7273
'variables': {
@@ -156,6 +157,7 @@
156157
"<(agentcoredir)/plugins/<(SHARED_LIB_PREFIX)envplugin<(SHARED_LIB_SUFFIX)",
157158
"<(agentcoredir)/plugins/<(SHARED_LIB_PREFIX)memoryplugin<(SHARED_LIB_SUFFIX)",
158159
"<(agentcoredir)/plugins/<(SHARED_LIB_PREFIX)hcapiplugin<(SHARED_LIB_SUFFIX)",
160+
"<(agentcoredir)/plugins/<(SHARED_LIB_PREFIX)headlessplugin<(SHARED_LIB_SUFFIX)",
159161
],
160162
},
161163
],

headless_zip.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*******************************************************************************
2+
* Copyright 2016 IBM Corp.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*******************************************************************************/
16+
17+
var fstream = require('fstream')
18+
var tar = require('tar')
19+
var zlib = require('zlib')
20+
var fs = require('fs')
21+
var path = require('path')
22+
23+
var dirToWriteTo;
24+
25+
function onError(err) {
26+
console.error('Headless Zip: an error occurred:', err)
27+
}
28+
29+
function deleteDir(directory) {
30+
// Delete temporary directory
31+
if(fs.existsSync(directory)) {
32+
fs.readdirSync(directory).forEach(function(file,index){
33+
var fileName = path.join(directory, file)
34+
fs.unlinkSync(fileName)
35+
})
36+
fs.rmdirSync(directory);
37+
}
38+
}
39+
40+
module.exports.setHeadlessOutputDir = function setHeadlessOutputDir(dir) {
41+
dirToWriteTo = dir;
42+
}
43+
44+
function timestamp() {
45+
var date = new Date(Date.now())
46+
var timestamp = pad(date.getDate().toString()) + pad(date.getMonth().toString()) + date.getFullYear().toString().substr(2,3) + '_'
47+
+ pad(date.getHours().toString()) + pad(date.getMinutes().toString()) + pad(date.getSeconds().toString()) + '_'
48+
+ process.pid
49+
return timestamp
50+
}
51+
52+
function pad(numberString) {
53+
// pads a single digit number with a leading 0
54+
if(numberString.length == 1) {
55+
return '0' + numberString
56+
}
57+
return numberString
58+
}
59+
60+
module.exports.headlessZip = function headlessZip(dirToZip) {
61+
var outputFileName;
62+
if(dirToWriteTo) {
63+
outputFileName = path.join(dirToWriteTo, 'nodeappmetrics' + timestamp() + '.hcd')
64+
} else {
65+
outputFileName = 'nodeappmetrics' + timestamp() + '.hcd'
66+
}
67+
68+
var packer = tar.Pack({ fromBase: true })
69+
.on('error', onError)
70+
var zipper = zlib.Gzip()
71+
var writer = fstream.Writer({'path': outputFileName})
72+
.on('error', onError)
73+
.on('close', function() {
74+
deleteDir(dirToZip)
75+
})
76+
77+
fstream.Reader({'path': dirToZip, 'type': 'Directory'})
78+
.on('error', onError)
79+
.pipe(packer)
80+
.pipe(zipper)
81+
.pipe(writer)
82+
83+
}

index.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ var request = require('./lib/request.js');
2626
var fs = require('fs');
2727
var nodereport = require('nodereport');
2828
var agent = require("./appmetrics")
29+
var headlessZip = require("./headless_zip.js")
2930

31+
// Set the plugin search path
3032
agent.spath(path.join(module_dir, "plugins"))
3133

3234

@@ -230,6 +232,7 @@ for (var prop in agent) {
230232
if (typeof agent[prop] == "function") {
231233
module.exports[prop] = agent[prop]
232234
}
235+
agent.setHeadlessZipFunction(headlessZip.headlessZip);
233236
}
234237

235238
// Export emit() API for JS data providers
@@ -250,7 +253,11 @@ module.exports.monitor = function() {
250253

251254
if (typeof(this.api) == 'undefined') {
252255
agent.start();
253-
this.api = hcAPI.getAPI(agent, module.exports);
256+
this.api = hcAPI.getAPI(agent, module.exports);
257+
var headlessOutputDir = agent.getOption('com.ibm.diagnostics.healthcenter.headless.output.directory');
258+
if(headlessOutputDir) {
259+
headlessZip.setHeadlessOutputDir(headlessOutputDir);
260+
}
254261
}
255262
return this.api;
256263
};
@@ -288,8 +295,13 @@ module.exports.getJSONProfilingMode = function() {
288295

289296
module.exports.start = function () {
290297
agent.setOption(propertyMappings['applicationID'], main_filename);
298+
var headlessOutputDir = agent.getOption('com.ibm.diagnostics.healthcenter.headless.output.directory');
299+
if(headlessOutputDir) {
300+
headlessZip.setHeadlessOutputDir(headlessOutputDir);
301+
}
291302
agent.start();
292303
}
304+
293305
module.exports.nodereport = function() {
294306
return nodereport;
295307
}

src/appmetrics.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "uv.h"
2424
#include "ibmras/monitoring/AgentExtensions.h"
2525
#include "plugins/node/prof/watchdog.h"
26+
#include "headlessutils.h"
2627

2728
#if NODE_VERSION_AT_LEAST(0, 11, 0) // > v0.11+
2829
#include "objecttracker.hpp"
@@ -298,13 +299,27 @@ NAN_METHOD(setOption) {
298299
}
299300
}
300301

302+
// get property
303+
NAN_METHOD(getOption) {
304+
if (info.Length() > 0) {
305+
Local<String> value = info[0]->ToString();
306+
std::string property = loaderApi->getProperty(toStdString(value).c_str());
307+
v8::Local<v8::String> v8str = v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), property.c_str());
308+
info.GetReturnValue().Set<v8::String>(v8str);
309+
} else {
310+
loaderApi->logMessage(warning, "Incorrect number of parameters passed to getOption");
311+
}
312+
}
313+
301314
NAN_METHOD(start) {
302315
if (!running) {
303316
running = true;
304317

305318
loaderApi->init();
306319

307320
loaderApi->start();
321+
322+
headless::start();
308323
}
309324
if (!initMonitorApi()) {
310325
loaderApi->logMessage(warning, "Failed to initialize monitoring API");
@@ -319,6 +334,7 @@ NAN_METHOD(stop) {
319334
running = false;
320335
loaderApi->stop();
321336
loaderApi->shutdown();
337+
headless::stop();
322338
}
323339

324340
}
@@ -492,6 +508,13 @@ NAN_METHOD(sendControlCommand) {
492508

493509
}
494510

511+
NAN_METHOD(setHeadlessZipFunction) {
512+
if (!info[0]->IsFunction()) {
513+
return Nan::ThrowError("First argument must be a function");
514+
}
515+
Nan::Callback *callback = new Nan::Callback(info[0].As<Function>());
516+
headless::setZipFunction(callback);
517+
}
495518

496519
NAN_METHOD(localConnect) {
497520
if (!isMonitorApiValid()) {
@@ -624,6 +647,10 @@ static bool isGlobalAgentAlreadyLoaded(Local<Object> module) {
624647
return false;
625648
}
626649

650+
void zip(const char* outputDir) {
651+
headless::zip(outputDir);
652+
}
653+
627654
void init(Local<Object> exports, Local<Object> module) {
628655
/*
629656
* Throw an error if appmetrics has already been loaded globally
@@ -644,13 +671,15 @@ void init(Local<Object> exports, Local<Object> module) {
644671
/*
645672
* Set exported functions
646673
*/
674+
exports->Set(Nan::New<String>("getOption").ToLocalChecked(), Nan::New<FunctionTemplate>(getOption)->GetFunction());
647675
exports->Set(Nan::New<String>("setOption").ToLocalChecked(), Nan::New<FunctionTemplate>(setOption)->GetFunction());
648676
exports->Set(Nan::New<String>("start").ToLocalChecked(), Nan::New<FunctionTemplate>(start)->GetFunction());
649677
exports->Set(Nan::New<String>("spath").ToLocalChecked(), Nan::New<FunctionTemplate>(spath)->GetFunction());
650678
exports->Set(Nan::New<String>("stop").ToLocalChecked(), Nan::New<FunctionTemplate>(stop)->GetFunction());
651679
exports->Set(Nan::New<String>("localConnect").ToLocalChecked(), Nan::New<FunctionTemplate>(localConnect)->GetFunction());
652680
exports->Set(Nan::New<String>("nativeEmit").ToLocalChecked(), Nan::New<FunctionTemplate>(nativeEmit)->GetFunction());
653681
exports->Set(Nan::New<String>("sendControlCommand").ToLocalChecked(), Nan::New<FunctionTemplate>(sendControlCommand)->GetFunction());
682+
exports->Set(Nan::New<String>("setHeadlessZipFunction").ToLocalChecked(), Nan::New<FunctionTemplate>(setHeadlessZipFunction)->GetFunction());
654683
#if defined(_LINUX)
655684
exports->Set(Nan::New<String>("lrtime").ToLocalChecked(), Nan::New<FunctionTemplate>(lrtime)->GetFunction());
656685
#endif
@@ -670,6 +699,7 @@ void init(Local<Object> exports, Local<Object> module) {
670699
if (!loadProperties()) {
671700
loaderApi->logMessage(warning, "Failed to load appmetrics.properties file");
672701
}
702+
loaderApi->registerZipFunction(&zip);
673703
loaderApi->setLogLevels();
674704
/* changing this to pass agentcore.version and adding new appmetrics.version for use in the client */
675705
loaderApi->setProperty("agentcore.version", loaderApi->getAgentVersion());

src/headlessutils.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*******************************************************************************
2+
* Copyright 2016 IBM Corp.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*******************************************************************************/
16+
17+
18+
#include "headlessutils.h"
19+
#include <iostream>
20+
#include "nan.h"
21+
#include "uv.h"
22+
23+
namespace headless {
24+
25+
Nan::Callback* zipFunction;
26+
27+
void setZipFunction(Nan::Callback* zF) {
28+
zipFunction = zF;
29+
}
30+
31+
uv_async_t async_zip;
32+
33+
uv_loop_t* loop;
34+
const char* outputDir;
35+
36+
void asyncfunc(uv_async_t* handle) {
37+
Nan::HandleScope scope;
38+
v8::Isolate* isolate = v8::Isolate::GetCurrent();
39+
v8::Local<v8::Value> argv[] = { v8::String::NewFromUtf8(isolate, outputDir) };
40+
headless::zipFunction->Call(1, argv);
41+
}
42+
43+
44+
const char* headlessRecVersion = "1.0";
45+
46+
void start() {
47+
loop = uv_default_loop();
48+
uv_async_init(loop, &async_zip, asyncfunc);
49+
}
50+
51+
void stop() {
52+
uv_close((uv_handle_t*) &async_zip, NULL);
53+
}
54+
55+
void zip(const char* dir) {
56+
outputDir = dir;
57+
uv_async_send(&async_zip);
58+
}
59+
60+
61+
} /* end namespace headless */
62+
63+

src/headlessutils.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*******************************************************************************
2+
* Copyright 2016 IBM Corp.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*******************************************************************************/
16+
17+
18+
#ifndef HEADLESSUTILS_H_
19+
#define HEADLESSUTILS_H_
20+
21+
#include "nan.h"
22+
23+
24+
namespace headless {
25+
26+
void setZipFunction(Nan::Callback* callback);
27+
void start();
28+
void stop();
29+
void zip(const char* dir);
30+
31+
} /* namespace headless */
32+
#endif /* HEADLESSUTILS_H_ */

0 commit comments

Comments
 (0)