1
#include "source/common/tracing/tracer_manager_impl.h"
2

            
3
#include "source/common/config/utility.h"
4

            
5
namespace Envoy {
6
namespace Tracing {
7

            
8
SINGLETON_MANAGER_REGISTRATION(tracer_manager);
9

            
10
TracerManagerImpl::TracerManagerImpl(Server::Configuration::TracerFactoryContextPtr factory_context)
11
9625
    : factory_context_(std::move(factory_context)) {}
12

            
13
TracerSharedPtr
14
46
TracerManagerImpl::getOrCreateTracer(const envoy::config::trace::v3::Tracing_Http* config) {
15
46
  if (!config) {
16
1
    return null_tracer_;
17
1
  }
18

            
19
45
  const auto cache_key = MessageUtil::hash(*config);
20
45
  const auto it = tracers_.find(cache_key);
21
45
  if (it != tracers_.end()) {
22
3
    auto tracer = it->second.lock();
23
3
    if (tracer) { // Tracer might have been released since it's a weak reference
24
3
      return tracer;
25
3
    }
26
3
  }
27

            
28
  // Free memory held by expired weak references.
29
  //
30
  // Given that:
31
  //
32
  // * Tracer is obtained only once per listener lifecycle
33
  // * in a typical case, all listeners will have identical tracing configuration and, consequently,
34
  //   will share the same Tracer instance
35
  // * amount of memory held by an expired weak reference is minimal
36
  //
37
  // it seems reasonable to avoid introducing an external sweeper and only reclaim memory at
38
  // the moment when a new Tracer instance is about to be created.
39
42
  removeExpiredCacheEntries();
40

            
41
  // Initialize a new tracer.
42
42
  ENVOY_LOG(info, "instantiating a new tracer: {}", config->name());
43

            
44
  // Now see if there is a factory that will accept the config.
45
42
  auto& factory =
46
42
      Envoy::Config::Utility::getAndCheckFactory<Server::Configuration::TracerFactory>(*config);
47
42
  ProtobufTypes::MessagePtr message = Envoy::Config::Utility::translateToFactoryConfig(
48
42
      *config, factory_context_->messageValidationVisitor(), factory);
49

            
50
42
  TracerSharedPtr tracer =
51
42
      std::make_shared<Tracing::TracerImpl>(factory.createTracerDriver(*message, *factory_context_),
52
42
                                            factory_context_->serverFactoryContext().localInfo());
53
42
  tracers_.emplace(cache_key, tracer); // cache a weak reference
54
42
  return tracer;
55
45
}
56

            
57
42
void TracerManagerImpl::removeExpiredCacheEntries() {
58
42
  absl::erase_if(tracers_, [](const std::pair<const std::size_t, std::weak_ptr<Tracer>>& entry) {
59
2
    return entry.second.expired();
60
2
  });
61
42
}
62

            
63
std::shared_ptr<TracerManager>
64
9840
TracerManagerImpl::singleton(Server::Configuration::FactoryContext& context) {
65
9840
  return context.serverFactoryContext().singletonManager().getTyped<Tracing::TracerManagerImpl>(
66
9840
      SINGLETON_MANAGER_REGISTERED_NAME(tracer_manager), [&context] {
67
9618
        return std::make_shared<Tracing::TracerManagerImpl>(
68
9618
            std::make_unique<Tracing::TracerFactoryContextImpl>(
69
9618
                context.serverFactoryContext(), context.messageValidationVisitor()));
70
9618
      });
71
9840
}
72

            
73
} // namespace Tracing
74
} // namespace Envoy