-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Created 5 examples and a way to compile them with make example. Basic example, content example, holder example, utils example and aggregated file example. All have comprehensive comments and are somewhat interactive.
- Loading branch information
Daniel Pelanek
committed
Jun 20, 2024
1 parent
cb7ab15
commit a488f5d
Showing
8 changed files
with
468 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
add_executable(test1 | ||
basicExample.cpp | ||
) | ||
|
||
target_link_libraries(test1 PRIVATE | ||
telemetry::telemetry | ||
telemetry::appFs | ||
) | ||
|
||
add_executable(test2 | ||
contentExample.cpp | ||
) | ||
|
||
target_link_libraries(test2 PRIVATE | ||
telemetry::telemetry | ||
telemetry::appFs | ||
) | ||
|
||
add_executable(test3 | ||
holderExample.cpp | ||
) | ||
|
||
target_link_libraries(test3 PRIVATE | ||
telemetry::telemetry | ||
telemetry::appFs | ||
) | ||
|
||
add_executable(test4 | ||
utilsExample.cpp | ||
) | ||
|
||
target_link_libraries(test4 PRIVATE | ||
telemetry::telemetry | ||
telemetry::appFs | ||
) | ||
|
||
add_executable(test5 | ||
aggregatedFileExample.cpp | ||
) | ||
|
||
target_link_libraries(test5 PRIVATE | ||
telemetry::telemetry | ||
telemetry::appFs | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/** | ||
* @file | ||
* @author Daniel Pelanek <xpeland00@vutbr.cz> | ||
* @brief Shows how the aggregated files are used and it's methods | ||
* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
|
||
#include <telemetry.hpp> | ||
#include <appFs.hpp> | ||
|
||
// example help | ||
#include <iostream> | ||
|
||
telemetry::Content returnValue(int64_t value) { | ||
return telemetry::Scalar(value); | ||
} | ||
|
||
telemetry::Content returnValueDict(int64_t value) { | ||
telemetry::Dict dict; | ||
dict["1"] = telemetry::Scalar(value*2); | ||
|
||
return dict; | ||
} | ||
|
||
int main() { | ||
// Same as basic example | ||
std::shared_ptr<telemetry::Directory> telemetryRootNode; | ||
telemetryRootNode = telemetry::Directory::create(); | ||
|
||
std::string fusePath = "fusedir"; | ||
|
||
telemetry::appFs::AppFsFuse fuse = telemetry::appFs::AppFsFuse(telemetryRootNode, fusePath, true, true); | ||
fuse.start(); | ||
|
||
// We create two fileops that just return a constant value | ||
const telemetry::FileOps fileOps1 | ||
= {[]() { return returnValue(2); }, nullptr}; | ||
|
||
const telemetry::FileOps fileOps2 | ||
= {[]() { return returnValue(5); }, nullptr}; | ||
|
||
|
||
// It is better to keep the files in another directory and not | ||
// aggregate them straight from root dir. | ||
auto aggFileDir = telemetryRootNode->addDir("aggDir"); | ||
auto file1 = aggFileDir->addFile("file1", fileOps1); | ||
auto file2 = aggFileDir->addFile("file2", fileOps2); | ||
|
||
// Here we init three different aggregation operations. | ||
// One of them is join meaning it will add values from all files into an array. | ||
// The two arguments after the method type are source dict field name and result dict field name | ||
// If they are left empty ("") the values are taken directly from file->read() and | ||
// directly returned as telemetry::Scalar, telemetry::Array, ... | ||
// The result here is 1 : [2, 5]. | ||
const telemetry::AggOperation aggOp0 = {telemetry::AggMethodType::JOIN, "", "1"}; | ||
|
||
// Average of read from files in aggfile if there are different types of Scalar(WithUnit)s the return | ||
// type is same as in cpp meaning avg of uint64_t, int64_t and double the result is double. | ||
const telemetry::AggOperation aggOp1 = {telemetry::AggMethodType::AVG}; | ||
// Sum of read from files in aggfile | ||
const telemetry::AggOperation aggOp2 = {telemetry::AggMethodType::SUM}; | ||
|
||
// We have to add these aggregation operations into a vector. | ||
std::vector<telemetry::AggOperation> aggOps0 = {aggOp0}; | ||
std::vector<telemetry::AggOperation> aggOps1 = {aggOp1}; | ||
std::vector<telemetry::AggOperation> aggOps2 = {aggOp2}; | ||
|
||
// The method for creating an aggregated file is addAggFile | ||
// You can specify which of the files from a directory are picked | ||
// by regex. | ||
auto aggFile0 = aggFileDir->addAggFile("aggFile", "file[0-9]+", aggOps0); | ||
auto aggFile1 = aggFileDir->addAggFile("aggFile1", "file[0-9]+", aggOps1); | ||
auto aggFile2 = aggFileDir->addAggFile("aggFile2", "file[0-9]+", aggOps2); | ||
|
||
// Just for showing the results to terminal. The same results will be in the | ||
// actual filesystem. | ||
std::cout << "Single aggregation operations: \n"; | ||
std::cout << telemetry::contentToString(aggFile0->read()) << "\n"; | ||
std::cout << telemetry::contentToString(aggFile1->read()) << "\n"; | ||
std::cout << telemetry::contentToString(aggFile2->read()) << "\n"; | ||
|
||
|
||
// Using two aggregation operations in a single file is only possible when | ||
// the sources are dicts. | ||
const telemetry::FileOps fileOpsDict1 | ||
= {[]() { return returnValueDict(2); }, nullptr}; | ||
|
||
const telemetry::FileOps fileOpsDict2 | ||
= {[]() { return returnValueDict(5); }, nullptr}; | ||
|
||
auto aggFileDirDict = telemetryRootNode->addDir("aggDirDict"); | ||
auto fileDict1 = aggFileDirDict->addFile("fileDict1", fileOpsDict1); | ||
auto fileDict2 = aggFileDirDict->addFile("fileDict2", fileOpsDict2); | ||
|
||
// The result dict keys have to be different. If they are the same only | ||
// the first result is valid and is read. | ||
const telemetry::AggOperation aggOpDict0 = {telemetry::AggMethodType::JOIN, "1", "1"}; | ||
const telemetry::AggOperation aggOpDict1 = {telemetry::AggMethodType::AVG, "1", "2"}; | ||
|
||
std::vector<telemetry::AggOperation> aggOpsDict = {aggOpDict0, aggOpDict1}; | ||
|
||
auto aggFileDict = aggFileDirDict->addAggFile("aggFileDict", "fileDict[0-9]+", aggOpsDict); | ||
|
||
std::cout << "\nMultiple aggregation operations: \n"; | ||
std::cout << telemetry::contentToString(aggFileDict->read()) << "\n"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
/** | ||
* @file | ||
* @author Daniel Pelanek <xpeland00@vutbr.cz> | ||
* @brief Shows the basic usage of telemetry with fuse | ||
* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
|
||
#include <telemetry.hpp> | ||
#include <appFs.hpp> | ||
#include <memory> | ||
|
||
// example help | ||
#include <chrono> | ||
#include <csignal> | ||
#include <atomic> | ||
std::atomic<bool> g_gotSIGINT(false); | ||
void signalHandler(int signum) { | ||
(void)signum; | ||
g_gotSIGINT.store(true); | ||
} | ||
|
||
|
||
// The return value has to be telemetry::Content or one of its variants. | ||
telemetry::Content getTimeElapsed(const std::chrono::time_point<std::chrono::system_clock>& startTime) { | ||
auto now = std::chrono::system_clock::now(); | ||
auto timeElapsed = std::chrono::duration_cast<std::chrono::seconds>(now - startTime).count(); | ||
|
||
// telemetry::Content is std::variant<Scalar, ScalarWithUnit, Array, Dict>. | ||
// How they are used is shown in another example. | ||
return telemetry::Scalar(timeElapsed); | ||
} | ||
|
||
// Resets start time to the current time. | ||
void clearTime(std::chrono::time_point<std::chrono::system_clock>& startTime) { | ||
startTime = std::chrono::system_clock::now(); | ||
} | ||
|
||
int main() { | ||
// Creating root dir for filesystem. | ||
std::shared_ptr<telemetry::Directory> telemetryRootNode; | ||
telemetryRootNode = telemetry::Directory::create(); | ||
|
||
// The path to root dir is local to where the program is called from. | ||
std::string fusePath = "fusedir"; | ||
|
||
// Linking root dir to the chosen directory on disk. | ||
// If the fourth argument is true it means the directory on disk doesn't need to | ||
// exist before starting program. | ||
telemetry::appFs::AppFsFuse fuse = telemetry::appFs::AppFsFuse(telemetryRootNode, fusePath, true, true); | ||
fuse.start(); | ||
// The filesystem is still just empty. | ||
// / | ||
|
||
// So let's a directory named input into the root dir. | ||
std::shared_ptr<telemetry::Directory> inputDir = telemetryRootNode->addDir("input"); | ||
// Now the filesystem looks like this. | ||
// / | ||
// └─ input/ | ||
|
||
|
||
// Every file can have two lambdas attached to it. | ||
// | ||
// One for reading -> What gets called when something tries to read the file on disk. | ||
// Here we write the return value of getTime to the file. | ||
// | ||
// One for clearing -> What gets called when you want to reset telemetry data. | ||
// In this case we reset the startTime. | ||
auto startTime = std::chrono::system_clock::now(); | ||
const telemetry::FileOps fileOps | ||
= {[&startTime]() { return getTimeElapsed(startTime); }, | ||
[&startTime]() { return clearTime(startTime); }}; | ||
|
||
// The read and clear functions are optional. In the case you don't use them pass | ||
// a null pointer instead. | ||
const telemetry::FileOps anotherFileOps | ||
= {nullptr, nullptr}; | ||
|
||
|
||
// Files be put into the root directory. | ||
const std::shared_ptr<telemetry::File> timeFile = telemetryRootNode->addFile("time", fileOps); | ||
// Now it looks like this. | ||
// / | ||
// ├─ input/ | ||
// └─ time | ||
|
||
// Or into another directory. | ||
const std::shared_ptr<telemetry::File> anotherTimeFile = inputDir->addFile("time", anotherFileOps); | ||
// Now it looks like this. | ||
// / | ||
// ├─ input/ | ||
// │ └─ time | ||
// └─ time | ||
|
||
// Waiting for ctrl+c. In the meantime you can open another terminal and | ||
// navigate to the newly linked directory. Just reading the new time file | ||
// should print the time elapsed in seconds since the start of the program. | ||
std::signal(SIGINT, signalHandler); | ||
while(!g_gotSIGINT.load()){}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/** | ||
* @file | ||
* @author Daniel Pelanek <xpeland00@vutbr.cz> | ||
* @brief Shows how telemetry content data types are used | ||
* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
|
||
#include <telemetry.hpp> | ||
|
||
// example help | ||
#include <iostream> | ||
|
||
// Simplest type. Only contains one value . | ||
// The values can be of type std::monostate, bool, uint64_t, int64_t, double, std::string. | ||
telemetry::Scalar scalarReturn() { | ||
return telemetry::Scalar(static_cast<uint64_t>(100)); | ||
} | ||
|
||
// Contains not only scalar but also has a unit. | ||
// The unit is of type string. | ||
telemetry::ScalarWithUnit scalartWithUnitReturn() { | ||
return telemetry::ScalarWithUnit(static_cast<double>(42), "%"); | ||
} | ||
|
||
// Array is a vector of Scalars. | ||
telemetry::Array arrayReturn() { | ||
telemetry::Array arr; | ||
|
||
const uint64_t nScalars = 10; | ||
|
||
for(uint64_t index = 0; index < nScalars; index++) { | ||
arr.push_back(telemetry::Scalar(index)); | ||
} | ||
|
||
return arr; | ||
} | ||
|
||
// Dict is a map with string as a key. | ||
// Value can be std::monostate or any one of the three previous types | ||
telemetry::Dict dictReturn() { | ||
telemetry::Dict dict; | ||
|
||
dict["1"] = telemetry::Scalar(static_cast<int64_t>(10)); | ||
dict["2"] = telemetry::ScalarWithUnit(static_cast<bool>(10), "bool"); | ||
dict["3"] = telemetry::Array(std::vector<telemetry::Scalar>()); | ||
|
||
return dict; | ||
} | ||
|
||
int main() { | ||
// telemetry::Content can be easily printed or stored as string with contentToString() | ||
std::cout << telemetry::contentToString(scalarReturn()) << "\n"; | ||
std::cout << telemetry::contentToString(scalartWithUnitReturn()) << "\n"; | ||
std::cout << telemetry::contentToString(arrayReturn()) << "\n"; | ||
std::cout << telemetry::contentToString(dictReturn()) << "\n"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/** | ||
* @file | ||
* @author Daniel Pelanek <xpeland00@vutbr.cz> | ||
* @brief Shows how to use the holder class | ||
* | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
|
||
#include <telemetry.hpp> | ||
#include <appFs.hpp> | ||
|
||
// Object that collects it's own telemetry or owns | ||
// telemetry files or directories. | ||
class IOwnTelemetryFiles { | ||
public: | ||
void configTelemetry(const std::shared_ptr<telemetry::Directory>& rootDir) { | ||
// Create a telemetry file | ||
const telemetry::FileOps fileOps | ||
= {nullptr, nullptr}; | ||
|
||
auto someFile = rootDir->addFile("someFile", fileOps); | ||
|
||
// We also need to add the file to the holder. | ||
m_telemetryHolder.add(someFile); | ||
} | ||
|
||
// If you want to disable callback of files before the | ||
// is destroyed. | ||
void disableFiles() { | ||
m_telemetryHolder.disableFiles(); | ||
} | ||
|
||
private: | ||
telemetry::Holder m_telemetryHolder; | ||
}; | ||
|
||
int main() { | ||
// Same as basic example | ||
std::shared_ptr<telemetry::Directory> telemetryRootNode; | ||
telemetryRootNode = telemetry::Directory::create(); | ||
|
||
std::string fusePath = "fusedir"; | ||
|
||
telemetry::appFs::AppFsFuse fuse = telemetry::appFs::AppFsFuse(telemetryRootNode, fusePath, true, true); | ||
fuse.start(); | ||
|
||
// The files callbacks get disabled when the telemetry holder | ||
// is destroyed and if the files and dirs don't have another reference | ||
// elsewhere they get destroyed too. | ||
IOwnTelemetryFiles object; | ||
|
||
// Configuration of telemetry inside of the object. | ||
object.configTelemetry(telemetryRootNode); | ||
|
||
// Disable callbacks before the objects destructor | ||
object.disableFiles(); | ||
} |
Oops, something went wrong.