Basic log output

This commit is contained in:
Aanand Prasad 2013-12-18 14:58:58 +00:00
parent 23c3dc430b
commit 64253a8290
4 changed files with 139 additions and 0 deletions

41
plum/cli/colors.py Normal file
View File

@ -0,0 +1,41 @@
NAMES = [
'grey',
'red',
'green',
'yellow',
'blue',
'magenta',
'cyan',
'white'
]
def get_pairs():
for i, name in enumerate(NAMES):
yield(name, str(30 + i))
yield('intense_' + name, str(30 + i) + ';1')
def ansi(code):
return '\033[{0}m'.format(code)
def ansi_color(code, s):
return '{0}{1}{2}'.format(ansi(code), s, ansi(0))
def make_color_fn(code):
return lambda s: ansi_color(code, s)
for (name, code) in get_pairs():
globals()[name] = make_color_fn(code)
def rainbow():
cs = ['cyan', 'yellow', 'green', 'magenta', 'red', 'blue',
'intense_cyan', 'intense_yellow', 'intense_green',
'intense_magenta', 'intense_red', 'intense_blue']
for c in cs:
yield globals()[c]

53
plum/cli/log_printer.py Normal file
View File

@ -0,0 +1,53 @@
import sys
from itertools import cycle
from ..service import get_container_name
from .multiplexer import Multiplexer
from . import colors
class LogPrinter(object):
def __init__(self, client):
self.client = client
def attach(self, containers):
generators = self._make_log_generators(containers)
mux = Multiplexer(generators)
for line in mux.loop():
sys.stdout.write(line)
def _make_log_generators(self, containers):
color_fns = cycle(colors.rainbow())
generators = []
for container in containers:
color_fn = color_fns.next()
generators.append(self._make_log_generator(container, color_fn))
return generators
def _make_log_generator(self, container, color_fn):
container_name = get_container_name(container)
format = lambda line: color_fn(container_name + " | ") + line
return (format(line) for line in self._readlines(container))
def _readlines(self, container, logs=False, stream=True):
socket = self.client.attach_socket(
container['Id'],
params={
'stdin': 0,
'stdout': 1,
'stderr': 1,
'logs': 1 if logs else 0,
'stream': 1 if stream else 0
},
)
for line in iter(socket.makefile().readline, b''):
if not line.endswith('\n'):
line += '\n'
yield line
socket.close()

View File

@ -11,6 +11,7 @@ from .. import __version__
from ..service import get_container_name
from ..service_collection import ServiceCollection
from .command import Command
from .log_printer import LogPrinter
from .errors import UserError
from .docopt_command import NoSuchCommand
@ -113,3 +114,15 @@ class TopLevelCommand(Command):
"""
self.service_collection.stop()
def logs(self, options):
"""
View containers' output
Usage: logs
"""
containers = self._get_containers(all=False)
print "Attaching to", ", ".join(get_container_name(c) for c in containers)
LogPrinter(client=self.client).attach(containers)
def _get_containers(self, all):
return [c for s in self.service_collection for c in s.get_containers(all=all)]

32
plum/cli/multiplexer.py Normal file
View File

@ -0,0 +1,32 @@
from threading import Thread
try:
from Queue import Queue, Empty
except ImportError:
from queue import Queue, Empty # Python 3.x
class Multiplexer(object):
def __init__(self, generators):
self.generators = generators
self.queue = Queue()
def loop(self):
self._init_readers()
while True:
try:
yield self.queue.get(timeout=0.1)
except Empty:
pass
def _init_readers(self):
for generator in self.generators:
t = Thread(target=_enqueue_output, args=(generator, self.queue))
t.daemon = True
t.start()
def _enqueue_output(generator, queue):
for item in generator:
queue.put(item)