]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/opentracing-cpp/mocktracer/src/tracer_factory.cpp
buildsys: switch source download to quincy
[ceph.git] / ceph / src / jaegertracing / opentracing-cpp / mocktracer / src / tracer_factory.cpp
CommitLineData
f67539c2
TL
1#include <opentracing/mocktracer/json_recorder.h>
2#include <opentracing/mocktracer/tracer.h>
3#include <opentracing/mocktracer/tracer_factory.h>
4#include <cctype>
5#include <cerrno>
6#include <cstring>
7#include <fstream>
8#include <stdexcept>
9#include <string>
10
11namespace opentracing {
12BEGIN_OPENTRACING_ABI_NAMESPACE
13namespace mocktracer {
14
15namespace {
16struct InvalidConfigurationError : public std::exception {
17 public:
18 InvalidConfigurationError(const char* position, std::string&& message)
19 : position_{position}, message_{std::move(message)} {}
20
21 const char* what() const noexcept override { return message_.c_str(); }
22
23 const char* position() const { return position_; }
24
25 private:
26 const char* position_;
27 std::string message_;
28};
29} // namespace
30
31static void Consume(const char*& i, const char* last, string_view s) {
32 if (static_cast<std::size_t>(std::distance(i, last)) < s.size()) {
33 throw InvalidConfigurationError{i,
34 std::string{"expected "} + std::string{s}};
35 }
36
37 for (size_t index = 0; index < s.size(); ++index) {
38 if (*i++ != s[index]) {
39 throw InvalidConfigurationError{
40 i, std::string{"expected "} +
41 std::string{s.data() + index, s.data() + s.size()}};
42 }
43 }
44}
45
46static void ConsumeWhitespace(const char*& i, const char* last) {
47 for (; i != last; ++i) {
48 if (!std::isspace(*i)) {
49 return;
50 }
51 }
52}
53
54static void ConsumeToken(const char*& i, const char* last, string_view token) {
55 ConsumeWhitespace(i, last);
56 Consume(i, last, token);
57}
58
59static std::string ParseFilename(const char*& i, const char* last) {
60 ConsumeToken(i, last, "\"");
61 std::string result;
62 while (i != last) {
63 if (*i == '\"') {
64 ++i;
65 return result;
66 }
67 if (*i == '\\') {
68 throw InvalidConfigurationError{
69 i, "escaped characters are not supported in filename"};
70 }
71 if (std::isprint(*i)) {
72 result.push_back(*i);
73 } else {
74 throw InvalidConfigurationError{i, "invalid character"};
75 }
76 ++i;
77 }
78
79 throw InvalidConfigurationError{i, R"(no matching ")"};
80}
81
82static std::string ParseConfiguration(const char* i, const char* last) {
83 ConsumeToken(i, last, "{");
84 ConsumeToken(i, last, R"("output_file")");
85 ConsumeToken(i, last, ":");
86 auto filename = ParseFilename(i, last);
87 ConsumeToken(i, last, "}");
88 ConsumeWhitespace(i, last);
89 if (i != last) {
90 throw InvalidConfigurationError{i, "expected EOF"};
91 }
92
93 return filename;
94}
95
96struct MockTracerConfiguration {
97 std::string output_file;
98};
99
100expected<std::shared_ptr<Tracer>> MockTracerFactory::MakeTracer(
101 const char* configuration, std::string& error_message) const noexcept try {
102 MockTracerConfiguration tracer_configuration;
103 if (configuration == nullptr) {
104 error_message = "configuration must not be null";
105 return make_unexpected(invalid_configuration_error);
106 }
107 try {
108 tracer_configuration.output_file = ParseConfiguration(
109 configuration, configuration + std::strlen(configuration));
110 } catch (const InvalidConfigurationError& e) {
111 error_message = std::string{"Error parsing configuration at position "} +
112 std::to_string(std::distance(configuration, e.position())) +
113 ": " + e.what();
114 return make_unexpected(invalid_configuration_error);
115 }
116
117 errno = 0;
118 std::unique_ptr<std::ostream> ostream{
119 new std::ofstream{tracer_configuration.output_file}};
120 if (!ostream->good()) {
121 error_message = "failed to open file `";
122 error_message += tracer_configuration.output_file + "` (";
123 error_message += std::strerror(errno);
124 error_message += ")";
125 return make_unexpected(invalid_configuration_error);
126 }
127
128 MockTracerOptions tracer_options;
129 tracer_options.recorder =
130 std::unique_ptr<Recorder>{new JsonRecorder{std::move(ostream)}};
131
132 return std::shared_ptr<Tracer>{new MockTracer{std::move(tracer_options)}};
133} catch (const std::bad_alloc&) {
134 return make_unexpected(std::make_error_code(std::errc::not_enough_memory));
135}
136
137} // namespace mocktracer
138END_OPENTRACING_ABI_NAMESPACE
139} // namespace opentracing