brpc/include/bvar/status.h
2022-12-14 19:05:52 +08:00

243 lines
6.7 KiB
C++

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// Date 2014/09/22 11:57:43
#ifndef BVAR_STATUS_H
#define BVAR_STATUS_H
#include <string> // std::string
#include "butil/atomicops.h"
#include "butil/type_traits.h"
#include "butil/string_printf.h"
#include "butil/synchronization/lock.h"
#include "bvar/detail/is_atomical.h"
#include "bvar/variable.h"
#include "bvar/reducer.h"
namespace bvar {
// Display a rarely or periodically updated value.
// Usage:
// bvar::Status<int> foo_count1(17);
// foo_count1.expose("my_value");
//
// bvar::Status<int> foo_count2;
// foo_count2.set_value(17);
//
// bvar::Status<int> foo_count3("my_value", 17);
template <typename T, typename Enabler = void>
class Status : public Variable {
public:
Status() {}
Status(const T& value) : _value(value) {}
Status(const butil::StringPiece& name, const T& value) : _value(value) {
this->expose(name);
}
Status(const butil::StringPiece& prefix,
const butil::StringPiece& name, const T& value) : _value(value) {
this->expose_as(prefix, name);
}
// Calling hide() manually is a MUST required by Variable.
~Status() { hide(); }
void describe(std::ostream& os, bool /*quote_string*/) const override {
os << get_value();
}
#ifdef BAIDU_INTERNAL
void get_value(boost::any* value) const override {
butil::AutoLock guard(_lock);
*value = _value;
}
#endif
T get_value() const {
butil::AutoLock guard(_lock);
const T res = _value;
return res;
}
void set_value(const T& value) {
butil::AutoLock guard(_lock);
_value = value;
}
private:
T _value;
// We use lock rather than butil::atomic for generic values because
// butil::atomic requires the type to be memcpy-able (POD basically)
mutable butil::Lock _lock;
};
template <typename T>
class Status<T, typename butil::enable_if<detail::is_atomical<T>::value>::type>
: public Variable {
public:
struct PlaceHolderOp {
void operator()(T&, const T&) const {}
};
class SeriesSampler : public detail::Sampler {
public:
typedef typename butil::conditional<
true, detail::AddTo<T>, PlaceHolderOp>::type Op;
explicit SeriesSampler(Status* owner)
: _owner(owner), _series(Op()) {}
void take_sample() { _series.append(_owner->get_value()); }
void describe(std::ostream& os) { _series.describe(os, NULL); }
private:
Status* _owner;
detail::Series<T, Op> _series;
};
public:
Status() : _series_sampler(NULL) {}
Status(const T& value) : _value(value), _series_sampler(NULL) { }
Status(const butil::StringPiece& name, const T& value)
: _value(value), _series_sampler(NULL) {
this->expose(name);
}
Status(const butil::StringPiece& prefix,
const butil::StringPiece& name, const T& value)
: _value(value), _series_sampler(NULL) {
this->expose_as(prefix, name);
}
~Status() {
hide();
if (_series_sampler) {
_series_sampler->destroy();
_series_sampler = NULL;
}
}
void describe(std::ostream& os, bool /*quote_string*/) const override {
os << get_value();
}
#ifdef BAIDU_INTERNAL
void get_value(boost::any* value) const override {
*value = get_value();
}
#endif
T get_value() const {
return _value.load(butil::memory_order_relaxed);
}
void set_value(const T& value) {
_value.store(value, butil::memory_order_relaxed);
}
int describe_series(std::ostream& os, const SeriesOptions& options) const override {
if (_series_sampler == NULL) {
return 1;
}
if (!options.test_only) {
_series_sampler->describe(os);
}
return 0;
}
protected:
int expose_impl(const butil::StringPiece& prefix,
const butil::StringPiece& name,
DisplayFilter display_filter) override {
const int rc = Variable::expose_impl(prefix, name, display_filter);
if (rc == 0 &&
_series_sampler == NULL &&
FLAGS_save_series) {
_series_sampler = new SeriesSampler(this);
_series_sampler->schedule();
}
return rc;
}
private:
butil::atomic<T> _value;
SeriesSampler* _series_sampler;
};
// Specialize for std::string, adding a printf-style set_value().
template <>
class Status<std::string, void> : public Variable {
public:
Status() {}
Status(const butil::StringPiece& name, const char* fmt, ...) {
if (fmt) {
va_list ap;
va_start(ap, fmt);
butil::string_vprintf(&_value, fmt, ap);
va_end(ap);
}
expose(name);
}
Status(const butil::StringPiece& prefix,
const butil::StringPiece& name, const char* fmt, ...) {
if (fmt) {
va_list ap;
va_start(ap, fmt);
butil::string_vprintf(&_value, fmt, ap);
va_end(ap);
}
expose_as(prefix, name);
}
~Status() { hide(); }
void describe(std::ostream& os, bool quote_string) const override {
if (quote_string) {
os << '"' << get_value() << '"';
} else {
os << get_value();
}
}
std::string get_value() const {
butil::AutoLock guard(_lock);
return _value;
}
#ifdef BAIDU_INTERNAL
void get_value(boost::any* value) const override {
*value = get_value();
}
#endif
void set_value(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
{
butil::AutoLock guard(_lock);
butil::string_vprintf(&_value, fmt, ap);
}
va_end(ap);
}
void set_value(const std::string& s) {
butil::AutoLock guard(_lock);
_value = s;
}
private:
std::string _value;
mutable butil::Lock _lock;
};
} // namespace bvar
#endif //BVAR_STATUS_H