Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
slapos
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Roque
slapos
Commits
100153ea
Commit
100153ea
authored
Jan 22, 2015
by
Alain Takoudjou
Committed by
Tristan Cavelier
Mar 31, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
monitor: tail -f the logs on monitoring stack (one file or many files)
parent
f2cfdbb8
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
279 additions
and
1 deletion
+279
-1
stack/monitor/buildout.cfg
stack/monitor/buildout.cfg
+9
-1
stack/monitor/cgi-httpd.conf.in
stack/monitor/cgi-httpd.conf.in
+4
-0
stack/monitor/logTools.py
stack/monitor/logTools.py
+69
-0
stack/monitor/monitor.cfg.in
stack/monitor/monitor.cfg.in
+20
-0
stack/monitor/webfile-directory/logfile.cgi.in
stack/monitor/webfile-directory/logfile.cgi.in
+177
-0
No files found.
stack/monitor/buildout.cfg
View file @
100153ea
...
...
@@ -60,7 +60,7 @@ mode = 0644
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/${:filename}
download-only = true
md5sum = 2d48f8b8e01fa0fdde964ed1c1547f05
#md5sum =
filename = cgi-httpd.conf.in
mode = 0644
...
...
@@ -90,6 +90,14 @@ download-only = true
filename = information.html.in
mode = 0644
[logfile-cgi]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename}
download-only = true
#md5sum =
filename = logfile.cgi.in
mode = 0644
[status-cgi]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename}
...
...
stack/monitor/cgi-httpd.conf.in
View file @
100153ea
...
...
@@ -24,6 +24,7 @@ LoadModule authn_file_module modules/mod_authn_file.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule env_module modules/mod_env.so
# SSL Configuration
<IfDefine !SSLConfigured>
...
...
@@ -38,6 +39,9 @@ SSLProtocol -ALL +SSLv3 +TLSv1
SSLHonorCipherOrder On
SSLCipherSuite RC4-SHA:HIGH:!ADH
</IfDefine>
{% for key, value in environment_dict.items() -%}
SetEnv {{ key }} "{{ value }}"
{% endfor -%}
SSLEngine On
ScriptSock {{ httpd_configuration.get('cgid-pid-file') }}
<Directory {{ directory.get('www') }}>
...
...
stack/monitor/logTools.py
View file @
100153ea
...
...
@@ -167,3 +167,72 @@ def generateRSS(db_path, name, rss_path, url_link, limit=10):
with open(rss_path, 'w') as rss_ouput:
rss_ouput.write(rss_feed.to_xml())
def tail(f, lines=20):
"""
Returns the last `lines` lines of file `f`. It is an implementation of tail -f n.
"""
BUFSIZ = 1024
f.seek(0, 2)
bytes = f.tell()
size = lines + 1
block = -1
data = []
while size > 0 and bytes > 0:
if bytes - BUFSIZ > 0:
# Seek back one whole BUFSIZ
f.seek(block * BUFSIZ, 2)
# read BUFFER
data.insert(0, f.read(BUFSIZ))
else:
# file too small, start from begining
f.seek(0, 0)
# only read what was not read
data.insert(0, f.read(bytes))
linesFound = data[0].count('
\
n
')
size -= linesFound
bytes -= BUFSIZ
block -= 1
return '
\
n
'.join(''.join(data).splitlines()[-lines:])
def readFileFrom(f, lastPosition, limit=20000):
"""
Returns the last lines of file `f`, from position lastPosition.
and the last position
limit = max number of characters to read
"""
BUFSIZ = 1024
f.seek(0, 2)
# XXX-Marco do now shadow 'bytes'
bytes = f.tell()
block = -1
data = ""
length = bytes
truncated = False # True if a part of log data has been truncated
if (lastPosition <= 0 and length > limit) or (length - lastPosition > limit):
lastPosition = length - limit
truncated = True
size = bytes - lastPosition
while bytes > lastPosition:
if abs(block * BUFSIZ) <= size:
# Seek back one whole BUFSIZ
f.seek(block * BUFSIZ, 2)
data = f.read(BUFSIZ) + data
else:
margin = abs(block * BUFSIZ) - size
if length < BUFSIZ:
f.seek(0, 0)
else:
seek = block * BUFSIZ + margin
f.seek(seek, 2)
data = f.read(BUFSIZ - margin) + data
bytes -= BUFSIZ
block -= 1
f.close()
return {
'content': data,
'position': length,
'truncated': truncated
}
stack/monitor/monitor.cfg.in
View file @
100153ea
...
...
@@ -179,6 +179,22 @@ context =
key monitoring_file_json monitor-parameters:json-path
raw python_executable ${buildout:executable}
[deploy-logfile-cgi]
recipe = slapos.recipe.template:jinja2
template = ${logfile-cgi:location}/${logfile-cgi:filename}
rendered = $${monitor-directory:monitoring-cgi}/$${:filename}
filename = Files.cgi
script-path= monitoring/Files.cgi
mode = 0744
context =
key monitor_bin monitor-parameters:executable
key script_path :script-path
section base_folder_list log-folder-cgi
raw python_executable ${buildout:directory}/bin/${extra-eggs:interpreter}
[log-folder-cgi]
log-folder = $${monitor-directory:log}
[make-rss]
recipe = slapos.recipe.template:jinja2
template = ${make-rss-script:output}
...
...
@@ -353,6 +369,9 @@ listening-ip = $${slap-parameters:ipv6-random}
certificate = $${ca-httpd:cert-file}
key = $${ca-httpd:key-file}
[httpd-environment]
PYTHONPATH = ${log-tools:location}
[monitor-httpd-configuration-file]
recipe = slapos.recipe.template:jinja2
template = ${monitor-httpd-template:destination}/${monitor-httpd-template:filename}
...
...
@@ -363,6 +382,7 @@ context =
section monitor_parameters monitor-parameters
section httpd_configuration monitor-httpd-configuration
section monitor_rewrite_rule monitor-rewrite-rule
section environment_dict httpd-environment
[cgi-httpd-wrapper]
recipe = slapos.cookbook:wrapper
...
...
stack/monitor/webfile-directory/logfile.cgi.in
0 → 100644
View file @
100153ea
#!{{ python_executable }}
import cgi
import cgitb
import json
import os
import subprocess
import logTools
import codecs
cgitb.enable(display=0, logdir="/tmp/cgi.log")
form = cgi.FieldStorage()
base_folder_list = {{ base_folder_list }}
script_path = "{{ script_path }}"
logpath = form.getvalue("path", "")
size = int(form.getvalue("size", "200"))
print """
<html><head>
<link
rel=
"stylesheet"
href=
"static/pure-min.css"
>
<link
rel=
"stylesheet"
href=
"static/style.css"
>
<script
src=
"static/jquery-1.10.2.min.js"
></script>
<style>
.head
{
background-color
:
#0078e7
;
border
:
0px
solid
#ffffff
;
text-align
:
left
;
border-width
:
0px
0px
1px
1px
;
font-size
:
18px
;
font-family
:
Helvetica
;
font-weight
:
normal
;
color
:
#ffffff
;
display
:
block
;
padding
:
10px
;
margin
:
0
;
}
.box
{
border
:
1px
solid
#e8eaed
;
padding
:
5px
;
}
textarea
{
width
:
100%
;
height
:
470px
;
margin-top
:
10px
;}
ul
{
margin
:
0px
;
padding
:
0px
;
list-style
:
none
;}
.button
{
margin-top
:
5px
;}
.button
div
{
margin
:
0
;
margin-right
:
10px
;
float
:
left
;
}
</style>
<script
language=
"javascript"
type=
"text/javascript"
>
$
(
document
).
ready
(
function
()
{
$
(
"
.file
"
).
click
(
function
()
{
var
child
=
$
(
this
).
children
(
'
input[type=checkbox]
'
);
if
(
!
$
(
child
).
is
(
'
:checked
'
)
)
{
$
(
child
).
prop
(
"
checked
"
,
true
);
}
else
{
$
(
child
).
prop
(
"
checked
"
,
false
);}
});
$
(
"
#open
"
).
click
(
function
()
{
var
file_list
=
""
;
$
(
"
.file
"
).
each
(
function
()
{
if
(
$
(
this
).
children
(
'
input[type=checkbox]
'
).
is
(
'
:checked
'
)
)
{
file_list
+=
$
(
this
).
attr
(
"
rel
"
)
+
"
#
"
;
}
});
if
(
file_list
==
""
)
{
return
false
;}
$
(
"
#path
"
).
val
(
file_list
);
$
(
"
#log_form
"
).
submit
();
return
false
;
});
$
(
"
#check
"
).
click
(
function
()
{
$
(
"
.file
"
).
each
(
function
()
{
var
child
=
$
(
this
).
children
(
'
input[type=checkbox]
'
);
if
(
!
$
(
child
).
is
(
'
:checked
'
)
)
{
$
(
child
).
prop
(
"
checked
"
,
true
);
}
});
return
false
;
});
$
(
"
#uncheck
"
).
click
(
function
()
{
$
(
"
.file
"
).
each
(
function
()
{
var
child
=
$
(
this
).
children
(
'
input[type=checkbox]
'
);
if
(
$
(
child
).
is
(
'
:checked
'
)
)
{
$
(
child
).
prop
(
"
checked
"
,
false
);
}
});
return
false
;
});
$
(
"
#reload
"
).
click
(
function
()
{
$
(
"
#log_form
"
).
submit
();
return
false
;
});
$
(
"
#return
"
).
click
(
function
()
{
$
(
"
#path
"
).
val
(
""
);
$
(
"
#log_form
"
).
submit
();
return
false
;
});
var
textarea
=
$
(
"
#logcontent
"
)
if
(
textarea
!=
undefined
)
{
$
(
textarea
).
animate
({
scrollTop
:
$
(
textarea
)[
0
].
scrollHeight
-
$
(
textarea
).
height
()
},
"
slow
"
);
}
});
</script>
</head><body>
"""
if not logpath:
print """
<form
action=
"/index.cgi"
method=
"post"
class=
"pure-form-aligned"
id=
"log_form"
>
<input
type=
"hidden"
name=
"posting-script"
value=
"%s"
/>
<div
class=
"box pure-menu pure-menu-open"
>
<h2
class=
"head"
>
Select file(s) in the list bellow
</h2>
<ul>
""" % script_path
for base_folder in base_folder_list.values():
if os.path.exists(base_folder):
for filename in os.listdir(base_folder):
path = os.path.join(base_folder, filename)
if not os.path.isdir(path):
print """
<li>
<a
href=
"#"
class=
"script file"
rel=
"%s"
title=
"%s"
>
<input
type=
"checkbox"
/>
%s
</a></li>
""" % (
path, path, filename)
else:
# accept a folder containing log files
for sub_filename in os.listdir(path):
sub_path = os.path.join(path, sub_filename)
if os.path.isdir(sub_path):
continue
print """
<li><a
href=
"#"
class=
"script file"
rel=
"%s"
title=
"%s"
>
%s
</a></li>
""" % (
sub_path, sub_path, sub_filename)
print """
</ul>
</div>
<div
class=
"button"
>
<div><label
for=
"size"
>
Lines:
</label><select
name=
"size"
id=
"size"
>
<option
value=
"50"
selected
>
50
</option>
<option
value=
"100"
>
100
</option>
<option
value=
"200"
>
200
</option>
<option
value=
"500"
>
500
</option>
<option
value=
"1500"
>
1500
</option>
</select></div>
<button
type=
"button"
class=
"pure-button pure-button-primary"
id=
"uncheck"
>
Uncheck All
</button>
<button
type=
"button"
class=
"pure-button pure-button-primary"
id=
"check"
>
Check All
</button>
<button
type=
"button"
class=
"pure-button pure-button-primary"
id=
"open"
>
Open File(s)
</button>
</div>
<div
style=
'clear:both'
></div>
<input
type=
"hidden"
name=
"path"
id=
"path"
value=
""
/>
</form>
"""
else:
path_list = [x for x in logpath.split('#') if x]
log_content = ""
title = ""
for filepath in path_list:
if os.path.exists(filepath) and os.path.isfile(filepath):
title += " " + filepath.split('/')[-1:][0]
try:
content = logTools.tail(codecs.open(filepath, "r", "utf_8"), size)
except Exception, e:
content = str(e)
if content:
log_content += "TAIL FILE %s >>>>\n\n" % filepath
log_content += content + "\n\n\n"
print """
<form
action=
"/index.cgi"
method=
"post"
class=
"pure-form-aligned"
id=
"log_form"
>
<input
type=
"hidden"
name=
"posting-script"
value=
"%s"
/>
<input
type=
"hidden"
name=
"path"
id=
"path"
value=
"%s"
/>
</form>
<div
class=
"box"
>
<h2
class=
"head"
>
Tail: %s
</h2>
<div
class=
"button"
>
<button
type=
"submit"
class=
"pure-button pure-button-primary"
id=
"return"
>
Return
</button>
<button
type=
"submit"
class=
"pure-button pure-button-primary"
id=
"reload"
>
Refresh
</button>
</div>
<div
style=
'clear:both'
></div>
<textarea
id=
"logcontent"
>
%s
</textarea>
</div>
""" % (script_path, logpath, title, log_content)
print """
</body></html>
"""
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment