-
Notifications
You must be signed in to change notification settings - Fork 107
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/develop'
- Loading branch information
Showing
63 changed files
with
2,723 additions
and
683 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
app/css/* | ||
app/*.js | ||
dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
app | ||
gulpfile.js | ||
wercker.yml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,27 @@ | ||
# `rtail(1)` (DO NOT USE IT YET) | ||
[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/kilianc/rtail?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||
# `rtail(1)` | ||
|
||
Stupid simple UNIX style stream broadcast over UDP in your browser. | ||
[![Wercker CI](https://img.shields.io/wercker/ci/556547b7be632a8c751c857d.svg?style=flat-square)](https://app.wercker.com/project/bykey/54b073dac5b9156509c26031c78c98d4) | ||
[![Coveralls](https://img.shields.io/coveralls/kilianc/rtail.svg?style=flat-square)](https://coveralls.io/r/kilianc/rtail) | ||
[![NPM version](https://img.shields.io/npm/v/rtail.svg?style=flat-square)](https://www.npmjs.com/package/rtail) | ||
[![NPM downloads](https://img.shields.io/npm/dm/rtail.svg?style=flat-square)](https://www.npmjs.com/package/rtail) | ||
[![GitHub Stars](https://img.shields.io/github/stars/kilianc/rtail.svg?style=flat-square)](https://github.com/kilianc/rtail) | ||
[![License](https://img.shields.io/npm/l/rtail.svg?style=flat-square)](https://www.npmjs.com/package/rtail) | ||
[![Gitter](https://img.shields.io/badge/≡_gitter-join_chat_➝-04cd7e.svg?style=flat-square)](https://gitter.im/kilianc/rtail?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||
|
||
`rtail` is a command line utility that grabs every line in `stdin` and broadcast it over **UDP**. That's it, nothing fancy, nothing complicated. You can tail your log files, your app logs or whatever you wish to pipe in `rtail` to a `rtail-server` and see multiple streams in the browser, realtime. | ||
## Pipe your terminal output to the browser in seconds, using UNIX pipes. | ||
|
||
`rtail` is a command line utility that grabs every line in `stdin` and broadcast it over **UDP**. That's it, nothing fancy, nothing complicated. You can tail your log files, your app output or whatever you wish to pipe, in `rtail` to a `rtail-server` and see multiple streams in the browser, realtime. | ||
|
||
## Installation | ||
|
||
$ npm install -g rtail | ||
|
||
## Web app | ||
|
||
![](https://s3.amazonaws.com/rtail/github/dark.png) | ||
|
||
![](https://s3.amazonaws.com/rtail/github/light.png) | ||
|
||
## Rationale | ||
|
||
If you develop software for work and you deploy your code on remote servers using multiple environments, or simply have multiple projects, you know that to monitor realtime your logs **you need to `ssh` to every single machine running your code**. | ||
|
@@ -55,19 +68,21 @@ For fun and debugging | |
Usage: cmd | rtail --host [string] --port [num] [--mute] [--id [string]] | ||
|
||
Examples: | ||
server | rtail --host 127.0.0.1 > server.log broadcast to localhost + file | ||
server | rtail --port 43567 custom port | ||
server | rtail --mute only remote | ||
server | rtail --id api.domain.com name the log stream | ||
server | rtail --host 127.0.0.1 > server.log Broadcast to localhost + file | ||
server | rtail --port 43567 Custom port | ||
server | rtail --mute Only remote | ||
server | rtail --id api.domain.com Name the log stream | ||
server | rtail --not-tty Strips ANSI colors | ||
|
||
|
||
Options: | ||
--mute, -m don't pipe stdin with stdout | ||
--host the recipient server host [default: "127.0.0.1"] | ||
--port, -p the recipient server port [default: 9999] | ||
--id, --name, -n the log stream id [default: uuid()] | ||
--help, -h Show help | ||
--version, -v Show version number | ||
--mute, -m Don't pipe stdin with stdout | ||
--host The recipient server host [default: "127.0.0.1"] | ||
--port, -p The recipient server port [default: 9999] | ||
--id, --name The log stream id [default: moniker()] | ||
--not-tty Strips ansi colors | ||
--help, -h Show help | ||
--version, -v Show version number | ||
|
||
## `rtail-server(1)` | ||
|
||
|
@@ -81,28 +96,42 @@ With default values | |
|
||
$ rtail-server | ||
|
||
Stay up to date! | ||
|
||
$ rtail-server --web-version stable | ||
|
||
With custom ports | ||
|
||
$ rtail-server --web-port 8080 --udp-port 9090 | ||
|
||
With debugging on | ||
|
||
$ DEBUG=rtail:* rtail-server | ||
|
||
With serving always latest stable webapp | ||
|
||
$ DEBUG=rtail:* rtail-server --web-version stable | ||
|
||
Open your browser and start tailing logs! | ||
|
||
## Params | ||
|
||
$ rtail-server | ||
Usage: rtail-server [--udp-host [string] --udp-port [num] --web-host [string] --web-port [num]] | ||
$ rtail-server -h | ||
Usage: rtail-server [--udp-host [string] --udp-port [num] --web-host [string] --web-port [num] --web-version [stable,unstable,<version>]] | ||
|
||
Examples: | ||
rtail-server --web-port 8080 custom http port | ||
rtail-server --udp-port 8080 custom udp port | ||
rtail-server --web-port 8080 Use custom http port | ||
rtail-server --udp-port 8080 Use custom udp port | ||
rtail-server --web-version stable Always uses latest stable webapp | ||
rtail-server --web-version 0.1.3 Use webapp v0.1.3 | ||
|
||
|
||
Options: | ||
--udp-host, --uh the listening udp hostname [default: "localhost"] | ||
--udp-port, --up the listening udp port [default: 9999] | ||
--web-host, --wh the listening http hostname [default: "localhost"] | ||
--web-port, --wp the listening http port [default: 8888] | ||
--udp-host, --uh The listening udp hostname [default: "127.0.0.1"] | ||
--udp-port, --up The listening udp port [default: 9999] | ||
--web-host, --wh The listening http hostname [default: "127.0.0.1"] | ||
--web-port, --wp The listening http port [default: 8888] | ||
--web-version Define web app version to serve | ||
--help, -h Show help | ||
--version, -v Show version number | ||
|
||
|
@@ -127,11 +156,17 @@ The test suite is written on top of [visionmedia/mocha](http://visionmedia.githu | |
|
||
$ npm test | ||
|
||
## Contributors | ||
|
||
* [Kilian Ciuffolo](https://github.com/kilianc) | ||
* [Luca Orio](https://www.behance.net/lucaorio) | ||
* [Sandaruwan Silva](https://github.com/s-silva) | ||
|
||
## License | ||
|
||
_This software is released under the MIT license cited below_. | ||
|
||
Copyright (c) 2014 Kilian Ciuffolo, [email protected]. All Rights Reserved. | ||
Copyright (c) 2015 Kilian Ciuffolo, [email protected]. All Rights Reserved. | ||
|
||
Permission is hereby granted, free of charge, to any person | ||
obtaining a copy of this software and associated documentation | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
/** | ||
* Main JS controller for webapp | ||
*/ | ||
|
||
angular | ||
.module('app', [ | ||
'ngAnimate', | ||
'angularMoment', | ||
'LocalForageModule', | ||
'rt.popup' | ||
]) | ||
.controller('MainController', function MainController($scope, $injector) { | ||
var $sce = $injector.get('$sce') | ||
var $moment = $injector.get('moment') | ||
var $localForage = $injector.get('$localForage') | ||
var $window = $injector.get('$window') | ||
var $streamLines = $('.stream-lines') | ||
var BUFFER_SIZE = 100 | ||
var ctrl = this | ||
|
||
ctrl.paused = false | ||
ctrl.version = '<%= version %>' | ||
ctrl.lines = [] | ||
|
||
/** | ||
* Socket stuff | ||
*/ | ||
|
||
ctrl.socket = io(document.location.origin, { path: document.location.pathname + 'socket.io' }) | ||
|
||
ctrl.socket.on('streams', function (streams) { | ||
ctrl.streams = streams | ||
$scope.$apply() | ||
}) | ||
|
||
ctrl.socket.on('backlog', function (lines) { | ||
if (!lines) return | ||
ctrl.lines = lines.map(formatLine) | ||
$scope.$apply() | ||
updateScroll() | ||
console.info('%s: backlog received %d', ctrl.activeStream, lines.length) | ||
}) | ||
|
||
ctrl.socket.on('line', function (line) { | ||
ctrl.lines.push(formatLine(line)) | ||
|
||
if (ctrl.lines.length > BUFFER_SIZE) { | ||
ctrl.lines.length >= 100 && ctrl.lines.shift() | ||
} | ||
|
||
$scope.$apply() | ||
updateScroll() | ||
}) | ||
|
||
ctrl.selectStream = function selectStream(stream) { | ||
ctrl.activeStream = stream | ||
ctrl.socket.emit('select stream', stream) | ||
ctrl.resume() | ||
$localForage.setItem('activeStream', stream) | ||
} | ||
|
||
ctrl.isSelected = function isSelected(stream) { | ||
return ctrl.activeStream === stream | ||
} | ||
|
||
function updateScroll() { | ||
var where = ctrl.streamDirection ? $streamLines[0].scrollHeight : 0 | ||
$streamLines.scrollTop(where) | ||
} | ||
|
||
function formatLine(line) { | ||
if (!line.content) { | ||
// handle empty line | ||
line.html = $sce.trustAsHtml('') | ||
} else if ('object' === line.type) { | ||
// for object just format JSON | ||
line.html = hljs.highlight('json', JSON.stringify(line.content, null, ' ')).value | ||
line.html = $sce.trustAsHtml('<pre>' + line.html + '</pre>') | ||
} else { | ||
// for log lines use ansi format | ||
line.html = ansi_up.ansi_to_html(line.content, { use_classes: true }) | ||
line.html = $sce.trustAsHtml(line.html) | ||
} | ||
|
||
return line | ||
} | ||
|
||
ctrl.resume = function resume() { | ||
if (!ctrl.paused) return | ||
ctrl.paused = false | ||
ctrl.socket.emit('select stream', ctrl.activeStream) | ||
$streamLines.on('mousewheel', ctrl.pause) | ||
} | ||
|
||
ctrl.pause = function pause() { | ||
if (ctrl.paused) return | ||
ctrl.paused = true | ||
ctrl.socket.emit('select stream') | ||
$streamLines.off('mousewheel', ctrl.pause) | ||
$scope.$apply() | ||
} | ||
|
||
$streamLines.on('mousewheel', ctrl.pause) | ||
|
||
/** | ||
* Settings and preferences | ||
*/ | ||
|
||
ctrl.toggleFavorite = function toggleFavorite(stream) { | ||
if (ctrl.favorites[stream]) { | ||
delete ctrl.favorites[stream] | ||
} else { | ||
ctrl.favorites[stream] = true | ||
} | ||
|
||
$localForage.setItem('favorites', ctrl.favorites) | ||
} | ||
|
||
ctrl.setTheme = function setTheme(theme) { | ||
ctrl.theme = theme | ||
$localForage.setItem('theme', theme) | ||
} | ||
|
||
ctrl.setFontFamily = function setFontFamily(fontFamily) { | ||
ctrl.fontFamily = fontFamily | ||
$localForage.setItem('fontFamily', fontFamily) | ||
} | ||
|
||
ctrl.incFontSize = function incFontSize(fontSize) { | ||
ctrl.fontSize = Math.min(7, ctrl.fontSize + 1) | ||
$localForage.setItem('fontSize', ctrl.fontSize) | ||
} | ||
|
||
ctrl.resetFontSize = function resetFontSize() { | ||
ctrl.fontSize = 4 | ||
$localForage.setItem('fontSize', ctrl.fontSize) | ||
} | ||
|
||
ctrl.decFontSize = function decFontSize(fontSize) { | ||
ctrl.fontSize = Math.max(1, ctrl.fontSize - 1) | ||
$localForage.setItem('fontSize', fontSize) | ||
} | ||
|
||
ctrl.setStreamDirection = function setStreamDirection(streamDirection) { | ||
ctrl.streamDirection = streamDirection | ||
$localForage.setItem('streamDirection', streamDirection) | ||
} | ||
|
||
/** | ||
* Load storage in memory and boot | ||
*/ | ||
|
||
$localForage.getItem('theme').then(function (theme) { | ||
ctrl.theme = theme || 'dark' | ||
}) | ||
|
||
$localForage.getItem('fontFamily').then(function (fontFamily) { | ||
ctrl.fontFamily = fontFamily || 1 | ||
}) | ||
|
||
$localForage.getItem('fontSize').then(function (fontSize) { | ||
ctrl.fontSize = fontSize || 4 | ||
}) | ||
|
||
$localForage.getItem('favorites').then(function (favorites) { | ||
ctrl.favorites = favorites || {} | ||
}) | ||
|
||
$localForage.getItem('activeStream').then(function (activeStream) { | ||
if (!activeStream) return | ||
console.info('%s: restoring session', activeStream) | ||
ctrl.selectStream(activeStream) | ||
}) | ||
|
||
$localForage.getItem('streamDirection').then(function (streamDirection) { | ||
ctrl.streamDirection = undefined === streamDirection ? true : streamDirection | ||
}) | ||
|
||
/** | ||
* Tell UI we're ready to roll | ||
*/ | ||
|
||
ctrl.loaded = true | ||
}) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.