Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New HTML info page for Windows #483

Merged
merged 14 commits into from
May 3, 2013
Merged
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
75 changes: 75 additions & 0 deletions checks/check_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,13 @@ def _header_lines(self, indent):
lines.append(l)
return lines + [""]

def to_dict(self):
return {
'pid': self.created_by_pid,
'status_date': "%s (%ss ago)" % (self.created_at.strftime('%Y-%m-%d %H:%M:%S'),
self.created_seconds_ago()),
}

@classmethod
def _not_running_message(cls):
lines = cls._title_lines() + [
Expand Down Expand Up @@ -396,6 +403,55 @@ def body_lines(self):

return lines

def to_dict(self):
status_info = AgentStatus.to_dict(self)

# Hostnames
status_info['hostnames'] = {}
metadata_whitelist = [
'hostname',
'fqdn',
'ipv4',
'instance-id'
]
if self.metadata:
for key, host in self.metadata.items():
for whitelist_item in metadata_whitelist:
if whitelist_item in key:
status_info['hostnames'][key] = host
break

# Checks.d Status
status_info['checks'] = {}
for cs in self.check_statuses:
status_info['checks'][cs.name] = {'instances': {}}
for s in cs.instance_statuses:
status_info['checks'][cs.name]['instances'][s.instance_id] = {
'status': s.status,
'has_error': s.has_error(),
'has_warnings': s.has_warnings(),
}
if s.has_error():
status_info['checks'][cs.name]['instances'][s.instance_id]['error'] = s.error
if s.has_warnings():
status_info['checks'][cs.name]['instances'][s.instance_id]['warnings'] = s.warnings
status_info['checks'][cs.name]['metric_count'] = cs.metric_count
status_info['checks'][cs.name]['event_count'] = cs.event_count

# Emitter status
status_info['emitter'] = []
for es in self.emitter_statuses:
check_status = {
'name': es.name,
'status': es.status,
'has_error': es.has_error(),
}
if es.has_error():
check_status['error'] = es.error
status_info['emitter'].append(check_status)

return status_info


class DogstatsdStatus(AgentStatus):

Expand All @@ -421,6 +477,16 @@ def body_lines(self):
]
return lines

def to_dict(self):
status_info = AgentStatus.to_dict(self)
status_info.update({
'flush_count': self.flush_count,
'packet_count': self.packet_count,
'packets_per_second': self.packets_per_second,
'metric_count': self.metric_count,
})
return status_info


class ForwarderStatus(AgentStatus):

Expand All @@ -442,3 +508,12 @@ def body_lines(self):

def has_error(self):
return self.flush_count == 0

def to_dict(self):
status_info = AgentStatus.to_dict(self)
status_info.update({
'flush_count': self.flush_count,
'queue_length': self.queue_length,
'queue_size': self.queue_size,
})
return status_info
12 changes: 11 additions & 1 deletion config.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,17 @@ def get_config(parse_args=True, cfg_path=None, options=None):
else:
agentConfig['use_pup'] = True

if agentConfig['use_pup']:
# Concerns only Windows
if config.has_option('Main', 'use_web_info_page'):
agentConfig['use_web_info_page'] = config.get('Main', 'use_web_info_page').lower() in ("yes", "true")
else:
agentConfig['use_web_info_page'] = True

# Pup doesn't work on Windows
if sys.platform == 'win32':
agentConfig['use_pup'] = False

if agentConfig['use_pup'] or agentConfig['use_web_info_page']:
if config.has_option('Main', 'pup_url'):
agentConfig['pup_url'] = config.get('Main', 'pup_url')
else:
Expand Down
13 changes: 9 additions & 4 deletions packaging/datadog-agent/win32/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ cp ..\..\..\checks.d\* install_files\checks.d
mkdir install_files\conf.d
cp ..\..\..\conf.d\* install_files\conf.d

# Copy the pup files into the install_files
cp -R ..\..\..\dist\pup install_files\pup

## Generate the UI install with NSIS

# Assumes makensis.exe is within the PATH
Expand All @@ -31,21 +34,23 @@ cp ..\..\..\conf.d\* install_files\conf.d

## Generate the CLI installer with WiX

# Generate fragments for the files in checks.d and conf.d
# Generate fragments for the files in checks.d, conf.d and pup
heat dir install_files\checks.d -gg -dr INSTALLDIR -var var.InstallFilesChecksD -cg checks.d -o wix\checksd.wxs
heat dir install_files\pup -gg -dr INSTALLDIR -var var.InstallFilesPup -cg pup -o wix\pup.wxs
heat dir install_files\conf.d -gg -dr APPLIDATIONDATADIRECTORY -t wix\confd.xslt -var var.InstallFilesConfD -cg conf.d -o wix\confd.wxs

# Create .wixobj files from agent.wxs, confd.wxs, checksd.wxs
$opts = '-dInstallFiles=install_files', '-dWixRoot=wix', '-dInstallFilesChecksD=install_files\checks.d', '-dInstallFilesConfD=install_files\conf.d', "-dAgentVersion=$version"
candle $opts wix\agent.wxs wix\checksd.wxs wix\confd.wxs
$opts = '-dInstallFiles=install_files', '-dWixRoot=wix', '-dInstallFilesChecksD=install_files\checks.d', '-dInstallFilesConfD=install_files\conf.d', '-dInstallFilesPup=install_files\pup', "-dAgentVersion=$version"
candle $opts wix\agent.wxs wix\checksd.wxs wix\confd.wxs wix\pup.wxs

# Light to create the msi
light agent.wixobj checksd.wixobj confd.wixobj -o ..\..\..\build\ddagent.msi
light agent.wixobj checksd.wixobj confd.wixobj pup.wixobj -o ..\..\..\build\ddagent.msi

# Clean up
rm *wixobj*
rm -r install_files\conf.d
rm -r install_files\checks.d
rm -r install_files\pup
rm -r install_files\Microsoft.VC90.CRT

# Move back to the root workspace
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[InternetShortcut]
URL=http://localhost:17125/status
IconFile=.\pup\static\favicon.ico
IconIndex=0
IDList=
HotKey=0
12 changes: 6 additions & 6 deletions packaging/datadog-agent/win32/install_files/datadog_win32.conf
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,16 @@ use_mount: no
# ca_certs = datadog-cert.pem

# ========================================================================== #
# Pup configuration
# Information page configuration
# ========================================================================== #

# Pup is a small server that displays metric data collected by the agent.
# Think of it as a fancy status page or a toe dip into the world of
# datadog. It can be connected to on the port below.
# Display general information about the running agent on a webpage
# Available at http://<pup_interface>:<pup_port>/status
# By default http://localhost:17125/status

# use_pup: yes
# use_web_info_page: yes
# pup_port: 17125
# pup_url: http://localhost:17125
# pup_interface: localhost

# ========================================================================== #
# DogStatsd configuration #
Expand Down
5 changes: 5 additions & 0 deletions packaging/datadog-agent/win32/nsis/agent.nsi
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,14 @@ Section "Datadog Agent" SecDummy
File "..\install_files\shell.exe"
File "..\install_files\ca-certificates.crt"
File "..\install_files\datadog-cert.pem"
File "..\install_files\datadog-agent-status.url"

; Install all of the checks.d checks
File /r "..\install_files\checks.d"

; Install all of the info page web files
File /r "..\install_files\pup"

; Config does in App Data
; Only write the config if it doesn't exist yet
${IfNot} ${FileExists} "$0\Datadog\datadog.conf"
Expand Down Expand Up @@ -202,6 +206,7 @@ Section "Uninstall"
Delete "$INSTDIR\ca-certificates.crt"
Delete "$INSTDIR\datadog-cert.pem"
Delete "$INSTDIR\license.txt"
Delete "$INSTDIR\datadog-agent-status.url"
Delete "$INSTDIR\Uninstall.exe"

RMDir "$INSTDIR"
Expand Down
5 changes: 5 additions & 0 deletions packaging/datadog-agent/win32/wix/agent.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@
<Component Id="license.txt" Guid="4B59F7AE-01AC-11E2-9AF6-28EC6088709B">
<File Id="license.txt" Source="$(var.InstallFiles)\license.txt" KeyPath="yes"></File>
</Component>
<Component Id="datadogagentstatus.url" Guid="B8F673AA-F5F7-4273-947A-21391678D6BD">
<File Id="datadogagentstatus.url" Source="$(var.InstallFiles)\datadog-agent-status.url" KeyPath="yes"></File>
</Component>
<Component Id="Microsoft.VC90.CRT.manifest" Guid="491C4E02-10C9-11E2-AC50-DD0B6288709B">
<File Id="Microsoft.VC90.CRT.manifest" Source="$(var.InstallFiles)\Microsoft.VC90.CRT\Microsoft.VC90.CRT.manifest" KeyPath="yes"></File>
</Component>
Expand All @@ -105,12 +108,14 @@
<ComponentRef Id="cacertificates.crt" />
<ComponentRef Id="datadogcert.pem" />
<ComponentRef Id="license.txt" />
<ComponentRef Id="datadogagentstatus.url" />
<ComponentRef Id="Microsoft.VC90.CRT.manifest" />
<ComponentRef Id="msvcp90.dll" />
<ComponentRef Id="msvcr90.dll" />
<ComponentRef Id="datadog.conf" />
<ComponentGroupRef Id="checks.d" />
<ComponentGroupRef Id="conf.d" />
<ComponentGroupRef Id="pup" />
</Feature>

