libadc-cxx 1.0.0
Structured logging for scientific computing
Loading...
Searching...
No Matches
file.ipp
Go to the documentation of this file.
1/* Copyright 2025 NTESS. See the top-level LICENSE.txt file for details.
2 *
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
7#include <cstdlib>
8#include <iostream>
9#include <fstream>
10#include <filesystem>
11
12namespace adc {
13
14using std::string;
15using std::string_view;
16
17
18/*! \brief File output publisher_api implementation.
19 This plugin generates writes each message to the configured file, with
20 <adct-json></adct-json> delimiters surrounding it.
21 The output directory is "." by default, but may be overriden with
22 a full path defined in env("ADC_FILE_PLUGIN_DIRECTORY").
23 The file name is adc.file_plugin.log by default, and may be overridden
24 with a path name in env("ADC_FILE_PLUGIN_FILE").
25 The file is overwritten when the file_plugin is created, unless
26 env("ADC_FILE_PLUGIN_APPEND") is "true".
27 Debugging output is enabled if
28 env("ADC_FILE_PLUGIN_DEBUG") is a number greater than 0.
29
30 Multiple independent file publishers may be created; if the same file name
31 and directory are used for distinct instances, output file content
32 is undefined.
33 */
34class file_plugin : public publisher_api {
35 enum state {
36 ok,
37 err
38 };
39 enum mode {
40 /* the next mode needed for correct operation */
41 pi_config,
42 pi_init,
43 pi_pub_or_final
44 };
45
46private:
47 inline static const std::map< const string, const string > plugin_file_config_defaults =
48 {{ "DIRECTORY", "."},
49 { "FILE", "adc.file_plugin.log" },
50 { "DEBUG", "0" },
51 { "APPEND", "false" }
52 };
53 inline static const char *plugin_file_prefix = "ADC_FILE_PLUGIN_";
54 const string vers;
55 const std::vector<string> tags;
56 string fname;
57 string fdir;
58 bool fappend;
59 std::ofstream out;
60 int debug;
61 enum state state;
62 bool paused;
63 enum mode mode;
64
65 int config(const string dir, const string file, bool append, const string& sdebug) {
66 if (mode != pi_config)
67 return 2;
68 fname = file;
69 fappend = append;
70 fdir = dir;
71 mode = pi_init;
72 std::stringstream ss(sdebug);
73 ss >> debug;
74 if (debug < 0) {
75 debug = 0;
76 }
77 if (debug > 0) {
78 std::cout<< "file plugin configured" <<std::endl;
79 }
80 return 0;
81 }
82
83 // find field in m, then with prefix in env, then the default.
84 const string get(const std::map< string, string >& m,
85 string field, string_view env_prefix) {
86 // fields not defined in config_defaults raise an exception.
87 auto it = m.find(field);
88 if (it != m.end()) {
89 return it->second;
90 }
91 string en = string(env_prefix) += field;
92 char *ec = getenv(en.c_str());
93 if (!ec) {
94 return plugin_file_config_defaults.at(field);
95 } else {
96 return string(ec);
97 }
98 }
99
100
101public:
102 file_plugin() : vers("1.0.0") , tags({"none"}), fappend(false), debug(0),
103 state(ok), paused(false), mode(pi_config) { }
104
105 int publish(std::shared_ptr<builder_api> b) {
106 if (paused)
107 return 0;
108 if (state != ok)
109 return 1;
110 if (mode != pi_pub_or_final)
111 return 2;
112 // write to stream
113 if (out.good()) {
114 out << "<adct-json>" << b->serialize() << "</adct-json>" << std::endl;
115 if (debug) {
116 std::cout << "'file' wrote" << std::endl;
117 }
118 return 0;
119 }
120 if (debug) {
121 std::cout << "plugin 'file' failed out.good" << std::endl;
122 }
123 return 1;
124 }
125
126 int config(const std::map< std::string, std::string >& m) {
127 return config(m, plugin_file_prefix);
128 }
129
130 int config(const std::map< std::string, std::string >& m, string_view env_prefix) {
131 bool app = ( get(m, "APPEND", env_prefix) == "true");
132 string d = get(m, "DIRECTORY", env_prefix);
133 string f = get(m, "FILE", env_prefix);
134 string sdebug = get(m, "DEBUG", env_prefix);
135 return config(d, std::move(f), app, sdebug);
136 }
137
138 const std::map< const std::string, const std::string> & get_option_defaults() {
139 return plugin_file_config_defaults;
140 }
141
143 std::map <string, string >m;
144 // config if never config'd
145 if (!fname.size())
146 config(m);
147 if (mode != pi_init) {
148 return 2;
149 }
150 if ( state == err ) {
151 std::cout << "file plugin initialize found pre-existing error" << std::endl;
152 return 3;
153 }
154 std::error_code ec;
155 std::filesystem::create_directories(fdir, ec);
156 if (ec.value() != 0 && ec.value() != EEXIST ) {
157 state = err;
158 std::cout << "unable to create output directory for plugin 'file'; "
159 << fdir << " : " << ec.message() << std::endl;
160 return ec.value();
161 }
162 string fpath = fdir + "/" + fname;
163 // open dump file; messages are <adct-json> tag separated, not endl separated, as content may include \n.
164 out.open(fpath, std::ofstream::out |
165 (fappend ? std::ofstream::app : std::ofstream::trunc));
166 if (out.good()) {
167 mode = pi_pub_or_final;
168 return 0;
169 }
170 state = err;
171 return EBADF;
172 }
173
174 void finalize() {
175 if (mode == pi_pub_or_final) {
176 state = ok;
177 paused = false;
178 mode = pi_config;
179 out.close();
180 } else {
181 if (debug) {
182 std::cout << "file plugin finalize on non-running plugin" << std::endl;
183 }
184 }
185 }
186
187 void pause() {
188 paused = true;
189 }
190
191 void resume() {
192 paused = false;
193 }
194
196 return "file";
197 }
198
200 return vers;
201 }
202
204 if (debug) {
205 std::cout << "Destructing file_plugin" << std::endl;
206 }
207 }
208};
209
210} // adc
File output publisher_api implementation. This plugin generates writes each message to the configured...
Definition file.ipp:34
void resume()
Resume publishing Duplicate calls are allowed.
Definition file.ipp:191
void pause()
Pause publishing until a call to resume. Duplicate calls are allowed.
Definition file.ipp:187
int initialize()
Ready the plugin to publish following the configuration options set or defaulted.
Definition file.ipp:142
string_view version() const
Definition file.ipp:199
void finalize()
Stop publishing and release any resources held for managing publication.
Definition file.ipp:174
int config(const std::map< std::string, std::string > &m)
Configure the plugin with the options given.
Definition file.ipp:126
int publish(std::shared_ptr< builder_api > b)
Publish the content of the builder.
Definition file.ipp:105
const std::map< const std::string, const std::string > & get_option_defaults()
Look up the settable options and their defaults.
Definition file.ipp:138
int config(const std::map< std::string, std::string > &m, string_view env_prefix)
Configure the plugin with the options given and the corresponding environment variables.
Definition file.ipp:130
string_view name() const
Definition file.ipp:195
Publisher plugin interface.
Definition publisher.hpp:48
Definition adc.hpp:82
std::string_view string_view
Definition curl.ipp:18
std::string string
Definition curl.ipp:17