Source

tinymq / extlib / boost / logging / detail / scenario.hpp

Full commit
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
// scenario.hpp

// 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

#ifndef JT28092007_format_fwd_HPP_DEFINED
#error Please include boost/logging/format_fwd.hpp instead
#endif

#ifndef JT28092007_scenario_HPP_DEFINED
#define JT28092007_scenario_HPP_DEFINED

#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif

#include <boost/logging/detail/fwd.hpp>

namespace boost { namespace logging {
/** @page your_scenario_examples Examples of customizing your scenario 

Example 1:
- use a filter that uses per-thread caching with resync once at 10 secs
- the filter uses levels
- use a logger that will favor speed

@code
using namespace boost::logging::scenario::usage;
typedef use< filter_::change::often<10>, filter_::level::use_levels, default_, logger_::favor::speed> finder;

BOOST_DECLARE_LOG_FILTER(g_log_filter, finder::filter);
BOOST_DECLARE_LOG(g_l, finder::logger) 
...
@endcode


Example 2:
- use a filter that is initialized only once, when multiple threads are running
- the filter does not use levels
- use a logger that is initialized only once, when only one thread is running

@code
using namespace boost::logging::scenario::usage;
typedef use< filter_::change::set_once_when_multiple_threads, filter_::level::no_levels, logger_::change::set_once_when_one_thread> finder;

BOOST_DECLARE_LOG_FILTER(g_log_filter, finder::filter);
BOOST_DECLARE_LOG(g_l, finder::logger) 
...
@endcode

To see scenario::usage used in code:
- @ref common_your_scenario "Click to see description of the example"
- @ref common_your_scenario_code "Click to see the code"
*/

namespace filter {
    template<int> struct use_tss_with_cache ;
    struct no_ts ;
    struct ts ;
    struct use_tss_once_init ;
}

namespace level {
    template<int> struct holder_tss_with_cache ;
    struct holder_tss_once_init ;
    struct holder_ts;
    struct holder_no_ts ;
}
namespace writer {
    namespace threading {
        struct no_ts ;
        struct ts_write ;
        struct on_dedicated_thread ;
    }
}

/** 
@brief Use this when you have a specific scenario, and want the best logger/filter classes that fit that scenario. Check out scenario::usage and scenario::ts. 

For example, if you want to specify a %scenario based on usage:

@copydoc your_scenario_examples 

*/
namespace scenario {

/** 
@brief If you want the library to choose the best logger/filter classes based on how your application will %use the loggers and filters, %use this namespace.

First, don't forget to 

@code 
using namespace boost::logging::scenario::usage;
@endcode

Then, you can specify the logger and filter, in a very easy manner

@copydoc your_scenario_examples 

*/
namespace usage {
    // ... bring it in this namespace
    typedef ::boost::logging::default_ default_;


    /** @brief Filter usage settings : filter_::change and filter_::level
    */
    namespace filter_ {
        /** @brief When does the filter change? */
        namespace change {
            /** @brief Optimize for %often %change. Does per-thread caching. At a given period, it re-synchronizes. 
                
                This is the default, for a multi-threaded application.

                @param cache_period_secs At what period should we re-syncronize
            */
            template<int cache_period_secs = 5> struct often {};

            /** @brief Set only once, when there's only one thread running - thus, you don't need to worry about thread-syncronizing */
            struct set_once_when_one_thread {};

            /** @brief Set only once, when there could be multiple thread running. 
            
            We automatically implement a strategy to check if the filter/logger has been initialized, and when it's done, we cache
            the result on every thread */
            struct set_once_when_multiple_threads {};

            /** @brief This is always accurate. However, it's the slowest too.

            In case of multiple threads, it always locks the logger/filter before accessing it. 

            Not recommended, you should usually go with another strategy (often, set_once_when_one_thread or set_once_when_multiple_threads)
            */
            struct always_accurate {};

            /** @brief Single threading. It doesn't matter when/how %often the filter/logger changes. 

                This is the default, for a single-threaded application.
            */
            struct single_thread {};

#ifdef BOOST_HAS_THREADS
            typedef often<> default_;
#else
            typedef single_thread default_;
#endif
        }

        /** @brief What's our "level" policy? */
        namespace level {
            /** @brief not using levels (default) */
            struct no_levels {};
            /** @brief using levels */
            struct use_levels {};

            typedef no_levels default_;
        }
    }

    /** @brief Logger %usage settings : logger_::change and logger_::favor
    */
    namespace logger_ {
        /** @brief When does the logger change, that is, how often do you manipulate it? 
        
        Note that using the log does not mean changing it. 
        Manipulation means invoking non-const functions on the logger, like 
        adding/removing formatters/destinations for instance.
        */
        namespace change {
            /** @brief Optimize for often change. Does per-thread caching. At a given period, it re-synchronizes. This is the default, for multi-threaded applications.

                @param cache_period_secs At what period should we re-syncronize
            */
            template<int cache_period_secs = 5> struct often {};

            /** @brief Set only once, when there's only one thread running - thus, you don't need to worry about thread-syncronizing */
            struct set_once_when_one_thread {};

            /** @brief Set only once, when there could be multiple thread running. 
            
            We automatically implement a strategy to check if the filter/logger has been initialized, and when it's done, we cache
            the result on every thread */
            struct set_once_when_multiple_threads {};

            /** @brief This is always accurate. However, it's the slowest too.

            In case of multiple threads, it always locks the logger/filter before accessing it. 

            Not recommended, you should usually go with another strategy (often, set_once_when_one_thread or set_once_when_multiple_threads)
            */
            struct always_accurate {};

            /** @brief Single threading. It doesn't matter when/how often the filter/logger changes. This is the default, for single-threaded applications.
            */
            struct single_thread {};

#ifdef BOOST_HAS_THREADS
            typedef often<> default_;
#else
            typedef single_thread default_;
#endif
        }

        /** @brief When logging, what should we %favor? */
        namespace favor {
            /** @brief This will favor speed (logging will happen on a dedicated thread). The only problem you could have is if the application crashes.

                In this case, on Windows, the rest of the application will continue, and any non-flushed log message will be flushed.

                On POSIX, this may not be the case.
            */
            struct speed {};

            /** @brief All messages will be logged. This is the default for multi-threaded application
            */
            struct correctness {};

            /** @brief Single threading. It doesn't matter when/how often the filter/logger changes. This is the default, for single-threaded applications.
            */
            struct single_thread {};

#ifdef BOOST_HAS_THREADS
            typedef correctness default_;
#else
            typedef single_thread default_;
#endif
        }

        /** @brief How do you gather the message? */
        namespace gather {
            /** @brief Using the cool operator<< (default) */
            struct ostream_like {};

            /** @brief If you want to use your custom class, specify it here */
            template<class gather_type> struct custom {};

            typedef ostream_like default_;
        }
    }



    namespace detail_find_filter {
        namespace level = ::boost::logging::scenario::usage::filter_::level;
        namespace change = ::boost::logging::scenario::usage::filter_::change;

        //////// use levels

        template<class change_> struct find_filter_use_levels {};
        
        template<int period_secs> struct find_filter_use_levels< change::often<period_secs> > {
            typedef ::boost::logging::level::holder_tss_with_cache<period_secs> type;
        };

        template<> struct find_filter_use_levels< change::set_once_when_one_thread > {
            typedef ::boost::logging::level::holder_no_ts type;
        };

        template<> struct find_filter_use_levels< change::set_once_when_multiple_threads > {
            typedef ::boost::logging::level::holder_tss_once_init type;
        };

        template<> struct find_filter_use_levels< change::always_accurate > {
            typedef ::boost::logging::level::holder_ts type;
        };

        template<> struct find_filter_use_levels< change::single_thread > {
            typedef ::boost::logging::level::holder_no_ts type;
        };



        //////// no levels

        template<class change_> struct find_filter_no_levels {};
        
        template<int period_secs> struct find_filter_no_levels< change::often<period_secs> > {
            typedef ::boost::logging::filter::use_tss_with_cache<period_secs> type;
        };

        template<> struct find_filter_no_levels< change::set_once_when_one_thread > {
            typedef ::boost::logging::filter::no_ts type;
        };

        template<> struct find_filter_no_levels< change::set_once_when_multiple_threads > {
            typedef ::boost::logging::filter::use_tss_once_init type;
        };

        template<> struct find_filter_no_levels< change::always_accurate > {
            typedef ::boost::logging::filter::ts type;
        };

        template<> struct find_filter_no_levels< change::single_thread > {
            typedef ::boost::logging::filter::no_ts type;
        };



        template<class change_, class level_> struct find_filter {
            // no levels
            typedef typename find_filter_no_levels<change_>::type type;
        };

        template<class change_> struct find_filter<change_, level::use_levels> {
            typedef typename find_filter_use_levels<change_>::type type;
        };

    }


    namespace detail_find_logger {
        namespace favor = ::boost::logging::scenario::usage::logger_::favor;
        namespace change = ::boost::logging::scenario::usage::logger_::change;
        namespace th = ::boost::logging::writer::threading;
        namespace gather_usage = ::boost::logging::scenario::usage::logger_::gather;

        template<class favor_> struct find_threading_from_favor {};
        template<> struct find_threading_from_favor<favor::speed>           { typedef th::on_dedicated_thread type; };
        template<> struct find_threading_from_favor<favor::correctness>     { typedef th::ts_write type; };
        template<> struct find_threading_from_favor<favor::single_thread>   { typedef th::no_ts type; };

        template<class gather_type> struct find_gather {};
        template<> struct find_gather<gather_usage::ostream_like> { typedef ::boost::logging::default_ type; };
        template<class custom_gather> struct find_gather<gather_usage::custom<custom_gather> > { typedef custom_gather type; };
        
        template<class favor_, class change_, class gather> struct find_logger {};
        
        template<class favor_, int period_secs, class gather> struct find_logger< favor_, change::often<period_secs>, gather > {
            typedef typename find_threading_from_favor<favor_>::type threading_type;
            template<int secs> struct lock_resource : ::boost::logging::lock_resource_finder::tss_with_cache<secs> {};

            typedef ::boost::logging::logger_format_write < default_, default_, threading_type, gather, lock_resource<period_secs> > type;
        };

        template<class favor_, class gather> struct find_logger< favor_, change::set_once_when_one_thread, gather > {
            typedef typename find_threading_from_favor<favor_>::type threading_type;
            typedef ::boost::logging::lock_resource_finder::single_thread lock_resource;

            typedef ::boost::logging::logger_format_write< default_, default_, threading_type, gather, lock_resource> type;
        };

        template<class favor_, class gather> struct find_logger< favor_, change::set_once_when_multiple_threads, gather > {
            typedef typename find_threading_from_favor<favor_>::type threading_type;
            typedef ::boost::logging::lock_resource_finder::tss_once_init<> lock_resource;

            typedef ::boost::logging::logger_format_write< default_, default_, threading_type, gather, lock_resource> type;
        };

        template<class favor_, class gather> struct find_logger< favor_, change::always_accurate, gather > {
            typedef typename find_threading_from_favor<favor_>::type threading_type;
            typedef ::boost::logging::lock_resource_finder::ts<> lock_resource;

            typedef ::boost::logging::logger_format_write< default_, default_, threading_type, gather, lock_resource> type;
        };

        template<class favor_, class gather> struct find_logger< favor_, change::single_thread, gather > {
            typedef typename find_threading_from_favor<favor_>::type threading_type;
            typedef ::boost::logging::lock_resource_finder::single_thread lock_resource;

            typedef ::boost::logging::logger_format_write< default_, default_, threading_type, gather, lock_resource> type;
        };
    }

    /** 
        @brief Finds a filter class and a logger class that fit your application's needs

        For this to happen, you will first need to specify your needs (the template parameters you'll pass to this class)

        @param filter_change @ref misc_use_defaults "(optional)" How does the %filter change? Any of the classes in the filter_::change namespace
        @param filter_level_ @ref misc_use_defaults "(optional)" Does our %filter %use levels? Any of the classes in the filter_::level namespace
        @param logger_change @ref misc_use_defaults "(optional)" How does our %logger change? Any of the classes in the logger_::change namespace
        @param logger_favor @ref misc_use_defaults "(optional)" What does the %logger favor? Any of the classes in the logger_::favor namespace
        @param logger_gather @ref misc_use_defaults "(optional)" What to %use as gather class. Any of the classes in the logger_::gather namespace

        @copydoc your_scenario_examples 
    */
    template<
        class filter_change = default_,
        class filter_level = default_, 
        class logger_change = default_,
        class logger_favor = default_,
        class logger_gather = default_ >
    struct use {

    private:
        typedef typename use_default<filter_change, filter_::change::default_ >::type filter_change_type;
        typedef typename use_default<filter_level, filter_::level::default_ >::type filter_level_type;