<InstallExecuteSequence>
Expand Down
3 changes: 3 additions & 0 deletions pup/pup.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
<p id="listening">Listening on port <span id="port">{{ port }}</span></p>
<hr class="break" />

<div id="agent-status"><a href="/status">Agent status</a></div>
<hr class="break" />

<!-- If no data streaming -->
<p id="no-metrics">No metrics to search through.</p>

Expand Down
69 changes: 59 additions & 10 deletions pup/pup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,18 @@
import logging
import zlib

# Status page
import platform
from checks.check_status import DogstatsdStatus, ForwarderStatus, CollectorStatus, logger_info

# 3p
import tornado
from tornado import ioloop
from tornado import web
from tornado import websocket

# project
from config import get_config
from config import get_config, get_version
from util import json

log = logging.getLogger('pup')
Expand Down Expand Up @@ -105,6 +109,20 @@
'events'
]

# Define settings, path is different if using py2exe
frozen = getattr(sys, 'frozen', '')
if not frozen:
agent_root = os.path.join(os.path.dirname(__file__), '..')
else:
# Using py2exe
agent_root = os.path.dirname(sys.executable)

settings = {
"static_path": os.path.join(agent_root, "pup", "static"),
"cookie_secret": "61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=",
"xsrf_cookies": True,
}

# Check if using old version of Python. Pup's usage of defaultdict requires 2.5 or later,
# and tornado only supports 2.5 or later. The agent supports 2.6 onwards it seems.
if int(sys.version_info[1]) <= 5:
Expand Down Expand Up @@ -173,10 +191,26 @@ def agent_update(payload):

class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render("pup.html",
self.render(os.path.join(agent_root, "pup", "pup.html"),
title="Pup",
port=port)

class StatusHandler(tornado.web.RequestHandler):
def get(self):
dogstatsd_status = DogstatsdStatus.load_latest_status()
forwarder_status = ForwarderStatus.load_latest_status()
collector_status = CollectorStatus.load_latest_status()
self.render(os.path.join(agent_root, "pup", "status.html"),
port=port,
platform=platform.platform(),
agent_version=get_version(),
python_version=platform.python_version(),
logger_info=logger_info(),
dogstatsd=dogstatsd_status.to_dict(),
forwarder=forwarder_status.to_dict(),
collector=collector_status.to_dict(),
)

class PostHandler(tornado.web.RequestHandler):
def post(self):
try:
Expand Down Expand Up @@ -207,13 +241,6 @@ def on_message(self):
def on_close(self):
del listeners[self]

settings = {
"static_path": os.path.join(os.path.dirname(__file__), "static"),
"cookie_secret": "61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=",
"xsrf_cookies": True,
}



def tornado_logger(handler):
""" Override the tornado logging method.
Expand All @@ -228,11 +255,11 @@ def tornado_logger(handler):
request_time = 1000.0 * handler.request.request_time()
log_method("%d %s %.2fms", handler.get_status(),
handler._request_summary(), request_time)



application = tornado.web.Application([
(r"/", MainHandler),
(r"/status", StatusHandler),
(r"/(.*\..*$)", tornado.web.StaticFileHandler,
dict(path=settings['static_path'])),
(r"/pupsocket", PupSocket),
Expand All @@ -259,6 +286,28 @@ def run_pup(config):
scheduler.start()
io_loop.start()

def run_info_page():
global port

config = get_config(parse_args=False)

info_page_application = tornado.web.Application([
(r"/", StatusHandler),
(r"/status", StatusHandler),
(r"/(.*\..*$)", tornado.web.StaticFileHandler,
dict(path=settings['static_path'])),
], log_function=tornado_logger)

port = config.get('pup_port', 17125)
interface = config.get('pup_interface', 'localhost')

info_page_application.listen(port, address=interface)

io_loop = ioloop.IOLoop.instance().start()

def stop_info_page():
ioloop.IOLoop.instance().stop()

def main():
""" Parses arguments and starts Pup server """

Expand Down
Binary file added pup/static/OpenSans-Bold-webfont.ttf
Binary file not shown.
Loading