Boost logo

Boost :

From: Darryl Green (darryl.green_at_[hidden])
Date: 2005-12-26 01:47:10


John Torjo wrote:
>>I've been sketching up a very simple implementation of some of these ideas
>>in my spare time. Is there interest in fleshing these ideas out more fully
>>on or off-list?
>>
>
>
> I'm all for it as well! But how 'bout after New Year's Eve?
> I'm quite beat, and I want a vacation...
>
> That said,
> Merry Christmas to you all, and
> A Happy New Year!

And the same to you. If you have a use for it, attached is a new version
of the wildcarded name matching logic + tests intended to:

1) Support detaching objects with rules (ie name matching) from logs
2) Avoid the rules table always getting bigger

Presumably predicates could be associated with logs using the same
mechanism as used for appenders and enabledness (really a degenerate
predicate anyway).

Regards
Darryl Green.


// test_rules.cpp
// Boost Logging Template library
//
// Author: Darryl Green
//
// Copyright (C) 2005 Darryl Green (darryl.green_at_[hidden])
//
// Permission to copy, use, sell and distribute this software is granted
// provided this copyright notice appears in all copies.
// Permission to modify the code and to distribute modified code is granted
// provided this copyright notice appears in all copies, and a notice
// that the code was modified is included with the copyright notice.
//
// This software is provided "as is" without express or implied warranty,
// and with no claim as to its suitability for any purpose.
// See http://www.boost.org for updates, documentation, and revision history.

// The rules are used to match appenders to logs
// rules are applied in teh order they were specified

#include <boost/log/log_impl.hpp>
#include <map>
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>

#include "rules.hpp"

using namespace boost::logging::detail;

struct fails
{
        fails(std::string msg) : m_msg(msg) {}

        const char *what() { return m_msg.c_str(); }
        std::string m_msg;
};

void test1()
{
        rule_set A;
        rule_set B;

        A.modify("a*+");
        B.modify("a*+");
        if (A.modify("a+")) throw fails("A already accepts a"); // should do nothing
        if (A.modify("a.b+")) throw fails("A already accepts a.b"); // should do nothing

        if (!(A.match("a") && A.match("a.b") && A.match("a.b.c")))
                        throw fails("A should match a & a.b & a.b.c");
                        
        if (A.match("b") || A.match("b.a") || A.match("ba"))
                        throw fails("A should NOT match b or b.a or ba");
                        
        if (!(B.match("a") && B.match("a.b") && B.match("a.b.c")))
                        throw fails("B should match");
                        
        if (B.match("b") || B.match("b.a") || B.match("ba"))
                        throw fails("B should NOT match");

        A.modify("a.b-");
        if (A.match("a.b"))
                        throw fails("A should NOT match a.b");
        if (!A.match("a.b.c"))
                        throw fails("A should match a.b.c");

        A.modify("a.c*-");
        if (A.match("a.c"))
                        throw fails("A should NOT match a.c");
        if (A.match("a.c.b"))
                        throw fails("A should NOT match a.c.b");

        if (A.modify("a.c.x-")) throw fails("A already rejects a.c.x"); // should do nothing
        if (A.modify("a.c.*-")) throw fails("A already rejects a.c.*"); // should do nothing

        // make a "hole" in the rejections
        if (!A.modify("a.c.x*+")) throw fails("A not accepting a.c.x");
        // and check it works
        if (!A.match("a.c.xanadu"))
                        throw fails("A should match a.c.xanadu");

        std::copy(A.rules().begin(), A.rules().end(), std::ostream_iterator<std::string>(std::cout, "\n") );
        
        // if we turn off "*" there should be no rules left
        A.modify("*-");

        if (!A.rules().empty())
                throw fails("A not empty");
}

int main (int argc, char *argv[])
{
        try {
                test1();
        }
        catch (fails& err)
        {
                std::cout << " FAILED : " << err.what() << std::endl;
                return 1;
        }
        
        std::cout << "PASSED" << std::endl;
        return 0;
}


// rules.cpp
// Boost Logging Template library
//
// Author: Darryl Green
//
// Copyright (C) 2005 Darryl Green (darryl.green_at_[hidden])
// Copyright (C) 2004-2005 John Torjo (john_at_[hidden])
//
// Permission to copy, use, sell and distribute this software is granted
// provided this copyright notice appears in all copies.
// Permission to modify the code and to distribute modified code is granted
// provided this copyright notice appears in all copies, and a notice
// that the code was modified is included with the copyright notice.
//
// This software is provided "as is" without express or implied warranty,
// and with no claim as to its suitability for any purpose.
// See http://www.boost.org for updates, documentation, and revision history.

// The rules are used to match appenders to logs
// rules are applied in teh order they were specified

#include "rules.hpp"
#include <boost/log/log_impl.hpp>
#include <map>
#include <vector>
#include <algorithm>
#include <iostream>

namespace boost {
    namespace logging {
        
        namespace {

            typedef logging_types::log_name_string_type rule_type;

            typedef std::vector<rule_type> rule_table;

