Skip to content

Commit b9e578b

Browse files
committed
Telemetry: Fail initialization if cache file cannot be opened
If the cache file cannot be opened, fail initialization early. Otherwise telemetry events are not persisted and never reach the Aria backend. Signed-off-by: Krzysztof Kanas <kkanas@microsoft.com>
1 parent 48a7ac9 commit b9e578b

5 files changed

Lines changed: 50 additions & 22 deletions

File tree

src/common/telemetry/bin/main.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ int main(int argc, char* argv[])
4646
OsConfigLogInfo(g_log, "%s", init_message.c_str());
4747

4848
OsConfigLogInfo(g_log, "Telemetry initializing...");
49-
Telemetry::TelemetryManager telemetryManager(args.verbose, args.teardown_time, g_log);
49+
std::string cacheFilePath(Telemetry::TelemetryManager::TELEMETRY_CACHE_FILE_NAME);
50+
Telemetry::TelemetryManager telemetryManager(cacheFilePath, args.verbose, args.teardown_time, g_log);
5051

5152
(void)(telemetryManager.ProcessJsonFile(args.filepath));
5253
OsConfigLogInfo(g_log, "Processed telemetry JSON file: %s", args.filepath.c_str());

src/common/telemetry/bin/tests/TelemetryBinTests.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,16 @@ class TelemetryBinTest : public ::testing::Test
2222
{
2323
protected:
2424
std::string m_testDir;
25+
std::string m_telemetryCache;
2526

2627
void SetUp() override
2728
{
2829
// Create a temporary directory for test files
2930
char tmpDir[] = "/tmp/telemetry_test_XXXXXX";
3031
ASSERT_NE(nullptr, mkdtemp(tmpDir));
3132
m_testDir = std::string(tmpDir);
33+
34+
m_telemetryCache = m_testDir + "/telemetry_cache_db";
3235
}
3336

3437
void TearDown() override
@@ -290,14 +293,13 @@ TEST_F(TelemetryBinTest, FileAndPositionalArgumentCannotBothBeUsed)
290293
TEST_F(TelemetryBinTest, ProcessesValidSingleLineJson)
291294
{
292295
std::string jsonFile = CreateTestJsonFile(R"({"EventName":"TestEvent","TestKey":"TestValue"})");
293-
294296
try
295297
{
296-
Telemetry::TelemetryManager telemetryManager(false, std::chrono::seconds{1});
298+
Telemetry::TelemetryManager telemetryManager(m_telemetryCache, false, std::chrono::seconds{1});
297299
EXPECT_FALSE(telemetryManager.ProcessJsonFile(jsonFile));
298300
}
299301
catch (const std::exception& e)
300302
{
301-
GTEST_SKIP() << "TelemetryManager creation failed: " << e.what();
303+
EXPECT_TRUE(false);
302304
}
303305
}

src/common/telemetry/lib/Telemetry.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,31 @@ using namespace MAT;
2121
namespace Telemetry
2222
{
2323

24-
TelemetryManager::TelemetryManager(bool enableDebug, std::chrono::seconds teardownTime, OsConfigLogHandle logHandle)
24+
TelemetryManager::TelemetryManager(std::string cacheFilePath,bool enableDebug, std::chrono::seconds teardownTime, OsConfigLogHandle logHandle)
2525
: m_log(logHandle)
2626
, m_logManager(nullptr)
2727
, m_logger(nullptr)
2828
{
29+
{
30+
FILE* testWrite = fopen(cacheFilePath.c_str(), "a");
31+
if (testWrite)
32+
{
33+
fclose(testWrite);
34+
}
35+
else
36+
{
37+
OsConfigLogError(m_log, "Telemetry sdk cache path '%s' not writable aborting", cacheFilePath.c_str() );
38+
throw std::runtime_error("Telemetry sdk cache path not writable aborting");
39+
}
40+
}
41+
2942
m_logConfig["name"] = TELEMETRY_NAME;
3043
m_logConfig["version"] = TELEMETRY_VERSION;
3144
m_logConfig["config"]["host"] = "*";
3245
m_logConfig[CFG_BOOL_ENABLE_TRACE] = enableDebug;
3346
m_logConfig[CFG_INT_TRACE_LEVEL_MIN] = 0;
3447
m_logConfig[CFG_INT_MAX_TEARDOWN_TIME] = teardownTime.count();
35-
m_logConfig[CFG_STR_CACHE_FILE_PATH] = TELEMETRY_CACHE_FILE_NAME;
48+
m_logConfig[CFG_STR_CACHE_FILE_PATH] = cacheFilePath;
3649
m_logConfig[CFG_INT_CACHE_FILE_SIZE] = TELEMETRY_CACHE_FILE_SIZE;
3750
m_logConfig[CFG_INT_RAM_QUEUE_SIZE] = TELEMETRY_RAM_QUEUE_SIZE;
3851
m_logConfig[CFG_BOOL_ENABLE_DB_DROP_IF_FULL] = true;

src/common/telemetry/lib/Telemetry.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ class TelemetryManager
2929
static constexpr const int TELEMETRY_CACHE_FILE_SIZE = 10 * 1024 * 1024;
3030
static constexpr const int TELEMETRY_RAM_QUEUE_SIZE = 2 * 1024 * 1024;
3131

32-
explicit TelemetryManager(bool enableDebug = false, std::chrono::seconds teardownTime = CONFIG_DEFAULT_TEARDOWN_TIME, OsConfigLogHandle logHandle = nullptr);
32+
explicit TelemetryManager(std::string cacheFilePath, bool enableDebug = false, std::chrono::seconds teardownTime = CONFIG_DEFAULT_TEARDOWN_TIME,
33+
OsConfigLogHandle logHandle = nullptr);
3334

3435
~TelemetryManager() noexcept;
3536

src/common/telemetry/lib/tests/TelemetryTests.cpp

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4+
#include <cstdlib>
5+
46
#include <chrono>
57
#include <fstream>
68
#include <gtest/gtest.h>
@@ -13,6 +15,7 @@ class TelemetryTest : public ::testing::Test
1315
protected:
1416
std::string m_testDir;
1517
std::string m_testJsonFile;
18+
std::string m_telemetryCache;
1619

1720
void SetUp() override
1821
{
@@ -21,7 +24,15 @@ class TelemetryTest : public ::testing::Test
2124
ASSERT_NE(nullptr, mkdtemp(tmpDir));
2225
m_testDir = std::string(tmpDir);
2326
m_testJsonFile = m_testDir + "/test_telemetry.json";
24-
}
27+
28+
std::string telemetryCache = m_testDir + "/XXXXXX_telemetry_cache_db";
29+
std::vector<char> buffer(telemetryCache.begin(), telemetryCache.end());
30+
buffer.push_back('\0');
31+
32+
int fd = ::mkstemp(buffer.data());
33+
EXPECT_TRUE(0 < fd);
34+
m_telemetryCache.assign(buffer.data(), buffer.size());
35+
}
2536

2637
void TearDown() override
2738
{
@@ -50,15 +61,15 @@ class TelemetryTest : public ::testing::Test
5061
// Test processing a non-existent file
5162
TEST_F(TelemetryTest, ProcessNonExistentFile)
5263
{
53-
Telemetry::TelemetryManager telemetryManager(false, std::chrono::seconds(1));
64+
Telemetry::TelemetryManager telemetryManager(m_telemetryCache, false, std::chrono::seconds(1));
5465
EXPECT_FALSE(telemetryManager.ProcessJsonFile("/non/existent/file.json"));
5566
}
5667

5768
// Test processing an empty file
5869
TEST_F(TelemetryTest, ProcessEmptyFile)
5970
{
6071
ASSERT_TRUE(CreateTestJsonFile(""));
61-
Telemetry::TelemetryManager telemetryManager(false, std::chrono::seconds(1));
72+
Telemetry::TelemetryManager telemetryManager(m_telemetryCache, false, std::chrono::seconds(1));
6273
EXPECT_TRUE(telemetryManager.ProcessJsonFile(m_testJsonFile)); // Empty file should be processed successfully
6374
}
6475

@@ -68,15 +79,15 @@ TEST_F(TelemetryTest, ProcessValidJsonFile)
6879
// Create a test file with a valid event
6980
std::string validJson = R"({"EventName": "TestEvent", "TestParam": "value"})";
7081
ASSERT_TRUE(CreateTestJsonFile(validJson));
71-
Telemetry::TelemetryManager telemetryManager(false, std::chrono::seconds(1));
82+
Telemetry::TelemetryManager telemetryManager(m_telemetryCache, false, std::chrono::seconds(1));
7283
EXPECT_FALSE(telemetryManager.ProcessJsonFile(m_testJsonFile));
7384
}
7485

7586
// Test processing a file with invalid JSON
7687
TEST_F(TelemetryTest, ProcessInvalidJsonFile)
7788
{
7889
ASSERT_TRUE(CreateTestJsonFile("invalid json content"));
79-
Telemetry::TelemetryManager telemetryManager(false, std::chrono::seconds(1));
90+
Telemetry::TelemetryManager telemetryManager(m_telemetryCache, false, std::chrono::seconds(1));
8091
EXPECT_FALSE(telemetryManager.ProcessJsonFile(m_testJsonFile));
8192
}
8293

@@ -87,7 +98,7 @@ TEST_F(TelemetryTest, ProcessMixedJsonFile)
8798
invalid json line
8899
{"EventName": "AnotherEvent", "Param": "value2"})";
89100
ASSERT_TRUE(CreateTestJsonFile(mixedContent));
90-
Telemetry::TelemetryManager telemetryManager(false, std::chrono::seconds(1));
101+
Telemetry::TelemetryManager telemetryManager(m_telemetryCache, false, std::chrono::seconds(1));
91102
EXPECT_FALSE(telemetryManager.ProcessJsonFile(m_testJsonFile));
92103
}
93104

