tailog 0.3.7 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascripts/ansi_up.js +8 -8
- data/app/assets/javascripts/jquery.highlight.js +152 -0
- data/app/assets/stylesheets/application.css +26 -0
- data/app/views/layout.erb +1 -0
- data/app/views/logs/index.erb +74 -8
- data/lib/tailog/eval.rb +36 -0
- data/lib/tailog/request_id.rb +24 -0
- data/lib/tailog/version.rb +1 -1
- data/lib/tailog/watch_methods.rb +69 -53
- data/lib/tailog.rb +3 -1
- data/tailog.gemspec +2 -0
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e059546fe3ba51e4d77e16ecec8e8415849af454
|
4
|
+
data.tar.gz: b3ae7620423132949c16eb327e5f8e56a280fb89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0afce3b55d7d34d91819a52a356846e58db3eb6ddc4e72e31b3240c76371a4b2bd93207d983247a0ab5734da94ae4089bd68ac9f3cf10fce201944eab14106bb
|
7
|
+
data.tar.gz: 143514a5dba6dd0519d1633961d7d44f52e92e60ceecde7108ac82a7cee2aa1c0555e5f4b97326e707e6eef4e7c7f705f8001b2e334560b0c59464b5b49b885a
|
@@ -15,14 +15,14 @@
|
|
15
15
|
// Normal and then Bright
|
16
16
|
ANSI_COLORS = [
|
17
17
|
[
|
18
|
-
{ color: "
|
19
|
-
{ color: "
|
20
|
-
{ color: "
|
21
|
-
{ color: "
|
22
|
-
{ color: "
|
23
|
-
{ color: "
|
24
|
-
{ color: "
|
25
|
-
{ color: "
|
18
|
+
{ color: "27, 27, 27", 'class': "ansi-black" },
|
19
|
+
{ color: "182, 80, 47", 'class': "ansi-red" },
|
20
|
+
{ color: "141, 161, 88", 'class': "ansi-green" },
|
21
|
+
{ color: "220, 175, 95", 'class': "ansi-yellow" },
|
22
|
+
{ color: "126, 170, 199", 'class': "ansi-blue" },
|
23
|
+
{ color: "176, 101, 152", 'class': "ansi-magenta" },
|
24
|
+
{ color: "141, 220, 217", 'class': "ansi-cyan" },
|
25
|
+
{ color: "217, 217, 217", 'class': "ansi-white" }
|
26
26
|
], [
|
27
27
|
{ color: "27, 27, 27", 'class': "ansi-bright-black" },
|
28
28
|
{ color: "182, 80, 47", 'class': "ansi-bright-red" },
|
@@ -0,0 +1,152 @@
|
|
1
|
+
/*
|
2
|
+
* jQuery Highlight plugin
|
3
|
+
*
|
4
|
+
* Based on highlight v3 by Johann Burkard
|
5
|
+
* http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html
|
6
|
+
*
|
7
|
+
* Code a little bit refactored and cleaned (in my humble opinion).
|
8
|
+
* Most important changes:
|
9
|
+
* - has an option to highlight only entire words (wordsOnly - false by default),
|
10
|
+
* - has an option to be case sensitive (caseSensitive - false by default)
|
11
|
+
* - highlight element tag and class names can be specified in options
|
12
|
+
*
|
13
|
+
* Usage:
|
14
|
+
* // wrap every occurrence of text 'lorem' in content
|
15
|
+
* // with <span class='highlight'> (default options)
|
16
|
+
* $('#content').highlight('lorem');
|
17
|
+
*
|
18
|
+
* // search for and highlight more terms at once
|
19
|
+
* // so you can save some time on traversing DOM
|
20
|
+
* $('#content').highlight(['lorem', 'ipsum']);
|
21
|
+
* $('#content').highlight('lorem ipsum');
|
22
|
+
*
|
23
|
+
* // search only for entire word 'lorem'
|
24
|
+
* $('#content').highlight('lorem', { wordsOnly: true });
|
25
|
+
*
|
26
|
+
* // search only for the entire word 'C#'
|
27
|
+
* // and make sure that the word boundary can also
|
28
|
+
* // be a 'non-word' character, as well as a regex latin1 only boundary:
|
29
|
+
* $('#content').highlight('C#', { wordsOnly: true , wordsBoundary: '[\\b\\W]' });
|
30
|
+
*
|
31
|
+
* // don't ignore case during search of term 'lorem'
|
32
|
+
* $('#content').highlight('lorem', { caseSensitive: true });
|
33
|
+
*
|
34
|
+
* // wrap every occurrence of term 'ipsum' in content
|
35
|
+
* // with <em class='important'>
|
36
|
+
* $('#content').highlight('ipsum', { element: 'em', className: 'important' });
|
37
|
+
*
|
38
|
+
* // remove default highlight
|
39
|
+
* $('#content').unhighlight();
|
40
|
+
*
|
41
|
+
* // remove custom highlight
|
42
|
+
* $('#content').unhighlight({ element: 'em', className: 'important' });
|
43
|
+
*
|
44
|
+
*
|
45
|
+
* Copyright (c) 2009 Bartek Szopka
|
46
|
+
*
|
47
|
+
* Licensed under MIT license.
|
48
|
+
*
|
49
|
+
*/
|
50
|
+
|
51
|
+
(function (factory) {
|
52
|
+
if (typeof define === 'function' && define.amd) {
|
53
|
+
// AMD. Register as an anonymous module.
|
54
|
+
define(['jquery'], factory);
|
55
|
+
} else if (typeof exports === 'object') {
|
56
|
+
// Node/CommonJS
|
57
|
+
factory(require('jquery'));
|
58
|
+
} else {
|
59
|
+
// Browser globals
|
60
|
+
factory(jQuery);
|
61
|
+
}
|
62
|
+
}(function (jQuery) {
|
63
|
+
jQuery.extend({
|
64
|
+
highlight: function (node, re, nodeName, className) {
|
65
|
+
if (node.nodeType === 3) {
|
66
|
+
var match = node.data.match(re);
|
67
|
+
if (match) {
|
68
|
+
// The new highlight Element Node
|
69
|
+
var highlight = document.createElement(nodeName || 'span');
|
70
|
+
highlight.className = className || 'highlight';
|
71
|
+
// Note that we use the captured value to find the real index
|
72
|
+
// of the match. This is because we do not want to include the matching word boundaries
|
73
|
+
var capturePos = node.data.indexOf( match[1] , match.index );
|
74
|
+
|
75
|
+
// Split the node and replace the matching wordnode
|
76
|
+
// with the highlighted node
|
77
|
+
var wordNode = node.splitText(capturePos);
|
78
|
+
wordNode.splitText(match[1].length);
|
79
|
+
|
80
|
+
var wordClone = wordNode.cloneNode(true);
|
81
|
+
highlight.appendChild(wordClone);
|
82
|
+
wordNode.parentNode.replaceChild(highlight, wordNode);
|
83
|
+
return 1; //skip added node in parent
|
84
|
+
}
|
85
|
+
} else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
|
86
|
+
!/(script|style)/i.test(node.tagName) && // ignore script and style nodes
|
87
|
+
!(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
|
88
|
+
for (var i = 0; i < node.childNodes.length; i++) {
|
89
|
+
i += jQuery.highlight(node.childNodes[i], re, nodeName, className);
|
90
|
+
}
|
91
|
+
}
|
92
|
+
return 0;
|
93
|
+
}
|
94
|
+
});
|
95
|
+
|
96
|
+
jQuery.fn.unhighlight = function (options) {
|
97
|
+
var settings = {
|
98
|
+
className: 'highlight',
|
99
|
+
element: 'span'
|
100
|
+
};
|
101
|
+
|
102
|
+
jQuery.extend(settings, options);
|
103
|
+
|
104
|
+
return this.find(settings.element + '.' + settings.className).each(function () {
|
105
|
+
var parent = this.parentNode;
|
106
|
+
parent.replaceChild(this.firstChild, this);
|
107
|
+
parent.normalize();
|
108
|
+
}).end();
|
109
|
+
};
|
110
|
+
|
111
|
+
jQuery.fn.highlight = function (words, options) {
|
112
|
+
var settings = {
|
113
|
+
className: 'highlight',
|
114
|
+
element: 'span',
|
115
|
+
caseSensitive: false,
|
116
|
+
wordsOnly: false,
|
117
|
+
wordsBoundary: '\\b'
|
118
|
+
};
|
119
|
+
|
120
|
+
jQuery.extend(settings, options);
|
121
|
+
|
122
|
+
if (typeof words === 'string') {
|
123
|
+
words = [words];
|
124
|
+
}
|
125
|
+
words = jQuery.grep(words, function(word, i){
|
126
|
+
return word != '';
|
127
|
+
});
|
128
|
+
words = jQuery.map(words, function(word, i) {
|
129
|
+
return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
130
|
+
});
|
131
|
+
|
132
|
+
if (words.length === 0) {
|
133
|
+
return this;
|
134
|
+
};
|
135
|
+
|
136
|
+
var flag = settings.caseSensitive ? '' : 'i';
|
137
|
+
// The capture parenthesis will make sure we can match
|
138
|
+
// only the matching word
|
139
|
+
var pattern = '(' + words.join('|') + ')';
|
140
|
+
if (settings.wordsOnly) {
|
141
|
+
pattern =
|
142
|
+
(settings.wordsBoundaryStart || settings.wordsBoundary) +
|
143
|
+
pattern +
|
144
|
+
(settings.wordsBoundaryEnd || settings.wordsBoundary);
|
145
|
+
}
|
146
|
+
var re = new RegExp(pattern, flag);
|
147
|
+
|
148
|
+
return this.each(function () {
|
149
|
+
jQuery.highlight(this, re, settings.element, settings.className);
|
150
|
+
});
|
151
|
+
};
|
152
|
+
}));
|
@@ -9,6 +9,28 @@ p {
|
|
9
9
|
margin: 0;
|
10
10
|
}
|
11
11
|
|
12
|
+
.fixed-top-right {
|
13
|
+
position: fixed;
|
14
|
+
top: 25px;
|
15
|
+
right: 25px;
|
16
|
+
}
|
17
|
+
|
18
|
+
.settings-panel {
|
19
|
+
margin-top: 50px;
|
20
|
+
width: 320px;
|
21
|
+
box-shadow: 0 6px 12px rgba(0,0,0,.175);
|
22
|
+
}
|
23
|
+
|
24
|
+
.highlight-list {
|
25
|
+
margin-top: 5px;
|
26
|
+
}
|
27
|
+
|
28
|
+
.highlight-list span {
|
29
|
+
cursor: pointer;
|
30
|
+
margin-right: 5px;
|
31
|
+
font-size: 12px;
|
32
|
+
}
|
33
|
+
|
12
34
|
.content-hover p:hover {
|
13
35
|
background: #EEE;
|
14
36
|
}
|
@@ -37,3 +59,7 @@ p {
|
|
37
59
|
color: #a94442;
|
38
60
|
border-bottom: 3px dashed #d9534f;
|
39
61
|
}
|
62
|
+
|
63
|
+
.highlight {
|
64
|
+
background: #FFFF88;
|
65
|
+
}
|
data/app/views/layout.erb
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
|
6
6
|
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.form/3.51/jquery.form.js"></script>
|
7
7
|
<script type="text/javascript" src="javascripts/ansi_up.js"></script>
|
8
|
+
<script type="text/javascript" src="javascripts/jquery.highlight.js"></script>
|
8
9
|
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css">
|
9
10
|
<link rel="stylesheet" type="text/css" href="stylesheets/application.css">
|
10
11
|
</head>
|
data/app/views/logs/index.erb
CHANGED
@@ -7,23 +7,83 @@
|
|
7
7
|
<h3 class="page-header"><%= file_path %></h3>
|
8
8
|
|
9
9
|
<% File.open file_path do |file| %>
|
10
|
-
<div id="content" class="content-hover"></div>
|
10
|
+
<div id="content" class="content content-hover"></div>
|
11
11
|
<% end %>
|
12
12
|
|
13
|
-
<a id="
|
13
|
+
<a id="settings-toggle" class="btn btn-primary fixed-top-right"><i class="glyphicon glyphicon-cog"></i></a>
|
14
|
+
|
15
|
+
<div id="settings-panel" class="panel panel-info fixed-top-right settings-panel hidden">
|
16
|
+
<div class="panel-heading">Settings</div>
|
17
|
+
<div class="panel-body">
|
18
|
+
<div class="form-group btn-group">
|
19
|
+
<a id="add-divider" class="btn btn-default">Add Divider</a>
|
20
|
+
<a id="clear-logs" class="btn btn-default">Clear Logs</a>
|
21
|
+
</div>
|
22
|
+
<div class="form-group">
|
23
|
+
<div class="input-group">
|
24
|
+
<input id="highlight" type="text" class="form-control" placeholder="Keyword">
|
25
|
+
<span class="input-group-btn">
|
26
|
+
<button id="add-highlight" class="btn btn-default" type="button">Highlight!</button>
|
27
|
+
</span>
|
28
|
+
</div>
|
29
|
+
<div id="highlight-list" class="highlight-list"></div>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
</div>
|
14
33
|
|
15
34
|
<script type="text/javascript">
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
$content = $("#content");
|
35
|
+
var $settingsPanel = $("#settings-panel");
|
36
|
+
$("#settings-toggle").click(function() {
|
37
|
+
$settingsPanel.toggleClass("hidden");
|
38
|
+
});
|
21
39
|
|
22
40
|
var dividerId = 1;
|
23
|
-
$("#
|
41
|
+
$("#add-divider").click(function() {
|
24
42
|
$content.append('<span class="divider"> #' + dividerId++ + ' - ' + new Date() + '</span>');
|
25
43
|
});
|
26
44
|
|
45
|
+
$("#clear-logs").click(function() {
|
46
|
+
$content.html('');
|
47
|
+
});
|
48
|
+
|
49
|
+
var $highlight = $("#highlight"),
|
50
|
+
$highlightList = $("#highlight-list");
|
51
|
+
|
52
|
+
function rawHighlight(keyword) {
|
53
|
+
$content.highlight(keyword, { className: 'highlight highlight-' + keyword });
|
54
|
+
}
|
55
|
+
|
56
|
+
function rawUnhighlight(keyword) {
|
57
|
+
$content.unhighlight({ className: 'highlight-' + keyword });
|
58
|
+
}
|
59
|
+
|
60
|
+
function highlight(keyword) {
|
61
|
+
if ($highlightList.find('.highlight-' + keyword).length > 0) return;
|
62
|
+
rawHighlight(keyword);
|
63
|
+
$highlightList.append('<span class="label label-primary highlight-' + keyword + ' toggle-highlight">' + keyword + '</span>');
|
64
|
+
}
|
65
|
+
|
66
|
+
$highlight.keypress(function(event) {
|
67
|
+
if ((event.keyCode || event.which) === 13) {
|
68
|
+
highlight($highlight.val());
|
69
|
+
}
|
70
|
+
});
|
71
|
+
$("#add-highlight").click(function() {
|
72
|
+
highlight($highlight.val());
|
73
|
+
});
|
74
|
+
|
75
|
+
$("#highlight-list").on("click", ".toggle-highlight", function(event) {
|
76
|
+
var $this = $(this),
|
77
|
+
keyword = $this.text();
|
78
|
+
$this.data('hidden') ? rawHighlight(keyword) : rawUnhighlight(keyword);
|
79
|
+
$this.data('hidden', !$this.data('hidden'));
|
80
|
+
});
|
81
|
+
|
82
|
+
window.fileSize = {};
|
83
|
+
window.fileSizeDone = {};
|
84
|
+
var $window = $(window),
|
85
|
+
$document = $(document),
|
86
|
+
$content = $("#content");
|
27
87
|
function loadMore() {
|
28
88
|
$.post(window.location.href, { seek: window.fileSize }, function(json) {
|
29
89
|
try {
|
@@ -36,10 +96,16 @@
|
|
36
96
|
|
37
97
|
if (!data.content) return;
|
38
98
|
var shouldScrollToBottom = $window.scrollTop() + $window.height() == $document.height();
|
99
|
+
|
39
100
|
$content
|
40
101
|
.append('<span class="text-info">' + data.server_hostname + ' - ' + data.file_size + '</span>')
|
41
102
|
.append(ansi_up.ansi_to_html(data.content));
|
42
103
|
|
104
|
+
$highlightList.find("span").each(function(index, node) {
|
105
|
+
var $node = $(node);
|
106
|
+
$node.data('hidden') || rawHighlight($node.text());
|
107
|
+
});
|
108
|
+
|
43
109
|
if (shouldScrollToBottom) {
|
44
110
|
$window.scrollTop($document.height() - $window.height());
|
45
111
|
}
|
data/lib/tailog/eval.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Tailog
|
2
|
+
class Eval
|
3
|
+
class << self
|
4
|
+
attr_accessor :blacklist
|
5
|
+
end
|
6
|
+
|
7
|
+
self.blacklist = %w(/tailog)
|
8
|
+
|
9
|
+
def initialize app
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
def call env
|
14
|
+
if skip_call? env
|
15
|
+
@app.call(env)
|
16
|
+
else
|
17
|
+
before = env["HTTP_TAILOG_EVAL_BEFORE"].presence
|
18
|
+
after = env["HTTP_TAILOG_EVAL_AFTER"].presence
|
19
|
+
|
20
|
+
eval before if before
|
21
|
+
response = @app.call(env)
|
22
|
+
eval after if after
|
23
|
+
|
24
|
+
response
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def skip_call? env
|
31
|
+
Tailog::Eval.blacklist.any? do |path|
|
32
|
+
env["PATH_INFO"].start_with? path
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Tailog
|
2
|
+
class RequestId
|
3
|
+
def initialize app
|
4
|
+
@app = app
|
5
|
+
end
|
6
|
+
|
7
|
+
def call env
|
8
|
+
Tailog.request_id = external_request_id(env) || internal_request_id
|
9
|
+
@app.call(env).tap do |_status, headers, _body|
|
10
|
+
headers["X-Request-Id"] = Tailog.request_id
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def external_request_id env
|
17
|
+
env["HTTP_X_REQUEST_ID"].presence
|
18
|
+
end
|
19
|
+
|
20
|
+
def internal_request_id
|
21
|
+
SecureRandom.uuid
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/tailog/version.rb
CHANGED
data/lib/tailog/watch_methods.rb
CHANGED
@@ -1,22 +1,17 @@
|
|
1
1
|
require 'active_support/core_ext/string'
|
2
|
-
require 'active_support/configurable'
|
3
2
|
require 'securerandom'
|
4
3
|
require 'logger'
|
5
4
|
|
6
5
|
module Tailog
|
7
6
|
module WatchMethods
|
8
|
-
include ActiveSupport::Configurable
|
9
|
-
|
10
7
|
class << self
|
11
|
-
attr_accessor :request_id
|
12
|
-
|
13
8
|
def logger
|
14
9
|
return @logger if @logger
|
15
10
|
@logger = Logger.new(File.join Tailog.log_path, "watch_methods.log")
|
16
11
|
@logger.formatter = proc do |severity, datetime, progname, message|
|
17
12
|
content = ""
|
18
13
|
content << "[#{datetime.strftime("%Y-%m-%d %H:%M:%S")}]"
|
19
|
-
content << "[#{Tailog
|
14
|
+
content << "[#{Tailog.request_id}]" if Tailog.request_id
|
20
15
|
content << " #{severity.rjust(5)}"
|
21
16
|
content << " (#{progname})" if progname
|
22
17
|
content << ": #{message.gsub(/\n\s*/, " ")}"
|
@@ -27,68 +22,63 @@ module Tailog
|
|
27
22
|
end
|
28
23
|
end
|
29
24
|
|
30
|
-
|
31
|
-
def initialize(app)
|
32
|
-
@app = app
|
33
|
-
end
|
34
|
-
|
35
|
-
def call(env)
|
36
|
-
Tailog::WatchMethods.request_id = external_request_id(env) || internal_request_id
|
37
|
-
@app.call(env).tap do |_status, headers, _body|
|
38
|
-
headers["X-Request-Id"] = Tailog::WatchMethods.request_id
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def external_request_id(env)
|
45
|
-
if request_id = env["HTTP_X_REQUEST_ID"].presence
|
46
|
-
request_id.gsub(/[^\w\-]/, "").first(255)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def internal_request_id
|
51
|
-
SecureRandom.uuid
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def inject_constants targets
|
25
|
+
def inject targets
|
56
26
|
targets.each do |target|
|
57
27
|
begin
|
58
|
-
target.
|
59
|
-
inject_instance_method
|
60
|
-
|
61
|
-
|
62
|
-
|
28
|
+
if target.include? "#"
|
29
|
+
inject_instance_method target
|
30
|
+
elsif target.include? "."
|
31
|
+
inject_class_method target
|
32
|
+
else
|
33
|
+
inject_constant target
|
63
34
|
end
|
64
35
|
rescue => error
|
65
|
-
WatchMethods.logger.error "Inject
|
36
|
+
WatchMethods.logger.error "Inject #{target} FAILED: #{error.class}: #{error.message}"
|
66
37
|
end
|
67
38
|
end
|
68
39
|
end
|
69
40
|
|
70
|
-
def
|
41
|
+
def cleanup targets
|
71
42
|
targets.each do |target|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
rescue => error
|
79
|
-
WatchMethods.logger.error "Inject method `#{target}' failed: #{error.class}: #{error.message}"
|
43
|
+
if target.include? "#"
|
44
|
+
cleanup_instance_method target
|
45
|
+
elsif target.include? "."
|
46
|
+
cleanup_class_method target
|
47
|
+
else
|
48
|
+
cleanup_constant target
|
80
49
|
end
|
81
50
|
end
|
82
51
|
end
|
83
52
|
|
84
53
|
private
|
85
54
|
|
55
|
+
RAW_METHOD_PREFIX = "watch_method_raw_"
|
56
|
+
|
57
|
+
def raw_method? method
|
58
|
+
method.to_s.start_with? RAW_METHOD_PREFIX
|
59
|
+
end
|
60
|
+
|
61
|
+
def inject_constant target
|
62
|
+
constant = target.constantize
|
63
|
+
constant.instance_methods(false).each do |method|
|
64
|
+
inject_instance_method "#{target}##{method}" unless raw_method? method
|
65
|
+
end
|
66
|
+
constant.methods(false).each do |method|
|
67
|
+
inject_class_method "#{target}.#{method}" unless raw_method? method
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def cleanup_constant target
|
72
|
+
target.constantize.instance_methods(false).each do |method|
|
73
|
+
cleanup_instance_method "#{target}##{method}" unless raw_method? method
|
74
|
+
end
|
75
|
+
target.constantize.methods(false).each do |method|
|
76
|
+
cleanup_class_method "#{target}.#{method}" unless raw_method? method
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
86
80
|
def inject_class_method target
|
87
|
-
klass, _, method =
|
88
|
-
target.rpartition(".")
|
89
|
-
else
|
90
|
-
target.rpartition("::")
|
91
|
-
end
|
81
|
+
klass, _, method = target.rpartition(".")
|
92
82
|
klass.constantize.class_eval <<-EOS, __FILE__, __LINE__
|
93
83
|
class << self
|
94
84
|
#{build_watch_method target, method}
|
@@ -96,6 +86,15 @@ module Tailog
|
|
96
86
|
EOS
|
97
87
|
end
|
98
88
|
|
89
|
+
def cleanup_class_method target
|
90
|
+
klass, _, method = target.rpartition(".")
|
91
|
+
klass.constantize.class_eval <<-EOS, __FILE__, __LINE__
|
92
|
+
class << self
|
93
|
+
#{build_cleanup_method target, method}
|
94
|
+
end
|
95
|
+
EOS
|
96
|
+
end
|
97
|
+
|
99
98
|
def inject_instance_method target
|
100
99
|
klass, _, method = target.rpartition("#")
|
101
100
|
klass.constantize.class_eval <<-EOS, __FILE__, __LINE__
|
@@ -103,8 +102,15 @@ module Tailog
|
|
103
102
|
EOS
|
104
103
|
end
|
105
104
|
|
105
|
+
def cleanup_instance_method target
|
106
|
+
klass, _, method = target.rpartition("#")
|
107
|
+
klass.constantize.class_eval <<-EOS, __FILE__, __LINE__
|
108
|
+
#{build_cleanup_method target, method}
|
109
|
+
EOS
|
110
|
+
end
|
111
|
+
|
106
112
|
def build_watch_method target, method
|
107
|
-
raw_method = "
|
113
|
+
raw_method = "#{RAW_METHOD_PREFIX}#{method}"
|
108
114
|
return <<-EOS
|
109
115
|
unless instance_methods.include?(:#{raw_method})
|
110
116
|
alias_method :#{raw_method}, :#{method}
|
@@ -124,5 +130,15 @@ module Tailog
|
|
124
130
|
end
|
125
131
|
EOS
|
126
132
|
end
|
133
|
+
|
134
|
+
def build_cleanup_method target, method
|
135
|
+
raw_method = "#{RAW_METHOD_PREFIX}#{method}"
|
136
|
+
return <<-EOS
|
137
|
+
if method_defined? :#{raw_method}
|
138
|
+
alias_method :#{method}, :#{raw_method}
|
139
|
+
remove_method :#{raw_method}
|
140
|
+
end
|
141
|
+
EOS
|
142
|
+
end
|
127
143
|
end
|
128
144
|
end
|
data/lib/tailog.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'tailog/version'
|
2
|
+
require 'tailog/eval'
|
3
|
+
require 'tailog/request_id'
|
2
4
|
require 'tailog/watch_methods'
|
3
5
|
require 'tailog/ext/file'
|
4
6
|
|
@@ -11,7 +13,7 @@ module Tailog
|
|
11
13
|
extend Tailog::WatchMethods
|
12
14
|
|
13
15
|
class << self
|
14
|
-
attr_accessor :log_path
|
16
|
+
attr_accessor :log_path, :request_id
|
15
17
|
|
16
18
|
def server_hostname
|
17
19
|
@server_hostname ||= Socket.gethostname
|
data/tailog.gemspec
CHANGED
@@ -27,6 +27,8 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
28
|
spec.require_paths = ["lib"]
|
29
29
|
|
30
|
+
spec.add_dependency "sinatra", "~> 1.4"
|
31
|
+
|
30
32
|
spec.add_development_dependency "bundler", "~> 1.11"
|
31
33
|
spec.add_development_dependency "rake", "~> 10.0"
|
32
34
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tailog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- bbtfr
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-04-
|
11
|
+
date: 2016-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: sinatra
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.4'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -51,6 +65,7 @@ files:
|
|
51
65
|
- README.md
|
52
66
|
- Rakefile
|
53
67
|
- app/assets/javascripts/ansi_up.js
|
68
|
+
- app/assets/javascripts/jquery.highlight.js
|
54
69
|
- app/assets/stylesheets/application.css
|
55
70
|
- app/views/env.erb
|
56
71
|
- app/views/error.erb
|
@@ -63,7 +78,9 @@ files:
|
|
63
78
|
- bin/console
|
64
79
|
- bin/setup
|
65
80
|
- lib/tailog.rb
|
81
|
+
- lib/tailog/eval.rb
|
66
82
|
- lib/tailog/ext/file.rb
|
83
|
+
- lib/tailog/request_id.rb
|
67
84
|
- lib/tailog/version.rb
|
68
85
|
- lib/tailog/watch_methods.rb
|
69
86
|
- tailog.gemspec
|