Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ postprocess it:
thoth: waiting for completion of job da3c0bf5-b04f-445b-aee7-af43ea3d17c0
thoth: job da3c0bf5-b04f-445b-aee7-af43ea3d17c0 completed in 0h0m2s

To upload the program that generated the core or crash dump, pass the `-p` argument. This will associate the program file with the core or crash dump and load it in MDB whenever `debug` is executed.

```
$ thoth upload core.19972 node
```

### info

Returns the JSON blob associated with the specified dump.
Expand Down Expand Up @@ -158,7 +164,22 @@ an exit status of 2 denotes that the dump was not found.
### debug

Results in an interactive debugging session debugging the specified dump
via [mlogin](http://blog.sysmgr.org/2013/06/manta-mlogin.html).
via [mlogin](http://blog.sysmgr.org/2013/06/manta-mlogin.html). For example,
to debug a core dump specied by the object value of `3e166b93871e7747c799008f58bd30b9`
run the following:

```
$ thoth debug 3e166b93871e7747c799008f58bd30b9
```

The `debug` command supports passing a binary referenced by a manta path. This is useful
when you need to analyze a core dump generated by a different version of node. The option is
`-p` and should be the manta path of the binary to pass into MDB. The example below demonstrates
passing the binary stored at /Joyent_Dev/public/node-6 into MDB.

```
$ thoth debug 3e166b93871e7747c799008f58bd30b9 -p /Joyent_Dev/public/node-6
```

### ls

Expand All @@ -172,7 +193,7 @@ By default, the dumps are listed in time order from oldest to newest.
For a given local dump, provides the hashed name of the object.

$ thoth object core.19972
3e166b93871e7747c799008f58bd30b9


This can be used to automate uploads of dumps.

Expand Down Expand Up @@ -300,7 +321,7 @@ Here's an analyzer that sets an ```fmri``` property to be that of the
echo $THOTH_NAME: $fmri

The output of analyzers is aggregated and displayed upon completion
of ```analyze```.
of ```analyze```.

#### Debugging analyzers

Expand All @@ -319,7 +340,7 @@ specify both the dump and the analyzer:

This results in an interactive shell whereby one can interactively
edit the specified analyzer by editing the file referred to by
```$THOTH_ANALYZER``` and can test the analyzer by running
```$THOTH_ANALYZER``` and can test the analyzer by running
```thoth_analyze```. When the shell exits successfully (that is,
an exit of 0), the contents of the file pointed to by ```$THOTH_ANALYZER```
will be written to the specified analyzer.
Expand Down
125 changes: 120 additions & 5 deletions bin/thoth
Original file line number Diff line number Diff line change
Expand Up @@ -1280,6 +1280,64 @@ var putCore = function (client, file, stat, base, cb)
});
};

var processProgram = function (client, base, program, cb)
{
var tmp = '/tmp/tmp.json';
var json = '/tmp/new.json';

var cmd = 'cat > ' + tmp + ' <<EOF\n';

cmd += '{ "program": "' + program + '" }\nEOF\n';

cmd += 'cat $MANTA_INPUT_FILE ' + tmp + ' | json --deep-merge > ' +
json + ';';
cmd += 'mput -f ' + json + ' $MANTA_INPUT_OBJECT ;';
cmd += jobExecThoth(json) + ' || ' +
'mln $MANTA_INPUT_OBJECT ' + thoth.path + '/' +
'`basename $(dirname $MANTA_INPUT_OBJECT)`' + thoth.unindexed;

jobOneKey(client, mod_path.join(base, '/info.json'), cmd, cb, jobSetThoth);
}

var uncompressProgram = function (client, stat, base, program, cb)
{
cmd = 'gunzip -cd $MANTA_INPUT_FILE > /var/tmp/gunzip.$$ ;'
cmd += 'mput -f /var/tmp/gunzip.$$ ' + program;

status('creating job to uncompress ' + mod_path.basename(base));
jobOneKey(client, program + '.gz', cmd,
function () { processProgram(client, base, program, cb); },
function (job) { job.phases[0].disk = 128; });
};