            struct compiled_rule
            {
                compiled_rule(const rule_type& r)
                {
                    rule_type pattern = r;
                    pattern.resize(pattern.size()-1);
                    match_all = (pattern == "*") || pattern.empty();
                    if (!match_all)
                    {
                        fixed_start = *pattern.begin() != '*';
                        fixed_end = *pattern.rbegin() != '*';
                    
                        rule_type::size_type pos = 0, next;
                
                        // split spec on wildcard char (*)
                        while ( pos < pattern.size() ) {
                            next = pattern.find('*', pos);
                            if (next == rule_type::npos) next = pattern.size();
                            if (next - pos > 0)
                                searches.push_back( pattern.substr(pos, next-pos));
                            pos = next+1;
                        }
                    
                        match_all = searches.empty();
                    }
                }
            
                bool matches(const rule_type& r) const
                {
                    if (match_all)
                        return true;
                
                    if (fixed_start && r.find(*searches.begin()) != 0)
                        return false;
                    
                    // each segment in searches must match,
                    // but there can be anything in between
                    rule_type::size_type at = 0;
                    for (rule_table::const_iterator
                            begin = searches.begin(),
                            end = searches.end();
                            begin != end;
                            ++begin) {
                        rule_type::size_type next = r.find(*begin, at);
                        if (next == rule_type::npos)
                            return false;
                        at = next + begin->length();
                    }
                
                    if (fixed_end) {
                        char ch = *r.rbegin();
                        if (ch == '-' || ch == '+')
                            return at == r.size()-1;
                        return at == r.size();
                    }
                
                    return true;
                }

              private:
                rule_table searches; // substrings to match
                bool match_all; // short cct common case
                bool fixed_start; // first substring must match at start
                bool fixed_end; // last substring must match at end
            

            };

            struct matches
            {
                matches(const compiled_rule& s) :
                    spec(s)
                {
                }

                bool operator () (const rule_type& r) const
                {
                    return spec.matches(r);
                }
         
              private:
                const compiled_rule& spec;
            };
                                
                  } // anon namespace
                  
        namespace detail {
                          
                          bool rule_set::modify(const rule_type& r)
                {
                    rule_type tmp = r;
                    if (*tmp.rbegin() != '-' && *tmp.rbegin() != '+')
                        tmp.push_back('+');
                    
                    compiled_rule new_rule(tmp);
                    // remove rules that are subranges of the new one
                    m_rules.erase (
                        std::remove_if(m_rules.begin(), m_rules.end(), matches(new_rule)),
                        m_rules.end());
                        
                    // add if this rule is a subrange of an existing rule of oposite sign
                    // add if it is a +ve rule that isn't a subrange of an existing rule
                    // (ie it is a subrange of the implied "everything off" rule)
                    char sign = *tmp.rbegin();
                    bool add_rule = sign != '-';
                    // see if rule is a subrange
                    for (rule_table::iterator rit = m_rules.begin(), end = m_rules.end(); rit != end; ++rit) {
                        if (compiled_rule(*rit).matches(tmp))
                            add_rule = sign != *rit->rbegin();
                    }
                    if (add_rule)
                        m_rules.push_back(tmp);
                        
                    return add_rule;
                    
                }
                
                                bool rule_set::clear()
                {
                    bool not_empty = !m_rules.empty();
                    m_rules.clear();
                    return not_empty;
                }
                
                 bool rule_set::match(const logging_types::log_name_string_type& target) const
                {
                    bool result = false;
                    for (rule_table::const_iterator rit = m_rules.begin(), end = m_rules.end(); rit != end; ++rit) {
                        if (compiled_rule(*rit).matches(target)) {
                            result = *rit->rbegin() != '-';
                        }
                    }
                    return result;
                }
                
            const rule_table& rule_set::rules() const
                                {
                                        return m_rules;
                                }
            
        } // detail

                  // public interface
                  
        
    } // logging

} // boost


// rules.hpp
// Boost Logging library
// rules match logs by name to modify them (attach appenders, enable/disable etc)
//
// Author: Darryl Green
//
// Copyright (C) 2005 Darryl Green (darryl.green_at_[hidden])
// Copyright (C) 2004-2005 John Torjo (john_at_[hidden])
//
// Permission to copy, use, sell and distribute this software is granted
// provided this copyright notice appears in all copies.
// Permission to modify the code and to distribute modified code is granted
// provided this copyright notice appears in all copies, and a notice
// that the code was modified is included with the copyright notice.
//
// This software is provided "as is" without express or implied warranty,
// and with no claim as to its suitability for any purpose.
// See http://www.boost.org for updates, documentation, and revision history.

// The rules are used to match appenders to logs
// rules are applied in the order they were specified
#ifndef BOOST_LOGGING_RULES_HPP
#define BOOST_LOGGING_RULES_HPP

#include <boost/log/log_impl.hpp>

namespace boost {
        namespace logging {
                namespace detail {
                        struct rule_set
            {
                                        
                    typedef logging_types::log_name_string_type rule_type;

                    typedef std::vector<rule_type> rule_table;

                bool modify( const logging_types::log_name_string_type& r);
                
                bool clear();
                
                bool match(const logging_types::log_name_string_type& target) const;

                                         const rule_table& rules() const;
                
                rule_table m_rules;
            };
                }
        }
}

#endif

No virus found in this outgoing message.
Checked by AVG Free Edition.
Version: 7.1.371 / Virus Database: 267.14.7/214 - Release Date: 23/12/2005


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