server/log_tee: shim to duplicate log streams

Fixes #28
This commit is contained in:
Emery Hemingway
2016-07-28 20:56:36 +02:00
committed by Norman Feske
parent 3af80e2d88
commit 3c25710f43
4 changed files with 186 additions and 0 deletions

33
run/log_tee.run Normal file
View File

@@ -0,0 +1,33 @@
build "core init server/log_tee test/printf"
create_boot_directory
install_config {
<config>
<parent-provides>
<service name="LOG"/>
<service name="RM"/>
</parent-provides>
<default-route>
<any-service> <parent/> </any-service>
</default-route>
<start name="log_tee">
<resource name="RAM" quantum="2M"/>
<provides> <service name="LOG"/> </provides>
</start>
<start name="test-printf">
<resource name="RAM" quantum="2M"/>
<route>
<any-service> <child name="log_tee"/> <parent/> </any-service>
</route>
</start>
</config>
}
build_boot_image "core init log_tee test-printf"
append qemu_args "-nographic -m 64"
run_genode_until {child "test-printf" exited with exit value 0} 10

41
src/server/log_tee/README Normal file
View File

@@ -0,0 +1,41 @@
Log_tee is a LOG shim server that writes client messages to
dedicated LOG sessions as well as a global component log. The
effect is that log messages are duplicated into two streams.
This component pays for each client session from its own quota,
client quota donations are forwarded to the LOG backends. This
is to prevent naive client donations from being depleted before
reaching the final logging destination.
Example: log messages should be written to the file-system,
the screen, and the kernel log.
log_tee → terminal_log (on-screen)
log_tee → parent (kernel)
fs_log (file-system)
!
! <start name="terminal_log"> ... </start>
! <start name="fs_log"> ... </start>
!
! <start name="log_tee_2">
! <binary name="log_tee"/>
! <resource name="RAM" quantum="4M"/>
! <provides> <service name="LOG"/> </provides>
! <route>
! <service name="LOG" label=""> <child name="terminal_log"/> </service>
! <service name="LOG"> <child name="log_tee_1"/> </service>
! </start>
!
! <start name="log_tee_1">
! <binary name="log_tee"/>
! <resource name="RAM" quantum="4M"/>
! <provides> <service name="LOG"/> </provides>
! <route>
! <service name="LOG" label=""> <parent/> </service>
! <service name="LOG"> <child name="fs_log"/> </service>
! </start>
!

View File

@@ -0,0 +1,109 @@
/*
* \brief Server that duplicates log streams
* \author Emery Hemingway
* \date 2016-07-28
*/
/*
* Copyright (C) 2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <log_session/connection.h>
#include <root/component.h>
#include <base/component.h>
#include <base/session_label.h>
#include <base/log.h>
#include <base/snprintf.h>
#include <util/list.h>
namespace Log_tee {
using namespace Genode;
class Session_component;
class Root_component;
}
class Log_tee::Session_component : public Rpc_object<Log_session>
{
private:
/* craft our own connection to get a label in */
struct Log_connection : Connection<Log_session>, Log_session_client
{
Log_connection(Env &env, char const *args)
:
Connection<Log_session>(env, session(env.parent(), args)),
Log_session_client(cap())
{ }
} _log;
char _prefix[Session_label::capacity()+3];
public:
Session_component(Env &env, Session_label const &label, char const *args)
: _log(env, args)
{ snprintf(_prefix, sizeof(_prefix), "[%s] ", label.string()); }
size_t write(Log_session::String const &msg) override
{
/* write to the dedicated client log session */
size_t n = _log.write(msg);
/* write to our own log session */
log((char const *)_prefix, msg.string());
return n;
}
};
class Log_tee::Root_component :
public Genode::Root_component<Log_tee::Session_component>
{
private:
Env &_env;
protected:
Log_tee::Session_component *_create_session(char const *args) override
{
Session_label const label = label_from_args(args);
try { return new (md_alloc()) Session_component(_env, label, args); }
catch (Genode::Parent::Service_denied) { throw Root::Unavailable(); }
}
public:
Root_component(Env &env, Allocator &alloc)
:
Genode::Root_component<Log_tee::Session_component>(env.ep(), alloc),
_env(env)
{ }
};
Genode::size_t Component::stack_size() { return 2*1024*sizeof(Genode::addr_t); }
void Component::construct(Genode::Env &env)
{
/*
* Client sessions are not allocated on seperate dataspaces,
* they are allocated on a heap against the component's own
* RAM quota. The session RAM donation is passed verbatim to
* the backend session.
*/
static Genode::Heap heap(env.ram(), env.rm());
static Log_tee::Root_component root(env, heap);
env.parent().announce(env.ep().manage(root));
}

View File

@@ -0,0 +1,3 @@
TARGET := log_tee
SRC_CC := component.cc
LIBS := base