-
Notifications
You must be signed in to change notification settings - Fork 121
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add logTrace API for Kabuki to log instrumentation events through JS …
…h5vcc API (#2877) Add a ringbuffer to the watchdog to hold events emitted from logEvent() API. InstrumentationLog is thread-safe. LogTrace(snapshot of event log) is added to the violation json when violation is created. b/327680765 Change-Id: I73159740487d7e791e8a0238999b5b06f1e2ae47
- Loading branch information
Showing
11 changed files
with
385 additions
and
9 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
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,63 @@ | ||
// Copyright 2024 The Cobalt Authors. All Rights Reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#include "cobalt/watchdog/instrumentation_log.h" | ||
|
||
#include <string> | ||
#include <vector> | ||
|
||
namespace cobalt { | ||
namespace watchdog { | ||
|
||
bool InstrumentationLog::LogEvent(const std::string& event) { | ||
if (event.length() > kMaxEventLenBytes) { | ||
SB_DLOG(ERROR) << "[Watchdog] Log event exceeds max: " << kMaxEventLenBytes; | ||
return false; | ||
} | ||
|
||
starboard::ScopedLock scoped_lock(buffer_mutex_); | ||
buffer_.SaveToBuffer(event); | ||
|
||
return true; | ||
} | ||
|
||
std::vector<std::string> InstrumentationLog::GetLogTrace() { | ||
std::vector<std::string> traceEvents; | ||
|
||
starboard::ScopedLock scoped_lock(buffer_mutex_); | ||
for (auto it = buffer_.Begin(); it; ++it) { | ||
traceEvents.push_back(**it); | ||
} | ||
|
||
return traceEvents; | ||
} | ||
|
||
base::Value InstrumentationLog::GetLogTraceAsValue() { | ||
base::Value log_trace_value = base::Value(base::Value::Type::LIST); | ||
|
||
starboard::ScopedLock scoped_lock(buffer_mutex_); | ||
for (auto it = buffer_.Begin(); it; ++it) { | ||
log_trace_value.GetList().emplace_back(**it); | ||
} | ||
|
||
return log_trace_value; | ||
} | ||
|
||
void InstrumentationLog::ClearLog() { | ||
starboard::ScopedLock scoped_lock(buffer_mutex_); | ||
buffer_.Clear(); | ||
} | ||
|
||
} // namespace watchdog | ||
} // namespace cobalt |
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,59 @@ | ||
// Copyright 2024 The Cobalt Authors. All Rights Reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#ifndef COBALT_WATCHDOG_INSTRUMENTATION_LOG_H_ | ||
#define COBALT_WATCHDOG_INSTRUMENTATION_LOG_H_ | ||
|
||
#include <string> | ||
#include <vector> | ||
|
||
#include "base/containers/ring_buffer.h" | ||
#include "base/values.h" | ||
#include "starboard/common/mutex.h" | ||
|
||
namespace cobalt { | ||
namespace watchdog { | ||
|
||
constexpr int kBufferSize = 128; | ||
constexpr int kMaxEventLenBytes = 256; | ||
|
||
// Wrapper class on top of base::RingBuffer for tracking log events emitted | ||
// through logEvent() h5vcc API. There's an optimization: identical sequential | ||
// events added back to back are folded into single event. | ||
class InstrumentationLog { | ||
public: | ||
// Append a single event to the end of the buffer. | ||
bool LogEvent(const std::string& event); | ||
|
||
// Returns a snapshot of the ring buffer. | ||
// Vector of kBufferSize strings at max. | ||
std::vector<std::string> GetLogTrace(); | ||
|
||
// Same as GetLogTrace() but converted to base::Value for json serialization. | ||
base::Value GetLogTraceAsValue(); | ||
|
||
// Empty the ring buffer. | ||
void ClearLog(); | ||
|
||
private: | ||
base::RingBuffer<std::string, kBufferSize> buffer_; | ||
|
||
// Mutex to guard buffer operations. E.g. LogEvent() called from h5vcc API | ||
// handler and getLogTrace() called from watchdog monitoring thread. | ||
starboard::Mutex buffer_mutex_; | ||
}; | ||
|
||
} // namespace watchdog | ||
} // namespace cobalt | ||
#endif // COBALT_WATCHDOG_INSTRUMENTATION_LOG_H_ |
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,122 @@ | ||
// Copyright 2024 The Cobalt Authors. All Rights Reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#include "cobalt/watchdog//instrumentation_log.h" | ||
|
||
#include <set> | ||
#include <vector> | ||
|
||
#include "base/json/json_reader.h" | ||
#include "base/json/json_writer.h" | ||
#include "starboard/common/file.h" | ||
#include "testing/gtest/include/gtest/gtest.h" | ||
|
||
namespace cobalt { | ||
namespace watchdog { | ||
|
||
class InstrumentationLogTest : public testing::Test { | ||
protected: | ||
InstrumentationLog* instrumentation_log_; | ||
}; | ||
|
||
TEST_F(InstrumentationLogTest, CanCallLogEvent) { | ||
InstrumentationLog log; | ||
log.LogEvent("abc"); | ||
|
||
ASSERT_EQ(log.GetLogTrace().size(), 1); | ||
} | ||
|
||
TEST_F(InstrumentationLogTest, LogEventReturnsFalseOnMaxLenExceed) { | ||
InstrumentationLog log; | ||
|
||
std::string maxLenEvent(kMaxEventLenBytes, 'a'); | ||
ASSERT_TRUE(log.LogEvent(maxLenEvent)); | ||
|
||
std::string exceedingLenEvent(kMaxEventLenBytes + 1, 'a'); | ||
ASSERT_FALSE(log.LogEvent(exceedingLenEvent)); | ||
} | ||
|
||
TEST_F(InstrumentationLogTest, GetLogTraceReturnsEventsInOrder) { | ||
InstrumentationLog log; | ||
|
||
for (int i = 0; i < kBufferSize; i++) { | ||
log.LogEvent(std::to_string(i)); | ||
} | ||
|
||
log.LogEvent("1"); | ||
log.LogEvent("2"); | ||
log.LogEvent("3"); | ||
log.LogEvent("4"); | ||
log.LogEvent("5"); | ||
|
||
ASSERT_EQ(log.GetLogTrace().at(kBufferSize - 1 - 4), "1"); | ||
ASSERT_EQ(log.GetLogTrace().at(kBufferSize - 1 - 3), "2"); | ||
ASSERT_EQ(log.GetLogTrace().at(kBufferSize - 1 - 2), "3"); | ||
ASSERT_EQ(log.GetLogTrace().at(kBufferSize - 1 - 1), "4"); | ||
ASSERT_EQ(log.GetLogTrace().at(kBufferSize - 1), "5"); | ||
} | ||
|
||
TEST_F(InstrumentationLogTest, GetLogTraceCanReturnDuplicateEvents) { | ||
InstrumentationLog log; | ||
|
||
log.LogEvent("1"); | ||
log.LogEvent("1"); | ||
log.LogEvent("1"); | ||
|
||
ASSERT_EQ(log.GetLogTrace().at(0), "1"); | ||
ASSERT_EQ(log.GetLogTrace().at(1), "1"); | ||
ASSERT_EQ(log.GetLogTrace().at(2), "1"); | ||
} | ||
|
||
TEST_F(InstrumentationLogTest, CanGetEmptyTraceAsValue) { | ||
InstrumentationLog log; | ||
|
||
ASSERT_EQ(log.GetLogTraceAsValue().GetList().size(), 0); | ||
} | ||
|
||
TEST_F(InstrumentationLogTest, CanGetLogTraceAsValue) { | ||
InstrumentationLog log; | ||
|
||
log.LogEvent("1"); | ||
log.LogEvent("2"); | ||
log.LogEvent("3"); | ||
|
||
ASSERT_EQ(log.GetLogTraceAsValue().GetList().at(0).GetString(), "1"); | ||
ASSERT_EQ(log.GetLogTraceAsValue().GetList().at(1).GetString(), "2"); | ||
ASSERT_EQ(log.GetLogTraceAsValue().GetList().at(2).GetString(), "3"); | ||
} | ||
|
||
TEST_F(InstrumentationLogTest, CanClearLog) { | ||
InstrumentationLog log; | ||
|
||
log.LogEvent("1"); | ||
log.LogEvent("2"); | ||
log.LogEvent("3"); | ||
|
||
ASSERT_EQ(log.GetLogTrace().size(), 3); | ||
|
||
log.ClearLog(); | ||
ASSERT_EQ(log.GetLogTrace().size(), 0); | ||
} | ||
|
||
TEST_F(InstrumentationLogTest, CanClearEmptyLog) { | ||
InstrumentationLog log; | ||
ASSERT_EQ(log.GetLogTrace().size(), 0); | ||
|
||
log.ClearLog(); | ||
ASSERT_EQ(log.GetLogTrace().size(), 0); | ||
} | ||
|
||
} // namespace watchdog | ||
} // namespace cobalt |
Oops, something went wrong.