xref: /6.6.0/phosphor/src/trace_config.cc (revision e2feef21)
1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2016 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17
18#include <cstring>
19#include <exception>
20#include <string>
21
22#include "phosphor/tools/export.h"
23#include "phosphor/trace_config.h"
24#include "utils/memory.h"
25#include "utils/string_utils.h"
26
27namespace phosphor {
28
29    std::ostream &operator<<(std::ostream &stream, const BufferMode mode) {
30        switch (mode) {
31            case BufferMode::custom:
32                stream << "custom";
33                break;
34            case BufferMode::fixed:
35                stream << "fixed";
36                break;
37            case BufferMode::ring:
38                stream << "ring";
39                break;
40        }
41        return stream;
42    }
43
44    void StringPtrDeleter::operator()(const std::string* ptr) {
45        delete ptr;
46    }
47
48    StringPtr make_String(const std::string& str) {
49        return StringPtr(new std::string(str));
50    }
51
52/*
53 * TraceLogConfig implementation
54 */
55    TraceLogConfig &TraceLogConfig::setStartupTrace(
56            const TraceConfig &_startup_trace) {
57        startup_trace = utils::make_unique<TraceConfig>(_startup_trace);
58        return *this;
59    }
60
61    TraceLogConfig &TraceLogConfig::clearStartupTrace() {
62        startup_trace.release();
63        return *this;
64    }
65
66    TraceConfig *TraceLogConfig::getStartupTrace() const {
67        return startup_trace.get();
68    }
69
70    TraceLogConfig &TraceLogConfig::fromEnvironment() {
71        const char *startup_config = std::getenv("PHOSPHOR_TRACING_START");
72        if (startup_config && strlen(startup_config)) {
73            this->setStartupTrace(TraceConfig::fromString(startup_config));
74        }
75
76        return *this;
77    }
78
79/*
80 * TraceConfig implementation
81 */
82
83    // Define the default constructor and destructor non-inline because this
84    // class is part of the DLL interface and the executable may be using a
85    // different CRT. Therefore by making the destructor non-inline we ensure
86    // that memory is allocated and freed using the same runtime as the
87    // constructors.
88    TraceConfig::TraceConfig() = default;
89
90    TraceConfig::~TraceConfig() = default;
91
92    TraceConfig::TraceConfig(BufferMode _buffer_mode, size_t _buffer_size)
93            : buffer_factory_container(_buffer_mode),
94              buffer_size(_buffer_size),
95              enabled_categories({{"*"}}) {}
96
97    TraceConfig::TraceConfig(trace_buffer_factory _buffer_factory,
98                             size_t _buffer_size)
99            : buffer_factory_container(_buffer_factory),
100              buffer_size(_buffer_size),
101              enabled_categories({{"*"}}) {}
102
103    trace_buffer_factory TraceConfig::BufferFactoryContainer::modeToFactory(BufferMode mode) {
104        switch (mode) {
105            case BufferMode::fixed:
106                return trace_buffer_factory(make_fixed_buffer);
107            case BufferMode::ring:
108                return trace_buffer_factory(make_ring_buffer);
109            case BufferMode::custom:
110                throw std::invalid_argument(
111                        "phosphor::TraceConfig::BufferFactoryContainer::modeToFactory: "
112                        "Cannot get factory for Custom Mode");
113        }
114        throw std::invalid_argument(
115                "phosphor::TraceConfig::BufferFactoryContainer::modeToFactory: "
116                "Invalid buffer mode");
117    }
118
119    BufferMode TraceConfig::getBufferMode() const {
120        return buffer_factory_container.mode;
121    }
122
123    trace_buffer_factory TraceConfig::getBufferFactory() const {
124        return buffer_factory_container.factory;
125    }
126
127    size_t TraceConfig::getBufferSize() const {
128        return buffer_size;
129    }
130
131    TraceConfig &TraceConfig::setStoppedCallback(
132            std::shared_ptr<TracingStoppedCallback> _tracing_stopped_callback) {
133        tracing_stopped_callback = _tracing_stopped_callback;
134        return *this;
135    }
136
137    TracingStoppedCallback* TraceConfig::getStoppedCallback() const {
138        return tracing_stopped_callback.get();
139    }
140
141    TraceConfig &TraceConfig::setStopTracingOnDestruct(bool _stop_tracing) {
142        stop_tracing = _stop_tracing;
143        return *this;
144    }
145
146    bool TraceConfig::getStopTracingOnDestruct() const {
147        return stop_tracing;
148    }
149
150    TraceConfig &TraceConfig::setCategories(
151            const std::vector<std::string> &enabled,
152            const std::vector<std::string> &disabled) {
153        enabled_categories = enabled;
154        disabled_categories = disabled;
155        return *this;
156    }
157
158    const std::vector<std::string> &TraceConfig::getEnabledCategories() const {
159        return enabled_categories;
160    }
161
162    const std::vector<std::string> &TraceConfig::getDisabledCategories() const {
163        return disabled_categories;
164    }
165
166    void TraceConfig::updateFromString(const std::string& config) {
167        auto arguments(phosphor::utils::split_string(config, ';'));
168
169        for (const std::string &argument : arguments) {
170            auto kv(phosphor::utils::split_string(argument, ':'));
171
172            if (kv.size() != 2) {
173                // if split_string does not return a key and a value (2 items)
174                throw std::invalid_argument(
175                        "TraceConfig::fromString: "
176                        "Invalid arguments provided. Arguments must be "
177                        "given in as 'key:value;' pairs");
178            };
179
180            std::string key(kv[0]);
181            std::string value(kv[1]);
182
183            if (key == "buffer-mode") {
184                if (value == "fixed") {
185                    buffer_factory_container = BufferMode::fixed;
186                } else if (value == "ring") {
187                    buffer_factory_container = BufferMode::ring;
188                } else {
189                    throw std::invalid_argument(
190                            "TraceConfig::fromString: "
191                                    "Invalid buffer mode given");
192                }
193            } else if (key == "buffer-size") {
194                int size;
195                try {
196                    size = std::stoi(value);
197                } catch (std::invalid_argument &) {
198                    throw std::invalid_argument(
199                            "TraceConfig::fromString: "
200                                    "buffer size was not a valid integer");
201                } catch (std::out_of_range &) {
202                    throw std::invalid_argument(
203                            "TraceConfig::fromString: "
204                                    "buffer size was too large");
205                }
206
207                if (size < 0) {
208                    throw std::invalid_argument(
209                            "TraceConfig::fromString: "
210                                    "buffer size cannot be negative");
211                }
212                buffer_size = size;
213            } else if (key == "save-on-stop") {
214                tracing_stopped_callback =
215                    std::make_shared<tools::FileStopCallback>(value);
216                stop_tracing = true;
217            } else if (key == "enabled-categories") {
218                enabled_categories = utils::split_string(value, ',');
219            } else if (key == "disabled-categories") {
220                disabled_categories = utils::split_string(value, ',');
221            }
222        }
223    }
224
225    TraceConfig TraceConfig::fromString(const std::string& config) {
226        TraceConfig config_obj(BufferMode::fixed,
227                               static_cast<size_t>(1024 * 1024 * 8));
228        config_obj.setCategories({"*"}, {});
229        config_obj.updateFromString(config);
230        return config_obj;
231    }
232
233    StringPtr TraceConfig::toString() const {
234        std::stringstream result;
235
236        result << "buffer-mode:" << buffer_factory_container.mode << ";";
237        result << "buffer-size:" << buffer_size << ";";
238        result << "enabled-categories:"
239               << utils::join_string(enabled_categories, ',') << ";";
240        result << "disabled-categories:"
241               << utils::join_string(disabled_categories, ',') << "";
242
243        // Can't easily do the 'save-on-stop' callback
244
245        return make_String(result.str());
246    }
247
248    TraceConfig::BufferFactoryContainer::BufferFactoryContainer(BufferMode m)
249      : mode(m),
250        factory(modeToFactory(m)) {
251    }
252
253    TraceConfig::BufferFactoryContainer::BufferFactoryContainer(trace_buffer_factory f)
254      : mode(BufferMode::custom),
255        factory(f) {
256    }
257
258}
259