@@ -98,7 +109,7 @@ TEST_F(TelemetryTest, ProcessMultipleValidJsonLines)
98109
{"EventName": "Event2", "Param2": "value2"}
99110
{"EventName": "Event3", "Param3": "value3"})";
100111
ASSERT_TRUE(CreateTestJsonFile(multipleLines));
101-
Telemetry::TelemetryManager telemetryManager(false, std::chrono::seconds(1));
112+
Telemetry::TelemetryManager telemetryManager(m_telemetryCache, false, std::chrono::seconds(1));
102113
EXPECT_FALSE(telemetryManager.ProcessJsonFile(m_testJsonFile));
103114
}
104115

@@ -107,62 +118,62 @@ TEST_F(TelemetryTest, ProcessRuleCompleteEvent)
107118
{
108119
std::string realEvent = R"({"EventName":"RuleComplete","Timestamp":"2025-10-17 22:52:56+0000","ComponentName":"SecurityBaseline","ObjectName":"auditEnsureAuditdInstalled","ObjectResult":"0","Microseconds":"29","DistroName":"CentOS","CorrelationId":"","Version":"1.0.5.20251017-g03b36b7d"})";
109120
ASSERT_TRUE(CreateTestJsonFile(realEvent));
110-
Telemetry::TelemetryManager telemetryManager(false, std::chrono::seconds(1));
121+
Telemetry::TelemetryManager telemetryManager(m_telemetryCache, false, std::chrono::seconds(1));
111122
EXPECT_TRUE(telemetryManager.ProcessJsonFile(m_testJsonFile));
112123
}
113124

