mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-08 03:45:24 +00:00
parent
7ce19216f4
commit
ce1e6c16fb
@ -1,18 +0,0 @@
|
||||
LOG server that writes log messages onto a file system.
|
||||
|
||||
Using this component, log messages of different processes can be redirected
|
||||
to files on a file-system service. The assignment of processes to files can
|
||||
be expressed in the configuration as follows:
|
||||
|
||||
! <start name="fs_log">
|
||||
! <resource name="RAM" quantum="2M"/>
|
||||
! <provides><service name="LOG"/></provides>
|
||||
! <config>
|
||||
! <policy label="noux" file="/noux.log" />
|
||||
! <policy label="noux ->" file="/noux_process.log" />
|
||||
! </config>
|
||||
! </start>
|
||||
|
||||
In this example, all messages originating from the noux process are directed
|
||||
to the file '/noux.log'. All messages originating from children of the noux
|
||||
process end up in the file '/noux_process.log'.
|
@ -1,171 +0,0 @@
|
||||
/*
|
||||
* \brief LOG service that writes to a file
|
||||
* \author Alexander Tarasikov <tarasikov@ksyslabs.org>
|
||||
* \author Norman Feske <norman.feske@genode-labs.com>
|
||||
* \date 2013-05-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Ksys Labs LLC
|
||||
* Copyright (C) 2012-2013 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 <base/env.h>
|
||||
#include <base/rpc_server.h>
|
||||
#include <base/sleep.h>
|
||||
#include <root/component.h>
|
||||
#include <util/string.h>
|
||||
#include <os/session_policy.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <log_session/log_session.h>
|
||||
|
||||
/* libc includes */
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
class Log_component : public Genode::Rpc_object<Genode::Log_session>
|
||||
{
|
||||
public:
|
||||
|
||||
enum { LABEL_LEN = 64 };
|
||||
|
||||
private:
|
||||
|
||||
typedef Genode::size_t size_t;
|
||||
|
||||
char _label[LABEL_LEN];
|
||||
size_t _label_len;
|
||||
int _fd;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Log_component(const char *label, char const *filename)
|
||||
:
|
||||
_fd(::open(filename, O_CREAT | O_WRONLY | O_APPEND))
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (_fd < 0) {
|
||||
PERR("unable to open \"%s\"", filename);
|
||||
throw Root::Unavailable();
|
||||
}
|
||||
|
||||
snprintf(_label, LABEL_LEN, "[%s] ", label);
|
||||
_label_len = strlen(_label);
|
||||
|
||||
PINF("log client \"%s\" to file \"%s\")", label, filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Log_component() { ::close(_fd); }
|
||||
|
||||
|
||||
/*****************
|
||||
** Log session **
|
||||
*****************/
|
||||
|
||||
/**
|
||||
* Write a log-message to the file.
|
||||
*/
|
||||
size_t write(String const &string_buf)
|
||||
{
|
||||
if (!(string_buf.is_valid_string())) {
|
||||
PERR("corrupted string");
|
||||
return 0;
|
||||
}
|
||||
|
||||
char const *string = string_buf.string();
|
||||
Genode::size_t const len = Genode::strlen(string);
|
||||
|
||||
::write(_fd, _label, _label_len);
|
||||
::write(_fd, string, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Log_root : public Genode::Root_component<Log_component>
|
||||
{
|
||||
private:
|
||||
|
||||
int _fd;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Root component interface
|
||||
*/
|
||||
Log_component *_create_session(const char *args)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
char label_buf[Log_component::LABEL_LEN];
|
||||
Arg label_arg = Arg_string::find_arg(args, "label");
|
||||
label_arg.string(label_buf, sizeof(label_buf), "");
|
||||
|
||||
/* obtain file name from configured policy */
|
||||
enum { FILENAME_MAX_LEN = 256 };
|
||||
char filename[FILENAME_MAX_LEN];
|
||||
try {
|
||||
Session_label label(args);
|
||||
Session_policy policy(label);
|
||||
policy.attribute("file").value(filename, sizeof(filename));
|
||||
} catch (...) {
|
||||
PERR("Invalid session request, no matching policy");
|
||||
throw Root::Unavailable();
|
||||
}
|
||||
|
||||
return new (md_alloc()) Log_component(label_buf, filename);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param session_ep entry point for managing cpu session objects
|
||||
* \param md_alloc meta-data allocator to be used by root component
|
||||
*/
|
||||
Log_root(Genode::Rpc_entrypoint *session_ep, Genode::Allocator *md_alloc)
|
||||
: Genode::Root_component<Log_component>(session_ep, md_alloc) { }
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
/*
|
||||
* Initialize server entry point
|
||||
*
|
||||
* Use a large stack because we are calling libc functions from the
|
||||
* context of the entrypoint.
|
||||
*/
|
||||
enum { STACK_SIZE = sizeof(addr_t)*16*1024 };
|
||||
static Cap_connection cap;
|
||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "fs_log_ep");
|
||||
|
||||
static Log_root log_root(&ep, env()->heap());
|
||||
|
||||
/*
|
||||
* Announce services
|
||||
*/
|
||||
env()->parent()->announce(ep.manage(&log_root));
|
||||
|
||||
/**
|
||||
* Got to sleep forever
|
||||
*/
|
||||
sleep_forever();
|
||||
return 0;
|
||||
}
|
20
repos/os/src/server/fs_log/README
Normal file
20
repos/os/src/server/fs_log/README
Normal file
@ -0,0 +1,20 @@
|
||||
LOG server that writes log messages onto a file system.
|
||||
|
||||
Log files are creating in a directory tree formed from session labels.
|
||||
As an example the session label "init -> nitpicker" would create
|
||||
a log file at "init/nitpicker.log". The behavior of opening two LOG
|
||||
sessions with the same label is undefined.
|
||||
|
||||
The only configuration and policy available is the option to truncate
|
||||
files at the start of the LOG session, which is disabled by default.
|
||||
|
||||
:Example configuration:
|
||||
! <start name="log_file">
|
||||
! <resource name="RAM" quantum="1M"/>
|
||||
! <provides><service name="LOG"/></provides>
|
||||
! <config>
|
||||
! <policy label="nic_drv" truncate="no"/>
|
||||
! <policy label="" truncate="yes"/>
|
||||
! </config>
|
||||
! </start>
|
||||
|
184
repos/os/src/server/fs_log/main.cc
Normal file
184
repos/os/src/server/fs_log/main.cc
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* \brief Server that writes log messages to a file system.
|
||||
* \author Emery Hemingway
|
||||
* \date 2015-05-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 <file_system_session/connection.h>
|
||||
#include <file_system/util.h>
|
||||
#include <root/component.h>
|
||||
#include <os/server.h>
|
||||
#include <os/session_policy.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
/* Local includes */
|
||||
#include "session.h"
|
||||
|
||||
namespace Fs_log {
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
class Root_component;
|
||||
struct Main;
|
||||
|
||||
enum {
|
||||
BLOCK_SIZE = Log_session::String::MAX_SIZE,
|
||||
QUEUE_SIZE = File_system::Session::TX_QUEUE_SIZE,
|
||||
TX_BUF_SIZE = BLOCK_SIZE * QUEUE_SIZE
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class Fs_log::Root_component : public Genode::Root_component<Fs_log::Session_component>
|
||||
{
|
||||
private:
|
||||
|
||||
Allocator_avl _write_alloc;
|
||||
File_system::Connection _fs;
|
||||
|
||||
File_system::File_handle open_file(File_system::Dir_handle &dir_handle,
|
||||
char const *name)
|
||||
{
|
||||
try {
|
||||
return _fs.file(dir_handle, name, File_system::WRITE_ONLY, false);
|
||||
} catch (File_system::Lookup_failed) {
|
||||
return _fs.file(dir_handle, name, File_system::WRITE_ONLY, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
Session_component *_create_session(const char *args)
|
||||
{
|
||||
using namespace File_system;
|
||||
|
||||
char path[MAX_PATH_LEN];
|
||||
path[0] = '/';
|
||||
char name[MAX_NAME_LEN];
|
||||
|
||||
Session_label session_label(args);
|
||||
strncpy(path+1, session_label.string(), sizeof(path)-1);
|
||||
|
||||
bool truncate = false;
|
||||
try {
|
||||
Session_policy policy(session_label);
|
||||
try {
|
||||
truncate = policy.attribute("truncate").has_value("yes");
|
||||
} catch (Xml_node::Nonexistent_attribute) { }
|
||||
|
||||
} catch (Session_policy::No_policy_defined) { }
|
||||
|
||||
size_t len = strlen(path);
|
||||
size_t start = 1;
|
||||
for (size_t i = 1; i < len;) {
|
||||
/* Replace any slashes in label elements. */
|
||||
if (path[i] == '/') path[i] = '_';
|
||||
if (strcmp(" -> ", path+i, 4) == 0) {
|
||||
path[i++] = '/';
|
||||
strncpy(path+i, path+i+3, sizeof(path)-i);
|
||||
start = i;
|
||||
i += 3;
|
||||
} else ++i;
|
||||
}
|
||||
|
||||
snprintf(name, sizeof(name), "%s.log", path+start);
|
||||
path[(start == 1) ? start : start-1] = '\0';
|
||||
|
||||
/* Rewrite any slashes in the name. */
|
||||
for (char *p = name; *p; ++p)
|
||||
if (*p == '/') *p = '_';
|
||||
|
||||
File_handle file_handle;
|
||||
seek_off_t offset = 0;
|
||||
try {
|
||||
Dir_handle dir_handle = ensure_dir(_fs, path);
|
||||
Handle_guard dir_guard(_fs, dir_handle);
|
||||
|
||||
file_handle = open_file(dir_handle, name);
|
||||
|
||||
if (truncate)
|
||||
_fs.truncate(file_handle, 0);
|
||||
else
|
||||
offset = _fs.status(file_handle).size;
|
||||
|
||||
} catch (Permission_denied) {
|
||||
PERR("%s/%s: permission denied", path, name);
|
||||
throw Root::Unavailable();
|
||||
|
||||
} catch (Name_too_long) {
|
||||
PERR("%s/%s: name too long", path, name);
|
||||
throw Root::Unavailable();
|
||||
|
||||
} catch (No_space) {
|
||||
PERR("%s/%s: no space", path, name);
|
||||
throw Root::Unavailable();
|
||||
|
||||
} catch (Out_of_node_handles) {
|
||||
PERR("%s/%s: out of node handles", path, name);
|
||||
throw Root::Unavailable();
|
||||
|
||||
} catch (Invalid_name) {
|
||||
PERR("%s/%s: invalid_name", path, name);
|
||||
throw Root::Unavailable();
|
||||
|
||||
} catch (Size_limit_reached) {
|
||||
PERR("%s/%s: size limit reached", path, name);
|
||||
throw Root::Unavailable();
|
||||
|
||||
} catch (...) {
|
||||
PERR("%s/%s: unknown error", path, name);
|
||||
throw Root::Unavailable();
|
||||
}
|
||||
|
||||
return new (md_alloc()) Session_component(_fs, file_handle, offset);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Root_component(Server::Entrypoint &ep, Allocator &alloc)
|
||||
:
|
||||
Genode::Root_component<Session_component>(&ep.rpc_ep(), &alloc),
|
||||
_write_alloc(env()->heap()),
|
||||
_fs(_write_alloc, TX_BUF_SIZE)
|
||||
{ }
|
||||
|
||||
};
|
||||
|
||||
struct Fs_log::Main
|
||||
{
|
||||
Server::Entrypoint &ep;
|
||||
|
||||
Sliced_heap sliced_heap = { env()->ram_session(), env()->rm_session() };
|
||||
|
||||
Root_component root { ep, sliced_heap };
|
||||
|
||||
Main(Server::Entrypoint &ep)
|
||||
: ep(ep)
|
||||
{ Genode::env()->parent()->announce(ep.manage(root)); }
|
||||
};
|
||||
|
||||
|
||||
/************
|
||||
** Server **
|
||||
************/
|
||||
|
||||
namespace Server {
|
||||
|
||||
char const* name() { return "fs_log_ep"; }
|
||||
|
||||
size_t stack_size() { return 3*512*sizeof(long); }
|
||||
|
||||
void construct(Entrypoint &ep) { static Fs_log::Main inst(ep); }
|
||||
|
||||
}
|
100
repos/os/src/server/fs_log/session.h
Normal file
100
repos/os/src/server/fs_log/session.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* \brief Log session that writes messages to a file system.
|
||||
* \author Emery Hemingway
|
||||
* \date 2015-05-16
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
#ifndef _FS_LOG__SESSION_H_
|
||||
#define _FS_LOG__SESSION_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <log_session/log_session.h>
|
||||
#include <file_system_session/file_system_session.h>
|
||||
#include <base/rpc_server.h>
|
||||
|
||||
namespace Fs_log {
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
class Session_component;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A log session that writes messages to a file system node.
|
||||
*
|
||||
* Message writing is fire-and-forget to prevent
|
||||
* logging from becoming I/O bound.
|
||||
*/
|
||||
class Fs_log::Session_component : public Rpc_object<Log_session, Session_component>
|
||||
{
|
||||
private:
|
||||
|
||||
File_system::Session &_fs;
|
||||
File_system::File_handle _file_handle;
|
||||
File_system::seek_off_t _offset;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Session_component(File_system::Session &fs,
|
||||
File_system::File_handle fh,
|
||||
File_system::seek_off_t offset)
|
||||
: _fs(fs), _file_handle(fh), _offset(offset) { }
|
||||
|
||||
/*****************
|
||||
** Log session **
|
||||
*****************/
|
||||
|
||||
size_t write(Log_session::String const &string)
|
||||
{
|
||||
if (!(string.is_valid_string())) {
|
||||
PERR("corrupted string");
|
||||
return 0;
|
||||
}
|
||||
|
||||
File_system::Session::Tx::Source &source = *_fs.tx();
|
||||
|
||||
char const *msg = string.string();
|
||||
size_t msg_len = Genode::strlen(msg);
|
||||
size_t write_len = msg_len;
|
||||
|
||||
/*
|
||||
* If the message did not fill the incoming buffer
|
||||
* make space to add a newline.
|
||||
*/
|
||||
if ((msg_len < Log_session::String::MAX_SIZE) &&
|
||||
(msg[msg_len-1] != '\n'))
|
||||
++write_len;
|
||||
|
||||
while (source.ack_avail())
|
||||
source.release_packet(source.get_acked_packet());
|
||||
|
||||
File_system::Packet_descriptor
|
||||
packet(source.alloc_packet(Log_session::String::MAX_SIZE),
|
||||
0, /* The result struct. */
|
||||
_file_handle, File_system::Packet_descriptor::WRITE,
|
||||
write_len, _offset);
|
||||
_offset += write_len;
|
||||
|
||||
char *buf = source.packet_content(packet);
|
||||
memcpy(buf, msg, msg_len);
|
||||
|
||||
if (msg_len != write_len)
|
||||
buf[msg_len] = '\n';
|
||||
|
||||
source.submit_packet(packet);
|
||||
return msg_len;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@ -1,3 +1,3 @@
|
||||
TARGET = fs_log
|
||||
SRC_CC = main.cc
|
||||
LIBS = base libc
|
||||
LIBS = base config server
|
Loading…
x
Reference in New Issue
Block a user