xref: /6.6.0/phosphor/src/trace_config.cc (revision 5b7b00a8)
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_mode(_buffer_mode),
94              buffer_size(_buffer_size),
95              buffer_factory(modeToFactory(_buffer_mode)),
96              enabled_categories({{"*"}}) {}
97
98    TraceConfig::TraceConfig(trace_buffer_factory _buffer_factory,
99                             size_t _buffer_size)
100            : buffer_mode(BufferMode::custom),
101              buffer_size(_buffer_size),
102              buffer_factory(_buffer_factory),
103              enabled_categories({{"*"}}) {}
104
105    trace_buffer_factory TraceConfig::modeToFactory(BufferMode mode) {
106        switch (mode) {
107            case BufferMode::fixed:
108                return trace_buffer_factory(make_fixed_buffer);
109            case BufferMode::ring:
110                return trace_buffer_factory(make_ring_buffer);
111            case BufferMode::custom:
112                throw std::invalid_argument(
113                        "phosphor::TraceConfig::modeToFactory: "
114                                "Cannot get factory for Custom Mode");
115        }
116        throw std::invalid_argument(
117                "phosphor::TraceConfig::modeToFactory:Invalid buffer mode");
118    }
119
120    BufferMode TraceConfig::getBufferMode() const {
121        return buffer_mode;
122    }
123
124    trace_buffer_factory TraceConfig::getBufferFactory() const {
125        return buffer_factory;
126    }
127
128    size_t TraceConfig::getBufferSize() const {
129        return buffer_size;
130    }
131
132    TraceConfig &TraceConfig::setStoppedCallback(
133            std::shared_ptr<TracingStoppedCallback> _tracing_stopped_callback) {
134        tracing_stopped_callback = _tracing_stopped_callback;
135        return *this;
136    }
137
138    TracingStoppedCallback* TraceConfig::getStoppedCallback() const {
139        return tracing_stopped_callback.get();
140    }
141
142    TraceConfig &TraceConfig::setStopTracingOnDestruct(bool _stop_tracing) {
143        stop_tracing = _stop_tracing;
144        return *this;
145    }
146
147    bool TraceConfig::getStopTracingOnDestruct() const {
148        return stop_tracing;
149    }
150
151    TraceConfig &TraceConfig::setCategories(
152            const std::vector<std::string> &enabled,
153            const std::vector<std::string> &disabled) {
154        enabled_categories = enabled;
155        disabled_categories = disabled;
156        return *this;
157    }
158
159    const std::vector<std::string> &TraceConfig::getEnabledCategories() const {
160        return enabled_categories;
161    }
162
163    const std::vector<std::string> &TraceConfig::getDisabledCategories() const {
164        return disabled_categories;
165    }
166
167    TraceConfig TraceConfig::fromString(const std::string &config) {
168        auto arguments(phosphor::utils::split_string(config, ';'));
169
170        BufferMode mode = BufferMode::fixed;
171        int buffer_size = 1024 * 1024 * 8;
172        std::string filename = "";
173        std::string enabled_categories = "*";
174        std::string disabled_categories = "";
175
176        for (const std::string &argument : arguments) {
177            auto kv(phosphor::utils::split_string(argument, ':'));
178
179            if (kv.size() != 2) {
180                // if split_string does not return a key and a value (2 items)
181                throw std::invalid_argument(
182                        "TraceConfig::fromString: "
183                        "Invalid arguments provided. Arguments must be "
184                        "given in as 'key:value;' pairs");
185            };
186
187            std::string key(kv[0]);
188            std::string value(kv[1]);
189
190            if (key == "buffer-mode") {
191                if (value == "fixed") {
192                    mode = BufferMode::fixed;
193                } else if (value == "ring") {
194                    mode = BufferMode::ring;
195                } else {
196                    throw std::invalid_argument(
197                            "TraceConfig::fromString: "
198                                    "Invalid buffer mode given");
199                }
200            } else if (key == "buffer-size") {
201                try {
202                    buffer_size = std::stoi(value);
203                } catch (std::invalid_argument &e) {
204                    throw std::invalid_argument(
205                            "TraceConfig::fromString: "
206                                    "buffer size was not a valid integer");
207                } catch (std::out_of_range &e) {
208                    throw std::invalid_argument(
209                            "TraceConfig::fromString: "
210                                    "buffer size was too large");
211                }
212
213                if (buffer_size < 0) {
214                    throw std::invalid_argument(
215                            "TraceConfig::fromString: "
216                                    "buffer size cannot be negative");
217                }
218            } else if (key == "save-on-stop") {
219                filename = value;
220            } else if (key == "enabled-categories") {
221                enabled_categories = value;
222            } else if (key == "disabled-categories") {
223                disabled_categories = value;
224            }
225        }
226
227        TraceConfig config_obj(mode, static_cast<size_t>(buffer_size));
228        if (filename != "") {
229            config_obj.setStoppedCallback(
230                std::make_shared<tools::FileStopCallback>(filename));
231            config_obj.setStopTracingOnDestruct(true);
232        }
233        config_obj.setCategories(utils::split_string(enabled_categories, ','),
234                                 utils::split_string(disabled_categories, ','));
235        return config_obj;
236    }
237
238    StringPtr TraceConfig::toString() const {
239        std::stringstream result;
240
241        result << "buffer-mode:" << buffer_mode << ";";
242        result << "buffer-size:" << buffer_size << ";";
243        result << "enabled-categories:"
244               << utils::join_string(enabled_categories, ',') << ";";
245        result << "disabled-categories:"
246               << utils::join_string(disabled_categories, ',') << "";
247
248        // Can't easily do the 'save-on-stop' callback
249
250        return make_String(result.str());
251    }
252}
253