var putProgram = function (client, file, stat, base, cb)
{
var stream = mod_fs.createReadStream(file);
var program = base + '/' + mod_path.basename(file);
var gzip = mod_zlib.createGzip();

status('uploading ' + mod_path.basename(program) + ' to ' +
mod_path.basename(base));

progressBar(program, stream, stat);

pipe = stream.pipe(gzip);
pipe.pause();

var opts = {
copies: 1,
headers: { 'max-content-length': stat.size }
};

stream.on('open', function () {
client.put(program + '.gz', gzip, opts, function (err) {
checkError(err);

uncompressProgram(client, stat, base, program, cb);
});
});
};

var processCrash = function (client, stat, base, dump, cb)
{
var mdb = function (cmd) {
Expand Down Expand Up @@ -1424,6 +1482,29 @@ var openDump = function (name, cb, failed)
}
}

var openProgram = function (name, cb, failed)
{
var fd, file = { name: name };
var stat;
var sum = mod_crypto.createHash('md5');
var path = [ thoth.path ], digest;

try {
fd = mod_fs.openSync(name, 'r');
} catch (err) {
if (!failed)
fatal('couldn\'t open "' + name + '": ' + err);
return (failed());
}

file.stat = mod_fs.fstatSync(fd);

mod_fs.closeSync(fd);
path.push(file.digest = sum.digest('hex'));
file.base = path.join('/');
cb(file);
}

var infoGet = function (client, dump, cb, bypass)
{
argToInfo(client, dump, function (object, err, stream, res) {
Expand All @@ -1446,27 +1527,46 @@ var infoGet = function (client, dump, cb, bypass)
}, bypass);
}

handlers.upload = function (client, argv)
handlers.upload = function (client, argv, program)
{
put = {
crash: putCrash,
core: putCore
};

var next = function () {
var pArgIndex = argv.length > 2 ? argv.indexOf('-p') : -1;
if (pArgIndex !== -1) {
program = argv[pArgIndex + 1];
argv.splice(pArgIndex, 2);
}

var finish = function () {
if (argv.length == 1)
process.exit(0);

handlers.upload(client, argv.slice(1, argv.length));
};
handlers.upload(client, argv.slice(1, argv.length), program);
}

var next = function (dump) {
if (!program) {
return finish();
}

openProgram(program, function (file) {
status('creating program ' + file.digest);
putProgram(client, file.name, file.stat, dump.base, finish);
});
}

openDump(argv[0], function (file) {
status('creating ' + file.digest);

client.mkdirp(file.base, function (err) {
checkError(err);
put[file.type](client,
file.name, file.stat, file.base, next);
file.name, file.stat, file.base, function () {
next(file);
});
});
});
}
Expand Down Expand Up @@ -1696,6 +1796,7 @@ handlers.debug = function (client, argv)
var mlogin = mod_path.dirname(require.resolve('manta')) +
'/../bin/mlogin';
var analyzer = undefined;
var nodePath = undefined;

var analyzerCmd = function (args) {
var cmd = 'export THOTH_ANALYZER=/var/tmp/' + analyzer + '\n';
Expand Down Expand Up @@ -1758,6 +1859,8 @@ handlers.debug = function (client, argv)

if (analyzer) {
cmd += analyzerCmd(args);
} else if (nodePath || dump.program) {
cmd += 'mdb /assets' + (nodePath || dump.program) + ' $MANTA_INPUT_FILE';
} else {
cmd += 'mdb $MANTA_INPUT_FILE';
}
Expand All @@ -1768,6 +1871,12 @@ handlers.debug = function (client, argv)
'-c', '/assets/' + asset,
'--memory=2048' ]);

if (nodePath) {
args = args.concat(['-s', nodePath]);
} else if (dump.program) {
args = args.concat(['-s', dump.program]);
}

var child = mod_child.spawn(mlogin, args,
{ stdio: 'inherit' });

Expand All @@ -1782,6 +1891,12 @@ handlers.debug = function (client, argv)
}, { loadv8: analyzer ? false : true });
};

var nodeIndex = argv.length > 2 ? argv.indexOf('-p') : -1;
if (nodeIndex !== -1) {
nodePath = argv[nodeIndex + 1];
argv.splice(nodeIndex, 2);
}

if (argv.length > 1 && argv[argv.length - 1].indexOf('=') == -1)
analyzer = argv.pop();

Expand Down