Boost logo

Boost :

From: John Torjo (john.groups_at_[hidden])
Date: 2008-02-05 17:37:37


> That's fine, but a concept is not a namespace. A concept is a set of
> requirements.
> I have no problem with putting everything associated with a particular
> concept
> in a single namespace. What I object to is your terminology.
>
>
Ok, my bad - will fix after the review. You're right - I didn't express
my intention clear enough.
>
>>> Second, is there any particular reason not to use shared_ptr directly?
>>>
>>>
>>>
>>>
>> Yes, see this :
>> http://torjo.com/log2/doc/html/namespaceboost_1_1logging_1_1manipulator.html#manipulator_manipulate
>>
>>
>
> That doesn't answer my question.
>
>
I wanted a standard way of implementing a manipulator that holds non
constant data.

Users will usually look at existing code and then develop their-own.
Using shared_ptr<> could easily be overlooked, and people could would
end up with a badly implemented manipulator.
Also, non_const_context makes sure the shared_ptr doesn't point to null
- syntactic sugar.

To answer your question : you can use shared_ptr, but the recommended
way is to use non_const_context.

>>> Level: I can't figure out from the documentation what I would need to do
>>> to model this concept.
>>>
>>>
>>>
>> http://torjo.com/log2/doc/html/namespaceboost_1_1logging_1_1level.html
>>
>> (also, see scenario below)
>>
>>
>
> What if I want to write my own level holder? All that gives is a list
> of level holders
> and levels that you provide.
>
>
Depends on what you want - the library is very flexible when it comes to
filters. The simplest level holders looks like this:

// the higher the level, the more critical the message
struct level_filter {
    level_filter(int default_level = 0) : m_level(default_level) {}
    bool is_enabled(int level) const { return level >= m_level; }
    void set_enabled(int level) {
        m_level = level;
    }
private:
    int m_level;
};

Then, you can use it in code
...
typedef logger_format_write< > logger_type;

BOOST_DECLARE_LOG(g_l, logger_type)
BOOST_DECLARE_LOG_FILTER(g_log_filter, level_filter )

#define L_(level) BOOST_LOG_USE_LOG_IF_FILTER(g_l(),
g_log_filter()->is_enabled(level) )

// logging messages
const int dbg_ = 500;
const int err_ = 1000;
L_(dbg_) << "debug message";
L_(err_) << "error msg";

>> The requirements are to return a void* pointer.
>> This is needed when http://torjo.com/log2/doc/html/caching.html and you
>> want to cache the filter as well.
>>
>>
>
> Then, are there two cases? The version of out returning an ostream
> and the version that processes the results directly and returns void*?
>
>
I will address this in another email.
>> If I remove the usage of
>> http://torjo.com/log2/doc/html/caching.html#caching_BOOST_LOG_BEFORE_INIT_CACHE_FILTER
>> then you can return anything you like.
>> For more details, please take a look at cache_before_init_macros.hpp,
>> line 50
>>
>>
>>> Tag: The only requirement on a tag is that it must be CopyConstructable
>>> (Is it
>>> Assignable, too?). tag::holder is a effectively a fusion::set of tags.
>>>
>>>
>>>
>> Not really - theres'a bit of logic in that class.
>>
>>
>
> Ok. That was the best guess I could come up with from
> namespaceboost_1_1logging_1_1tag.html.
> (structboost_1_1logging_1_1tag_1_1holder.html is completely useless)
>
>
>>> It's not clear from either the tag or holder documentation how to
>>> extract
>>> tags in a formatter.
>>>
>>>
>>>
>> Not sure what you mean.
>>
>>
>
> Suppose I write my own tag.
>
> struct my_tag {
> const char* data;
> };
>
> Now, I also need a formatter capable of processing it, right?
>
Yes.
> a) what should the argument type to the formatter be? b) How do I get the value of my_tag?
>
I've attached an example of creating your custom formatter.
I will put it on svn after the review.
>
>
> If manipulators are effectively function objects, I would like to be able
> to just plug in existing function objects like those created by bind.
> If there
> isn't anything more to specialize then you should re-use existing concepts.
>
>
There's more to manipulators than just being a functor:
- they need to have some inner typedefs, and they provide the
possibility to be configured.
>>> better to
>>> make manipulators Equality Comparable Unary Function Objects.
>>> In the case of destinations the return type is ignored, for
>>> for formatters, the result type should be the same as the
>>> argument
>>> type. For both the argument type is determined from the
>>>
>>>
>>>
>> "for formatters the result should be the same as the argument type" - why?
>>
>>
>
> Because the result may have to be passed on to other formatters, of the same
> static type right? Or am I completely misunderstanding how formatters work?
>
>
They don't work like that. A formatter gets a string as argument to its
operator(), and it manipulates that string.
So each manipulator works isolated from the other formatters.
>>> logger.
>>> You can use type erasure to allow them to be treated
>>> polymorphically
>>> at runtime.
>>>
>>>
>>>
>> Isn't this what I'm doing?
>>
>>
>
> Maybe so, but I don't understand the need to use inheritance at all.
>
>
When talking about inheritance - can you tell me which part you're
referring to, so I can explain?

Best,
John
> In Christ,
> Steven Watanabe
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
>
>

-- 
http://John.Torjo.com -- C++ expert
http://blog.torjo.com
... call me only if you want things done right

/**
 Boost Logging library

 Author: John Torjo, www.torjo.com

 Copyright (C) 2007 John Torjo (see www.torjo.com for email)

 Distributed under the Boost Software License, Version 1.0.
    (See accompanying file LICENSE_1_0.txt or copy at
          http://www.boost.org/LICENSE_1_0.txt)

 See http://www.boost.org for updates, documentation, and revision history.
 See http://www.torjo.com/log2/ for more details
*/

#include <boost/logging/format_fwd.hpp>

struct my_tag {
    my_tag(const char * data = "" /* default value */) : data(data) {}
   const char* data;
};

namespace bl = boost::logging;
typedef bl::tag::holder< bl::default_, my_tag> tag_holder;
BOOST_LOG_FORMAT_MSG( tag_holder )

#include <boost/logging/format.hpp>
#include <boost/logging/format/formatter/tags.hpp>

typedef bl::logger_format_write< > logger_type;
typedef bl::filter::no_ts filter_type;

struct my_tag_formatter : bl::formatter::class_<my_tag_formatter, bl::formatter::implement_op_equal::no_context > {
    void operator()(tag_holder & val) const {
        typedef tag_holder::string_type string_type;
        // automatic conversion - tag holder provides this
        const my_tag & tag = val;
        string_type & str = val;

        // print the tag
        str = tag.data + str;
    }
};

#define L_(data) BOOST_LOG_USE_LOG_IF_FILTER(g_l(), g_log_filter()->is_enabled() ) .set_tag( my_tag(data) )

BOOST_DEFINE_LOG_FILTER(g_log_filter, filter_type )
BOOST_DEFINE_LOG(g_l, logger_type)

void custom_tag_class_example() {
    g_l()->writer().add_formatter( bl::formatter::time("$hh:$mm ") );
    g_l()->writer().add_formatter( my_tag_formatter() );

    g_l()->writer().add_formatter( bl::formatter::append_newline() );
    g_l()->writer().add_destination( bl::destination::cout() );
    g_l()->mark_as_initialized();

    int i = 1;
    L_("tag_a ") << "this is so cool " << i++;
    L_("tag_b ") << "this is so cool again " << i++;
}

int main() {
    custom_tag_class_example();
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk