BDE 4.14.0 Production release
Loading...
Searching...
No Matches
balm_metricregistry.h
Go to the documentation of this file.
1/// @file balm_metricregistry.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// balm_metricregistry.h -*-C++-*-
8#ifndef INCLUDED_BALM_METRICREGISTRY
9#define INCLUDED_BALM_METRICREGISTRY
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup balm_metricregistry balm_metricregistry
15/// @brief Provide a registry for metrics.
16/// @addtogroup bal
17/// @{
18/// @addtogroup balm
19/// @{
20/// @addtogroup balm_metricregistry
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#balm_metricregistry-purpose"> Purpose</a>
25/// * <a href="#balm_metricregistry-classes"> Classes </a>
26/// * <a href="#balm_metricregistry-description"> Description </a>
27/// * <a href="#balm_metricregistry-alternative-systems-for-telemetry"> Alternative Systems for Telemetry </a>
28/// * <a href="#balm_metricregistry-thread-safety"> Thread Safety </a>
29/// * <a href="#balm_metricregistry-usage"> Usage </a>
30/// * <a href="#balm_metricregistry-example-1-basic-usage"> Example 1: Basic Usage </a>
31///
32/// # Purpose {#balm_metricregistry-purpose}
33/// Provide a registry for metrics.
34///
35/// # Classes {#balm_metricregistry-classes}
36///
37/// - balm::MetricRegistry: a registry for metrics
38///
39/// @see balm_metricsmanager, balm_metricrecord
40///
41/// # Description {#balm_metricregistry-description}
42/// This component defines a class, `balm::MetricRegistry`, that
43/// provides operations to register both metric categories and individual
44/// metrics. A metric is uniquely identified by its name and category, and the
45/// metric registry provides a mapping from those identifying properties to a
46/// `balm::MetricId`. A `balm::MetricRegistry` object also provides a mapping
47/// from a category name to the address of a non-modifiable `balm::Category`
48/// object.
49///
50/// ## Alternative Systems for Telemetry {#balm_metricregistry-alternative-systems-for-telemetry}
51///
52///
53/// Bloomberg software may alternatively use the GUTS telemetry API, which is
54/// integrated into Bloomberg infrastructure.
55///
56/// ## Thread Safety {#balm_metricregistry-thread-safety}
57///
58///
59/// `balm::MetricRegistry` is fully *thread-safe*, meaning that all non-creator
60/// operations on a given object can be safely invoked simultaneously from
61/// multiple threads.
62///
63/// ## Usage {#balm_metricregistry-usage}
64///
65///
66/// This section illustrates intended use of this component.
67///
68/// ### Example 1: Basic Usage {#balm_metricregistry-example-1-basic-usage}
69///
70///
71/// The following example illustrates how to create and use a
72/// `balm::MetricRegistry`. We start by creating a `balm::MetricRegistry`
73/// object, `registry`, and then using this registry to create a
74/// `balm::MetricId` for a metric named "MetricA" belonging to the category
75/// "MyCategory" (i.e., "MyCategory.MetricA").
76/// @code
77/// bslma::Allocator *allocator = bslma::Default::allocator(0);
78/// balm::MetricRegistry registry(allocator);
79///
80/// balm::MetricId idA = registry.addId("MyCategory", "MetricA");
81/// @endcode
82/// Now that we have added a metric id, "MyCategory.MetricA", attempting to add
83/// the metric id again will return an invalid id. We retrieve the same
84/// identifier we have created using either `getId` or `findId`:
85/// @code
86/// balm::MetricId invalidId = registry.addId("MyCategory", "MetricA");
87/// assert(!invalidId.isValid());
88///
89/// balm::MetricId idA_copy1 = registry.getId("MyCategory", "MetricA");
90/// assert(idA_copy1.isValid());
91/// assert(idA_copy1 == idA);
92///
93/// balm::MetricId idA_copy2 = registry.findId("MyCategory", "MetricA");
94/// assert(idA_copy2.isValid());
95/// assert(idA_copy2 == idA);
96/// @endcode
97/// We use the `getId` method to add a new metric to the registry, then verify
98/// we can lookup the metric:
99/// @code
100/// balm::MetricId idB = registry.getId("MyCategory", "MetricB");
101/// assert(idB.isValid());
102/// assert(idB == registry.getId("MyCategory", "MetricB"));
103/// assert(idB == registry.findId("MyCategory", "MetricB"));
104/// assert(!registry.addId("MyCategory", "MetricB").isValid());
105/// @endcode
106/// Next we use `getCategory` to find the address of the `balm::Category` object
107/// corresponding to "MyCategory":
108/// @code
109/// const balm::Category *myCategory = registry.getCategory("MyCategory");
110/// assert(myCategory == idA.category());
111/// assert(myCategory == idB.category());
112/// assert(myCategory->isEnabled());
113/// @endcode
114/// Finally we use the `setCategoryEnabled` method to disable the category
115/// "MyCategory":
116/// @code
117/// registry.setCategoryEnabled(myCategory, false);
118/// assert(!myCategory->isEnabled());
119/// @endcode
120/// @}
121/** @} */
122/** @} */
123
124/** @addtogroup bal
125 * @{
126 */
127/** @addtogroup balm
128 * @{
129 */
130/** @addtogroup balm_metricregistry
131 * @{
132 */
133
134#include <balscm_version.h>
135
136#include <balm_category.h>
138#include <balm_metricid.h>
139#include <balm_publicationtype.h>
140
141#include <bslmt_rwmutex.h>
142
143#include <bdlb_cstringless.h>
144
145#include <bslma_allocator.h>
146
148
149#include <bsl_iosfwd.h>
150#include <bsl_map.h>
151#include <bsl_memory.h>
152#include <bsl_set.h>
153#include <bsl_string.h>
154#include <bsl_utility.h>
155#include <bsl_vector.h>
156#include <bsl_cstddef.h>
157#include <bsl_cstring.h>
158
159#include <bslma_allocator.h>
160
161
162
163
164namespace balm {
165
166class MetricFormat;
167
168 // ====================
169 // class MetricRegistry
170 // ====================
171
172/// The class defines a thread-aware mechanism for registering metrics and
173/// metric categories. A metric is uniquely identified by its name and
174/// category, and the metric registry provides a mapping from those
175/// identifying properties to a `balm::MetricId`. A `balm::MetricRegistry`
176/// object also provides a mapping from a category name to the address of a
177/// non-modifiable `balm::Category` object.
178///
179/// See @ref balm_metricregistry
181
182 // PRIVATE TYPES
183
184 /// `CategoryAndName` is an alias for a pair of null-terminated
185 /// constant strings that represent the category and name of a metric.
186 /// The first element is the category and the second is the name.
188
189 /// This `struct` defines an ordering on `CategoryAndName` values
190 /// allowing them to be included in sorted containers such as
191 /// `bsl::map`. Note that the category and name strings are compared
192 /// by value.
193 struct CategoryAndNameLess {
194
196
197 bool operator()(const CategoryAndName& lhs,
198 const CategoryAndName& rhs) const
199 {
200 int cmp = bsl::strcmp(lhs.first, rhs.first);
201 /// Return `true` if the value of the specified `lhs` is less than
202 /// (ordered before) the value of the specified `rhs`, and `false`
203 /// otherwise. The `lhs` value is considered less than the `rhs`
204 /// value if the first value in the `lhs` pair (the category) is
205 /// less than the first value in the `rhs` pair or, if the first
206 /// values are equal, if the second value in the `lhs` pair (the
207 /// name) is less than the second value in the `rhs` pair.
208 if (0 == cmp) {
209 cmp = bsl::strcmp(lhs.second, rhs.second);
210 }
211 return cmp < 0;
212 }
213 };
214
215 /// A `MetricMap` is a type that maps a category and name to a
216 /// `balm::MetricDescription` object address.
219 CategoryAndNameLess> MetricMap;
220
221 /// A `CategoryRegistry` is a type that maps a name to a
222 /// `balm::Category` object address.
223 typedef bsl::map<const char *,
226
227 /// `UserDataRegistry` is an alias for a type that maps a category (or
228 /// category prefix) to the user data set for that category (or group of
229 /// categories).
230 typedef bsl::map<const char *,
233
234 // DATA
235 bsl::set<bsl::string> d_uniqueStrings; // unique string memory
236
237 CategoryRegistry d_categories; // category -> 'balm::Category'
238
239 MetricMap d_metrics; // map (category,name) -> MetricId
240
241 bool d_defaultEnabled; // default enabled status
242
243 UserDataRegistry d_categoryUserData;
244 // map category -> user data
245
246 UserDataRegistry d_categoryPrefixUserData;
247 // map category-prefix -> user
248 // data
249
250 int d_nextKey; // next valid user data key
251
252 mutable bslmt::RWMutex d_lock; // read-write property lock
253
254 bslma::Allocator *d_allocator_p; // allocator (held, not owned)
255
256 // NOT IMPLEMENTED
258 MetricRegistry& operator=(const MetricRegistry&);
259
260 private:
261 // PRIVATE MANIPULATORS
262
263 /// Insert a metric id having the specified `category` and `name` into
264 /// this metric registry. Return a pair whose first member is the id
265 /// of the metric, and whose second member is `true` if the returned
266 /// metric id is newly-created and `false` otherwise. The behavior is
267 /// undefined unless the calling thread has a *write* lock on `d_lock`.
268 bsl::pair<MetricId, bool> insertId(const char *category,
269 const char *name);
270
271 /// Associate the specified `value` with the specified `key` for every
272 /// metric belonging to the specified `category`. Note that this
273 /// operation modifies existing metrics, but does not affect metrics
274 /// created after this method is called. The behavior is undefined
275 /// unless the calling thread has a *write* lock on `d_lock`.
276 void setCurrentUserData(const char *category,
278 const void *value);
279
280 // PRIVATE ACCESSORS
281
282 /// Load into the specified `result` the user data associated (via
283 /// `setUserData`) with a category having the specified `categoryName`.
284 /// Each index position in `result` will contain 0, or an (opaque)
285 /// application-specific data value provided by the client, either for
286 /// `categoryName` or a prefix of `categoryName`. If there is more
287 /// than one non-null user-supplied data value applicable to an index
288 /// position in `result`, it is unspecified which value will be
289 /// returned. The behavior is undefined unless the calling thread has a
290 /// lock on `d_lock`.
291 void defaultUserData(bsl::vector<const void *> *result,
292 const char *categoryName) const;
293
294 public:
295 // PUBLIC TRAITS
297
298 // CREATORS
299
300 /// Create an empty metric registry. Optionally specify a
301 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
302 /// the currently installed default allocator is used.
303 MetricRegistry(bslma::Allocator *basicAllocator = 0);
304
305 /// Destroy this metric registry.
307
308 // MANIPULATORS
309
310 /// Add the specified `category` and `name` to this registry, unless it
311 /// has already been registered, and return a `balm::MetricId` object
312 /// identifying the newly-registered metric. If the indicated metric
313 /// has already been registered, the returned `balm::MetricId` object
314 /// will *not* be valid (i.e., `isValid` will return `false`). The
315 /// behavior is undefined unless `category` and `name` are
316 /// null-terminated.
317 MetricId addId(const char *category, const char *name);
318
319 /// Return a `balm::MetricId` object for the metric identified by the
320 /// specified `category` and `name`. If no corresponding metric has
321 /// already been registered, register a new metric and return a
322 /// `balm::MetricId` object identifying that newly-registered metric.
323 /// The behavior is undefined unless `category` and `name` are
324 /// null-terminated. Note that this operation is guaranteed to return
325 /// a valid `balm::MetricId` object.
326 MetricId getId(const char *category, const char *name);
327
328 /// Add the specified `category` to this registry, unless it has already
329 /// been registered. Return the address of the newly-created
330 /// non-modifiable `balm::Category` object on success, and 0 otherwise.
331 /// The behavior is undefined unless `category` is null-terminated.
332 const Category *addCategory(const char *category);
333
334 /// Return the address of the non-modifiable `balm::Category` object for
335 /// the specified `category`. If no corresponding category exists,
336 /// register a new category and return the address of the newly-created
337 /// `balm::Category` object. The behavior is undefined unless
338 /// `category` is null-terminated. Note that this operation is
339 /// guaranteed to return a valid address.
340 const Category *getCategory(const char *category);
341
342 /// Set whether the specified `category` is enabled to the specified
343 /// `value`. The behavior is undefined unless `category` is a valid
344 /// address of a category previously returned by this metric registry.
345 /// Note that this operation is thread-safe, but *not* atomic: Other
346 /// threads may simultaneously access the current enabled value for
347 /// `category` while this operation completes. Also note that this
348 /// operation has *linear* runtime performance with respect to the
349 /// number of registered category holders for `category`.
350 void setCategoryEnabled(const Category* category,
351 bool value);
352
353 /// Set whether each currently registered category is enabled to the
354 /// specified `value`, and ensure that categories registered after this
355 /// call are initialized as either enabled or disabled, accordingly.
356 /// This operation is logically equivalent to iterating over the list
357 /// of currently registered categories and calling `setCategoryEnabled`
358 /// on each category individually, and also setting a default `enabled`
359 /// value (for newly-created categories). Hence, subsequent calls
360 /// `setCategoryEnabled` will override this value for a particular
361 /// category. Note that this operation is thread-safe, but *not*
362 /// atomic: Other threads may simultaneously access the current enabled
363 /// status for registered categories while this operation completes.
364 /// Also note that this operation has *linear* runtime performance with
365 /// respect to the total number of category holders registered with this
366 /// repository.
367 void setAllCategoriesEnabled(bool value);
368
369 /// Load into the specified `holder` the address of the specified
370 /// `category`, its `enabled` status, and the address of the next holder
371 /// in the linked list of category holders maintained by `category`
372 /// (prepending `holder` to the linked list of category holders for
373 /// `category`). The supplied `category` will update the value returned
374 /// by `holder->enabled()` when its enabled state changes, and will
375 /// reset `holder` (i.e., `holder->reset()`) when `category` is
376 /// destroyed. The behavior is undefined unless `holder` remains valid
377 /// and *unmodified* (by the client) for the lifetime of this object.
378 ///
379 /// This method should *not* be used directly by client code. It is an
380 /// implementation detail of the `balm` metric collection system.
381 void registerCategoryHolder(const Category *category,
382 CategoryHolder *holder);
383
384 /// Set the preferred publication type of the specified `metric` to the
385 /// specified `type`. The preferred publication type of a metric
386 /// indicates the preferred aggregate to publish for that metric, or
387 /// `balm::PublicationType::UNSPECIFIED` if there is no preference. The
388 /// behavior is undefined unless `metric` was previously returned by
389 /// this metric registry. Note that there is no uniform definition for
390 /// how publishers will interpret this value; an `UNSPECIFIED` value
391 /// generally indicates that the all the collected aggregates (total,
392 /// count, minimum, and maximum value) should be published. Also note
393 /// that the preferred publication type is accessed through the
394 /// `balm::MetricDescription` (i.e.,
395 /// `metric.description()->preferredPublicationType()`).
398
399 /// Set the format for the specified `metricId` to the specified
400 /// `format`. Note that there is no uniform specification for how
401 /// publisher implementations will interpret the supplied `format`.
402 /// Also note that the format for a metric is accessed through the
403 /// `balm::MetricDescription`. For example:
404 /// @code
405 /// metric.description()->format();
406 /// @endcode
407 void setFormat(const MetricId& metricId,
408 const MetricFormat& format);
409
410 /// Return a new unique key that can be used to associate (via
411 /// `setUserData`) and retrieve (via `userData`) a value with a metric
412 /// (or group of metrics). Note that the returned key can be used by
413 /// clients of `balm` to associate additional information with a metric.
415
416 /// Associate the specified `value` with the specified `key` in the
417 /// description of the specified `metricId`. The behavior is undefined
418 /// unless `key` was previously returned from `createUserDataKey`. Note
419 /// that this method allows clients of `balm` to associate (opaque)
420 /// application-specific information with a metric.
421 void setUserData(const MetricId& metricId,
423 const void *value);
424
425 /// Associate the specified `value` with the specified `key` in any
426 /// metric belonging to a category having the specified `categoryName`,
427 /// or a category whose name begins with `categoryName`, as determined
428 /// by the optionally specified `prefixFlag`. If `prefixFlag` is
429 /// `false` or is not specified, only those metrics belonging to a
430 /// category having `categoryName` will be mapped; otherwise, `value`
431 /// will be associated with `key` for all metrics belonging to any
432 /// category whose name begins with `categoryName`. This association
433 /// applies to existing metrics as well as any subsequently created
434 /// ones. When a metric is created that matches more than one
435 /// registered category prefix, it is not specified which supplied value
436 /// will be associated with `key`, unless only one of those values is
437 /// non-null, in which case the unique non-null value is used. The
438 /// behavior is undefined unless `key` was previously returned from
439 /// `createUserDataKey`.
440 void setUserData(const char *categoryName,
442 const void *value,
443 bool prefixFlag = false);
444
445 // ACCESSORS
446
447 /// Return the number of metrics in this registry.
448 bsl::size_t numMetrics() const;
449
450 /// Return the number of categories in this registry.
451 bsl::size_t numCategories() const;
452
453 /// Find the specified `category`, a null-terminated string, in this
454 /// registry. Return the address of the non-modifiable `balm::Category`
455 /// object corresponding to the `category`, or 0 if no such category has
456 /// been registered.
457 const Category *findCategory(const char *category) const;
458
459 /// Find the specified null-terminated strings `category` and `name` in
460 /// this registry. Return the `balm::MetricId` object corresponding to
461 /// the metric having the `category` and `name`, if found, or an invalid
462 /// metric id if no such metric has been registered (i.e., `isValid`
463 /// will return `false`).
464 MetricId findId(const char *category, const char *name) const;
465
466 /// Append to the specified `categories` the addresses of all the
467 /// categories registered by this `balm::MetricRegistry` object.
469
470 /// Format this object to the specified output `stream` at the (absolute
471 /// value of) the optionally specified indentation `level` and return a
472 /// reference to `stream`. If `level` is specified, optionally specify
473 /// `spacesPerLevel`, the number of spaces per indentation level for
474 /// this and all of its nested objects. If `level` is negative,
475 /// suppress indentation of the first line. If `spacesPerLevel` is
476 /// negative, format the entire output on one line, suppressing all but
477 /// the initial indentation (as governed by `level`). If `stream` is
478 /// not valid on entry, this operation has no effect.
479 bsl::ostream& print(bsl::ostream& stream,
480 int level = 0,
481 int spacesPerLevel = 4) const;
482};
483
484} // close package namespace
485
486
487#endif
488
489// ----------------------------------------------------------------------------
490// Copyright 2015 Bloomberg Finance L.P.
491//
492// Licensed under the Apache License, Version 2.0 (the "License");
493// you may not use this file except in compliance with the License.
494// You may obtain a copy of the License at
495//
496// http://www.apache.org/licenses/LICENSE-2.0
497//
498// Unless required by applicable law or agreed to in writing, software
499// distributed under the License is distributed on an "AS IS" BASIS,
500// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
501// See the License for the specific language governing permissions and
502// limitations under the License.
503// ----------------------------- END-OF-FILE ----------------------------------
504
505/** @} */
506/** @} */
507/** @} */
Definition balm_category.h:257
Definition balm_category.h:151
int UserDataKey
Definition balm_metricdescription.h:190
Definition balm_metricformat.h:317
Definition balm_metricid.h:162
Definition balm_metricregistry.h:180
~MetricRegistry()
Destroy this metric registry.
MetricRegistry(bslma::Allocator *basicAllocator=0)
bsl::ostream & print(bsl::ostream &stream, int level=0, int spacesPerLevel=4) const
void setCategoryEnabled(const Category *category, bool value)
void getAllCategories(bsl::vector< const Category * > *categories) const
BSLMF_NESTED_TRAIT_DECLARATION(MetricRegistry, bslma::UsesBslmaAllocator)
MetricId getId(const char *category, const char *name)
const Category * getCategory(const char *category)
void setFormat(const MetricId &metricId, const MetricFormat &format)
bsl::size_t numMetrics() const
Return the number of metrics in this registry.
void setPreferredPublicationType(const MetricId &metric, PublicationType::Value type)
MetricDescription::UserDataKey createUserDataKey()
void setAllCategoriesEnabled(bool value)
bsl::size_t numCategories() const
Return the number of categories in this registry.
MetricId findId(const char *category, const char *name) const
void setUserData(const MetricId &metricId, MetricDescription::UserDataKey key, const void *value)
const Category * findCategory(const char *category) const
void registerCategoryHolder(const Category *category, CategoryHolder *holder)
void setUserData(const char *categoryName, MetricDescription::UserDataKey key, const void *value, bool prefixFlag=false)
const Category * addCategory(const char *category)
MetricId addId(const char *category, const char *name)
Definition bslstl_map.h:619
Definition bslstl_pair.h:1210
Definition bslstl_set.h:657
Definition bslstl_sharedptr.h:1830
Definition bslstl_vector.h:1025
Definition bslma_allocator.h:457
Definition bslmt_rwmutex.h:147
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition balm_bdlmmetricsadapter.h:141
Value
Definition balm_publicationtype.h:81
Definition bdlb_cstringless.h:141
TYPE first
Definition bslstl_pair.h:605
TYPE second
Definition bslstl_pair.h:908
Definition bslma_usesbslmaallocator.h:343