BDE 4.39.x 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.
187 typedef bsl::pair<const char *, const char *> CategoryAndName;
188
189 /// This `struct` defines an ordering on `CategoryAndName` values
190 /// allowing them to be included in sorted containers such as `bsl::map`.
191 ///
192 /// \note Note that the category and name strings are compared
193 /// by value.
194 ///
195 /// See @ref balm_metricregistry
196 struct CategoryAndNameLess {
197
198 typedef bsl::pair<const char *, const char *> CategoryAndName;
199
200 /// Return `true` if the value of the specified `lhs` is less than
201 /// (ordered before) the value of the specified `rhs`, and `false`
202 /// otherwise. The `lhs` value is considered less than the `rhs`
203 /// value if the first value in the `lhs` pair (the category) is
204 /// less than the first value in the `rhs` pair or, if the first
205 /// values are equal, if the second value in the `lhs` pair (the
206 /// name) is less than the second value in the `rhs` pair.
207 bool operator()(const CategoryAndName& lhs,
208 const CategoryAndName& rhs) const
209 {
210 int cmp = bsl::strcmp(lhs.first, rhs.first);
211 if (0 == cmp) {
212 cmp = bsl::strcmp(lhs.second, rhs.second);
213 }
214 return cmp < 0;
215 }
216 };
217
218 /// A `MetricMap` is a type that maps a category and name to a
219 /// `balm::MetricDescription` object address.
220 typedef bsl::map<CategoryAndName,
222 CategoryAndNameLess> MetricMap;
223
224 /// A `CategoryRegistry` is a type that maps a name to a
225 /// `balm::Category` object address.
226 typedef bsl::map<const char *,
229
230 /// `UserDataRegistry` is an alias for a type that maps a category (or
231 /// category prefix) to the user data set for that category (or group of
232 /// categories).
233 typedef bsl::map<const char *,
236
237 // DATA
238 bsl::set<bsl::string> d_uniqueStrings; // unique string memory
239
240 CategoryRegistry d_categories; // category -> 'balm::Category'
241
242 MetricMap d_metrics; // map (category,name) -> MetricId
243
244 bool d_defaultEnabled; // default enabled status
245
246 UserDataRegistry d_categoryUserData;
247 // map category -> user data
248
249 UserDataRegistry d_categoryPrefixUserData;
250 // map category-prefix -> user
251 // data
252
253 int d_nextKey; // next valid user data key
254
255 mutable bslmt::RWMutex d_lock; // read-write property lock
256
257 bslma::Allocator *d_allocator_p; // allocator (held, not owned)
258
259 private:
260 // NOT IMPLEMENTED
262 MetricRegistry& operator=(const MetricRegistry&);
263
264 private:
265 // PRIVATE MANIPULATORS
266
267 /// Insert a metric id having the specified `category` and `name` into
268 /// this metric registry. Return a pair whose first member is the id
269 /// of the metric, and whose second member is `true` if the returned
270 /// metric id is newly-created and `false` otherwise.
271 ///
272 /// \pre The behavior is undefined unless the calling thread has a *write* lock on `d_lock`.
273 bsl::pair<MetricId, bool> insertId(const char *category,
274 const char *name);
275
276 /// Associate the specified `value` with the specified `key` for every metric belonging to the specified `category`.
277 ///
278 /// \note Note that this
279 /// operation modifies existing metrics, but does not affect metrics
280 /// created after this method is called.
281 ///
282 /// \pre The behavior is undefined unless the calling thread has a *write* lock on `d_lock`.
283 void setCurrentUserData(const char *category,
285 const void *value);
286
287 // PRIVATE ACCESSORS
288
289 /// Load into the specified `result` the user data associated (via
290 /// `setUserData`) with a category having the specified `categoryName`.
291 /// Each index position in `result` will contain 0, or an (opaque)
292 /// application-specific data value provided by the client, either for
293 /// `categoryName` or a prefix of `categoryName`. If there is more
294 /// than one non-null user-supplied data value applicable to an index
295 /// position in `result`, it is unspecified which value will be returned.
296 ///
297 /// \pre The behavior is undefined unless the calling thread has a
298 /// lock on `d_lock`.
299 void defaultUserData(bsl::vector<const void *> *result,
300 const char *categoryName) const;
301
302 public:
303 // PUBLIC TRAITS
305
306 // CREATORS
307
308 /// Create an empty metric registry. Optionally specify a
309 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
310 /// the currently installed default allocator is used.
311 MetricRegistry(bslma::Allocator *basicAllocator = 0);
312
313 /// Destroy this metric registry.
315
316 // MANIPULATORS
317
318 /// Add the specified `category` and `name` to this registry, unless it
319 /// has already been registered, and return a `balm::MetricId` object
320 /// identifying the newly-registered metric. If the indicated metric
321 /// has already been registered, the returned `balm::MetricId` object
322 /// will *not* be valid (i.e., `isValid` will return `false`).
323 ///
324 /// \pre The behavior is undefined unless `category` and `name` are
325 /// null-terminated.
326 MetricId addId(const char *category, const char *name);
327
328 /// Return a `balm::MetricId` object for the metric identified by the
329 /// specified `category` and `name`. If no corresponding metric has
330 /// already been registered, register a new metric and return a
331 /// `balm::MetricId` object identifying that newly-registered metric.
332 ///
333 /// \pre The behavior is undefined unless `category` and `name` are null-terminated.
334 ///
335 /// \note Note that this operation is guaranteed to return
336 /// a valid `balm::MetricId` object.
337 MetricId getId(const char *category, const char *name);
338
339 /// Add the specified `category` to this registry, unless it has already
340 /// been registered. Return the address of the newly-created
341 /// non-modifiable `balm::Category` object on success, and 0 otherwise.
342 ///
343 /// \pre The behavior is undefined unless `category` is null-terminated.
344 const Category *addCategory(const char *category);
345
346 /// Return the address of the non-modifiable `balm::Category` object for
347 /// the specified `category`. If no corresponding category exists,
348 /// register a new category and return the address of the newly-created `balm::Category` object.
349 ///
350 /// \pre The behavior is undefined unless `category` is null-terminated.
351 ///
352 /// \note Note that this operation is
353 /// guaranteed to return a valid address.
354 const Category *getCategory(const char *category);
355
356 /// Set whether the specified `category` is enabled to the specified `value`.
357 ///
358 /// \pre The behavior is undefined unless `category` is a valid
359 /// address of a category previously returned by this metric registry.
360 ///
361 /// \note Note that this operation is thread-safe, but *not* atomic: Other
362 /// threads may simultaneously access the current enabled value for
363 /// `category` while this operation completes. Also note that this
364 /// operation has *linear* runtime performance with respect to the
365 /// number of registered category holders for `category`.
366 void setCategoryEnabled(const Category* category,
367 bool value);
368
369 /// Set whether each currently registered category is enabled to the
370 /// specified `value`, and ensure that categories registered after this
371 /// call are initialized as either enabled or disabled, accordingly.
372 /// This operation is logically equivalent to iterating over the list
373 /// of currently registered categories and calling `setCategoryEnabled`
374 /// on each category individually, and also setting a default `enabled`
375 /// value (for newly-created categories). Hence, subsequent calls
376 /// `setCategoryEnabled` will override this value for a particular category.
377 ///
378 /// \note Note that this operation is thread-safe, but *not*
379 /// atomic: Other threads may simultaneously access the current enabled
380 /// status for registered categories while this operation completes.
381 /// Also note that this operation has *linear* runtime performance with
382 /// respect to the total number of category holders registered with this
383 /// repository.
384 void setAllCategoriesEnabled(bool value);
385
386 /// Load into the specified `holder` the address of the specified
387 /// `category`, its `enabled` status, and the address of the next holder
388 /// in the linked list of category holders maintained by `category`
389 /// (prepending `holder` to the linked list of category holders for
390 /// `category`). The supplied `category` will update the value returned
391 /// by `holder->enabled()` when its enabled state changes, and will
392 /// reset `holder` (i.e., `holder->reset()`) when `category` is destroyed.
393 ///
394 /// \pre The behavior is undefined unless `holder` remains valid
395 /// and *unmodified* (by the client) for the lifetime of this object.
396 ///
397 /// This method should *not* be used directly by client code. It is an
398 /// implementation detail of the `balm` metric collection system.
399 void registerCategoryHolder(const Category *category,
400 CategoryHolder *holder);
401
402 /// Set the preferred publication type of the specified `metric` to the
403 /// specified `type`. The preferred publication type of a metric
404 /// indicates the preferred aggregate to publish for that metric, or
405 /// `balm::PublicationType::UNSPECIFIED` if there is no preference.
406 ///
407 /// \pre The behavior is undefined unless `metric` was previously returned by this metric registry.
408 ///
409 /// \note Note that there is no uniform definition for
410 /// how publishers will interpret this value; an `UNSPECIFIED` value
411 /// generally indicates that the all the collected aggregates (total,
412 /// count, minimum, and maximum value) should be published. Also note
413 /// that the preferred publication type is accessed through the
414 /// `balm::MetricDescription` (i.e.,
415 /// `metric.description()->preferredPublicationType()`).
418
419 /// Set the format for the specified `metricId` to the specified `format`.
420 ///
421 /// \note Note that there is no uniform specification for how
422 /// publisher implementations will interpret the supplied `format`.
423 /// Also note that the format for a metric is accessed through the
424 /// `balm::MetricDescription`. For example:
425 /// @code
426 /// metric.description()->format();
427 /// @endcode
428 void setFormat(const MetricId& metricId,
429 const MetricFormat& format);
430
431 /// Return a new unique key that can be used to associate (via
432 /// `setUserData`) and retrieve (via `userData`) a value with a metric (or group of metrics).
433 ///
434 /// \note Note that the returned key can be used by
435 /// clients of `balm` to associate additional information with a metric.
437
438 /// Associate the specified `value` with the specified `key` in the
439 /// description of the specified `metricId`.
440 ///
441 /// \pre The behavior is undefined unless `key` was previously returned from `createUserDataKey`.
442 ///
443 /// \note Note that this method allows clients of `balm` to associate (opaque)
444 /// application-specific information with a metric.
445 void setUserData(const MetricId& metricId,
447 const void *value);
448
449 /// Associate the specified `value` with the specified `key` in any
450 /// metric belonging to a category having the specified `categoryName`,
451 /// or a category whose name begins with `categoryName`, as determined
452 /// by the optionally specified `prefixFlag`. If `prefixFlag` is
453 /// `false` or is not specified, only those metrics belonging to a
454 /// category having `categoryName` will be mapped; otherwise, `value`
455 /// will be associated with `key` for all metrics belonging to any
456 /// category whose name begins with `categoryName`. This association
457 /// applies to existing metrics as well as any subsequently created
458 /// ones. When a metric is created that matches more than one
459 /// registered category prefix, it is not specified which supplied value
460 /// will be associated with `key`, unless only one of those values is
461 /// non-null, in which case the unique non-null value is used.
462 ///
463 /// \pre The behavior is undefined unless `key` was previously returned from
464 /// `createUserDataKey`.
465 void setUserData(const char *categoryName,
467 const void *value,
468 bool prefixFlag = false);
469
470 // ACCESSORS
471
472 /// Return the number of metrics in this registry.
473 bsl::size_t numMetrics() const;
474
475 /// Return the number of categories in this registry.
476 bsl::size_t numCategories() const;
477
478 /// Find the specified `category`, a null-terminated string, in this
479 /// registry. Return the address of the non-modifiable `balm::Category`
480 /// object corresponding to the `category`, or 0 if no such category has
481 /// been registered.
482 const Category *findCategory(const char *category) const;
483
484 /// Find the specified null-terminated strings `category` and `name` in
485 /// this registry. Return the `balm::MetricId` object corresponding to
486 /// the metric having the `category` and `name`, if found, or an invalid
487 /// metric id if no such metric has been registered (i.e., `isValid`
488 /// will return `false`).
489 MetricId findId(const char *category, const char *name) const;
490
491 /// Append to the specified `categories` the addresses of all the
492 /// categories registered by this `balm::MetricRegistry` object.
494
495 /// Format this object to the specified output `stream` at the (absolute
496 /// value of) the optionally specified indentation `level` and return a
497 /// reference to `stream`. If `level` is specified, optionally specify
498 /// `spacesPerLevel`, the number of spaces per indentation level for
499 /// this and all of its nested objects. If `level` is negative,
500 /// suppress indentation of the first line. If `spacesPerLevel` is
501 /// negative, format the entire output on one line, suppressing all but
502 /// the initial indentation (as governed by `level`). If `stream` is
503 /// not valid on entry, this operation has no effect.
504 bsl::ostream& print(bsl::ostream& stream,
505 int level = 0,
506 int spacesPerLevel = 4) const;
507};
508
509} // close package namespace
510
511
512#endif
513
514// ----------------------------------------------------------------------------
515// Copyright 2015 Bloomberg Finance L.P.
516//
517// Licensed under the Apache License, Version 2.0 (the "License");
518// you may not use this file except in compliance with the License.
519// You may obtain a copy of the License at
520//
521// http://www.apache.org/licenses/LICENSE-2.0
522//
523// Unless required by applicable law or agreed to in writing, software
524// distributed under the License is distributed on an "AS IS" BASIS,
525// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
526// See the License for the specific language governing permissions and
527// limitations under the License.
528// ----------------------------- END-OF-FILE ----------------------------------
529
530/** @} */
531/** @} */
532/** @} */
Definition balm_category.h:263
Definition balm_category.h:152
int UserDataKey
Definition balm_metricdescription.h:192
Definition balm_metricformat.h:321
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:653
Definition bslstl_pair.h:1280
Definition bslstl_set.h:691
Definition bslstl_sharedptr.h:1838
Definition bslstl_vector.h:1120
Definition bslma_allocator.h:545
Definition bslmt_rwmutex.h:148
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition balm_bdlmmetricsadapter.h:142
Value
Definition balm_publicationtype.h:83
Definition bdlb_cstringless.h:144
Definition bslma_usesbslmaallocator.h:344