114125
TEST_F(TelemetryTest, ProcessRuleCompleteMissingComponentNameEvent)
115126
{
116127
std::string realEvent = R"({"EventName":"RuleComplete","Timestamp":"2025-10-17 22:52:56+0000","ComponentName":"SecurityBaseline","ObjectResult":"0","Microseconds":"29","DistroName":"CentOS","CorrelationId":"","Version":"1.0.5.20251017-g03b36b7d"})";
117128
ASSERT_TRUE(CreateTestJsonFile(realEvent));
118-
Telemetry::TelemetryManager telemetryManager(false, std::chrono::seconds(1));
129+
Telemetry::TelemetryManager telemetryManager(m_telemetryCache, false, std::chrono::seconds(1));
119130
EXPECT_FALSE(telemetryManager.ProcessJsonFile(m_testJsonFile));
120131
}
121132

122133
TEST_F(TelemetryTest, ProcessBaselineRunEvent)
123134
{
124135
std::string realEvent = R"({"EventName":"BaselineRun","Timestamp":"2025-10-17 22:52:56+0000","BaselineName":"Azure Security Baseline for Linux","Mode":"audit-only","DurationSeconds":"8.87","DistroName":"CentOS","CorrelationId":"","Version":"1.0.5.20251017-g03b36b7d"})";
125136
ASSERT_TRUE(CreateTestJsonFile(realEvent));
126-
Telemetry::TelemetryManager telemetryManager(false, std::chrono::seconds(1));
137+
Telemetry::TelemetryManager telemetryManager(m_telemetryCache, false, std::chrono::seconds(1));
127138
EXPECT_TRUE(telemetryManager.ProcessJsonFile(m_testJsonFile));
128139
}
129140

130141
TEST_F(TelemetryTest, ProcessBaselineRunMissingTimestampEvent)
131142
{
132143
std::string realEvent = R"({"EventName":"BaselineRun","BaselineName":"Azure Security Baseline for Linux","Mode":"audit-only","DurationSeconds":"8.87","DistroName":"CentOS","CorrelationId":"","Version":"1.0.5.20251017-g03b36b7d"})";
133144
ASSERT_TRUE(CreateTestJsonFile(realEvent));
134-
Telemetry::TelemetryManager telemetryManager(false, std::chrono::seconds(1));
145+
Telemetry::TelemetryManager telemetryManager(m_telemetryCache, false, std::chrono::seconds(1));
135146
EXPECT_FALSE(telemetryManager.ProcessJsonFile(m_testJsonFile));
136147
}
137148