        typedef typename use_default<logger_change, logger_::change::default_ >::type logger_change_type;
        typedef typename use_default<logger_favor, logger_::favor::default_>::type logger_favor_type;
        typedef typename use_default<logger_gather, logger_::gather::default_>::type gather_usage_type;

        typedef typename detail_find_logger::find_gather<gather_usage_type> ::type gather_type;

    public:
        typedef typename detail_find_filter::find_filter<filter_change_type, filter_level_type>::type filter;
        typedef typename detail_find_logger::find_logger< logger_favor_type, logger_change_type, gather_type>::type logger;

    };
}

/** 
@brief Find out the right logger/filter, based on thread-safety of logger(s)/filter(s)

First, don't forget to 
    
@code 
using namespace boost::logging::scenario::ts;
@endcode

Then, you can specify the logger and filter, in a very easy manner

Example:
- use a filter that uses TSS (Thread Specific Storage)
- the filter uses levels
- use a logger that uses TSS

@code
using namespace boost::logging::scenario::ts;
typedef use< filter_::use_tss, level_::use_levels, logger_::use_tss> finder;

BOOST_DECLARE_LOG_FILTER(g_log_filter, finder::filter);
BOOST_DECLARE_LOG(g_l, finder::logger) 
...
@endcode


To see how you can specify the logger/filter based on how you will %use them, see usage namespace.
*/
namespace ts {
    // ... bring it in this namespace
    typedef ::boost::logging::default_ default_;

    /** @brief filter uses levels? */
    struct level_ {
        /** @brief type of %filter levels %usage */
        enum type {
            /** @brief %use levels */
            use_levels,
            /** @brief don't %use levels */
            no_levels
        };
    };

    /** @brief filter thread-safety */
    struct filter_ {
        /** @brief type of filter thread-safety */
        enum type {
            /** @brief not thread-safe */
            none,
            /** @brief %use TSS (thread-specific storage) */
            use_tss,
            /** @brief thread-safe (but slow) */
            ts
        };
    };

    /** logger thread-safety */
    struct logger_ {
        /** @brief type of logger thread-safety */
        enum type {
            /** @brief not thread-safe */
            none,
            /** @brief %use TSS (thread-specific storage) */
            use_tss,
            /** @brief thread-safe (but slow) */
            ts
        };
    };

    namespace detail {
        namespace th = ::boost::logging::writer::threading;

        template<filter_::type,level_::type> struct find_filter {};
        template<> struct find_filter<filter_::none, level_::no_levels > { typedef ::boost::logging::filter::no_ts type; };
        template<> struct find_filter<filter_::use_tss, level_::no_levels> { typedef  ::boost::logging::filter::use_tss_with_cache<5> type; };
        template<> struct find_filter<filter_::ts, level_::no_levels> { typedef ::boost::logging::filter::ts type; };

        template<> struct find_filter<filter_::none, level_::use_levels > { typedef ::boost::logging::level::holder_no_ts type; };
        template<> struct find_filter<filter_::use_tss, level_::use_levels > { typedef ::boost::logging::level::holder_tss_with_cache<5> type; };
        template<> struct find_filter<filter_::ts, level_::use_levels > { typedef ::boost::logging::level::holder_ts type; };

        template<logger_::type> struct find_logger {};
        template<> struct find_logger<logger_::none> { 
            typedef ::boost::logging::lock_resource_finder::single_thread lock_resource;
            typedef ::boost::logging::logger_format_write< default_, default_, th::no_ts, default_, lock_resource > type ; 
        };
        template<> struct find_logger<logger_::use_tss> { 
            typedef ::boost::logging::lock_resource_finder::tss_with_cache<> lock_resource;

            typedef ::boost::logging::logger_format_write< default_, default_, th::ts_write, default_, lock_resource > type ; 
        };
        template<> struct find_logger<logger_::ts> { 
            typedef ::boost::logging::lock_resource_finder::ts<> lock_resource;

            typedef ::boost::logging::logger_format_write< default_, default_, th::ts_write, default_, lock_resource > type ; 
        };
    }

    /** @brief Find the right logger and filter, based on thread-safety: filter_::type, level_::type and logger_::type 
    
        @copydoc ts
    */
    template<filter_::type filter_type, level_::type level_type, logger_::type logger_type> struct use {
        typedef typename detail::find_filter<filter_type,level_type>::type filter;
        typedef typename detail::find_logger<logger_type>::type logger;
    };
}

}

}}

#endif