138149
TEST_F(TelemetryTest, ProcessStatusTraceEvent)
139150
{
140151
std::string realEvent = R"({"EventName":"StatusTrace","Timestamp":"2025-10-17 22:52:56+0000","FileName":"/workspaces/azure-osconfig/src/common/asb/Asb.c","LineNumber":"1109","FunctionName":"AsbShutdown","RuleCodename":"auditEnsureSmbWithSambaIsDisabled","CallingFunctionName":"TestingStatusTrace","ResultCode":"0","ResultString":"OK","ScenarioName":"TestingScenario","Microseconds":"101807","DistroName":"CentOS","CorrelationId":"","Version":"1.0.5.20251017-g03b36b7d"})";
141152
ASSERT_TRUE(CreateTestJsonFile(realEvent));
142-
Telemetry::TelemetryManager telemetryManager(false, std::chrono::seconds(1));
153+
Telemetry::TelemetryManager telemetryManager(m_telemetryCache, false, std::chrono::seconds(1));
143154
EXPECT_TRUE(telemetryManager.ProcessJsonFile(m_testJsonFile));
144155
}
145156

146157
TEST_F(TelemetryTest, ProcessStatusTraceMissingScenarioNameEvent)
147158
{
148159
std::string realEvent = R"({"EventName":"StatusTrace","Timestamp":"2025-10-17 22:52:56+0000","FileName":"/workspaces/azure-osconfig/src/common/asb/Asb.c","LineNumber":"1109","FunctionName":"AsbShutdown","RuleCodename":"auditEnsureSmbWithSambaIsDisabled","CallingFunctionName":"TestingStatusTrace","ResultCode":"0","Microseconds":"101807","DistroName":"CentOS","CorrelationId":"","Version":"1.0.5.20251017-g03b36b7d"})";
149160
ASSERT_TRUE(CreateTestJsonFile(realEvent));
150-
Telemetry::TelemetryManager telemetryManager(false, std::chrono::seconds(1));
161+
Telemetry::TelemetryManager telemetryManager(m_telemetryCache, false, std::chrono::seconds(1));
151162
EXPECT_FALSE(telemetryManager.ProcessJsonFile(m_testJsonFile));
152163
}
153164

154165
TEST_F(TelemetryTest, ProcessCommandExecutedEvent)
155166
{
156167
std::string realEvent = R"({"EventName":"CommandExecuted","DistroName":"CentOS","Version":"1.3.0-preview123","CorrelationId":"{00000000-0000-0000-0000-000000000000}","CorrelationGroup":"TestGroup","Timestamp":"2025-10-17 22:52:56+0000","IsTestMode":true,"Subcommand":"get resource","Duration":1234.5678,"Success":true,"ErrorKind":"Resource","ErrorResourceName":"Test Resource","ErrorResourceType":"Microsoft.OSConfig/Test","ErrorLocation":"utils/test.rs:123","ErrorCode":1})";
157168
ASSERT_TRUE(CreateTestJsonFile(realEvent));
158-
Telemetry::TelemetryManager telemetryManager(false, std::chrono::seconds(1));
169+
Telemetry::TelemetryManager telemetryManager(m_telemetryCache, false, std::chrono::seconds(1));
159170
EXPECT_TRUE(telemetryManager.ProcessJsonFile(m_testJsonFile));
160171
}
161172

162173
TEST_F(TelemetryTest, ProcessCommandExecutedMissingSubcommandEvent)
163174
{
164175
std::string realEvent = R"({"EventName":"CommandExecuted","DistroName":"CentOS","Version":"1.3.0-preview123","CorrelationId":"{00000000-0000-0000-0000-000000000000}","CorrelationGroup":"TestGroup","Timestamp":"2025-10-17 22:52:56+0000","IsTestMode":true,"Duration":1234.5678,"Success":true,"ErrorKind":"Resource","ErrorResourceName":"Test Resource","ErrorResourceType":"Microsoft.OSConfig/Test","ErrorLocation":"utils/test.rs:123","ErrorCode":1})";
165176
ASSERT_TRUE(CreateTestJsonFile(realEvent));
166-
Telemetry::TelemetryManager telemetryManager(false, std::chrono::seconds(1));
177+
Telemetry::TelemetryManager telemetryManager(m_telemetryCache, false, std::chrono::seconds(1));
167178
EXPECT_FALSE(telemetryManager.ProcessJsonFile(m_testJsonFile));
168179
}

0 commit comments

Comments
 (0)