Skip to content
This repository has been archived by the owner on Feb 5, 2025. It is now read-only.

Add Support for Logging to JSON (beta feature) #1112

Merged
merged 8 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add support for logging to JSON.
  • Loading branch information
pmarkowsky authored and Pete Markowsky committed Jun 21, 2023
commit 10422a333042ca0d027fd47ac8f0988be4e58095
1 change: 1 addition & 0 deletions Source/common/SNTCommonEnums.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ typedef NS_ENUM(NSInteger, SNTEventLogType) {
SNTEventLogTypeSyslog,
SNTEventLogTypeFilelog,
SNTEventLogTypeProtobuf,
SNTEventLogTypeJSON,
SNTEventLogTypeNull,
};

Expand Down
2 changes: 2 additions & 0 deletions Source/common/SNTConfigurator.m
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,8 @@ - (SNTEventLogType)eventLogType {
return SNTEventLogTypeSyslog;
} else if ([logType isEqualToString:@"null"]) {
return SNTEventLogTypeNull;
} else if ([logType isEqualToString:@"json"]) {
return SNTEventLogTypeFilelog;
} else if ([logType isEqualToString:@"file"]) {
return SNTEventLogTypeFilelog;
} else {
Expand Down
5 changes: 5 additions & 0 deletions Source/santad/Logs/EndpointSecurity/Logger.mm
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
Protobuf::Create(esapi, std::move(decision_cache)),
Spool::Create([spool_log_path UTF8String], spool_dir_size_threshold,
spool_file_size_threshold, spool_flush_timeout_ms));
case SNTEventLogTypeJSON:
return std::make_unique<Logger>(
Protobuf::Create(esapi, std::move(decision_cache), true),
File::Create(event_log_path, kFlushBufferTimeoutMS, kBufferBatchSizeBytes,
kMaxExpectedWriteSizeBytes));
default: LOGE(@"Invalid log type: %ld", log_type); return nullptr;
}
}
Expand Down
5 changes: 5 additions & 0 deletions Source/santad/Logs/EndpointSecurity/LoggerTest.mm
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ LoggerPeer logger(
@"/tmp/spool", 1, 1, 1));
XCTAssertNotEqual(nullptr, std::dynamic_pointer_cast<Protobuf>(logger.Serializer()));
XCTAssertNotEqual(nullptr, std::dynamic_pointer_cast<Spool>(logger.Writer()));

logger = LoggerPeer(Logger::Create(mockESApi, SNTEventLogTypeJSON, nil, @"/tmp/temppy",
@"/tmp/spool", 1, 1, 1));
XCTAssertNotEqual(nullptr, std::dynamic_pointer_cast<Protobuf>(logger.Serializer()));
XCTAssertNotEqual(nullptr, std::dynamic_pointer_cast<File>(logger.Writer()));
}

- (void)testLog {
Expand Down
7 changes: 5 additions & 2 deletions Source/santad/Logs/EndpointSecurity/Serializers/Protobuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ class Protobuf : public Serializer {
public:
static std::shared_ptr<Protobuf> Create(
std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi,
SNTDecisionCache *decision_cache);
SNTDecisionCache *decision_cache, bool json = false);

Protobuf(
std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi,
SNTDecisionCache *decision_cache);
SNTDecisionCache *decision_cache, bool json = false);

std::vector<uint8_t> SerializeMessage(
const santa::santad::event_providers::endpoint_security::EnrichedClose &) override;
Expand Down Expand Up @@ -87,6 +87,9 @@ class Protobuf : public Serializer {
std::vector<uint8_t> FinalizeProto(::santa::pb::v1::SantaMessage *santa_msg);

std::shared_ptr<santa::santad::event_providers::endpoint_security::EndpointSecurityAPI> esapi_;
// Toggle for transforming protobuf output to its JSON form.
// See https://protobuf.dev/programming-guides/proto3/#json
bool json_;
};

} // namespace santa::santad::logs::endpoint_security::serializers
Expand Down
30 changes: 26 additions & 4 deletions Source/santad/Logs/EndpointSecurity/Serializers/Protobuf.mm
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@

using google::protobuf::Arena;
using google::protobuf::Timestamp;
using google::protobuf::util::JsonPrintOptions;
using google::protobuf::util::MessageToJsonString;

using santa::common::NSStringToUTF8StringView;
using santa::santad::event_providers::endpoint_security::EndpointSecurityAPI;
Expand Down Expand Up @@ -66,12 +68,12 @@
namespace santa::santad::logs::endpoint_security::serializers {

std::shared_ptr<Protobuf> Protobuf::Create(std::shared_ptr<EndpointSecurityAPI> esapi,
SNTDecisionCache *decision_cache) {
return std::make_shared<Protobuf>(esapi, std::move(decision_cache));
SNTDecisionCache *decision_cache, bool json) {
return std::make_shared<Protobuf>(esapi, std::move(decision_cache), json);
}

Protobuf::Protobuf(std::shared_ptr<EndpointSecurityAPI> esapi, SNTDecisionCache *decision_cache)
: Serializer(std::move(decision_cache)), esapi_(esapi) {}
Protobuf::Protobuf(std::shared_ptr<EndpointSecurityAPI> esapi, SNTDecisionCache *decision_cache, bool json)
: Serializer(std::move(decision_cache)), esapi_(esapi), json_(json) {}

static inline void EncodeTimestamp(Timestamp *timestamp, struct timespec ts) {
timestamp->set_seconds(ts.tv_sec);
Expand Down Expand Up @@ -387,6 +389,26 @@ static inline void EncodeCertificateInfo(::pbv1::CertificateInfo *pb_cert_info,
}

std::vector<uint8_t> Protobuf::FinalizeProto(::pbv1::SantaMessage *santa_msg) {
if (this->_) {
//TODO: Profile this. It's probably not the most efficient way to do this.
JsonPrintOptions options;
options.always_print_enums_as_ints = false;
options.always_print_primitive_fields = true;
options.preserve_proto_field_names = true;
std::string json;

google::protobuf::util::Status status = MessageToJsonString(*santa_msg, &json, options);

if (!status.ok()) {
LOG(ERROR) << "Failed to convert protobuf to JSON: " << status.error_message();
}

std::vector<uint8_t> vec(json.begin(), json.end());
// Add a newline to the end of the JSON row.
vec.push_back('\n');
return vec;
}

std::vector<uint8_t> vec(santa_msg->ByteSizeLong());
santa_msg->SerializeWithCachedSizesToArray(vec.data());
return vec;
Expand Down
3 changes: 2 additions & 1 deletion docs/deployment/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ also known as mobileconfig files, which are in an Apple-specific XML format.
| MachineOwnerKey | String | The key to use on MachineOwnerPlist. |
| MachineIDPlist | String | The path to a plist that contains the MachineOwnerKey / value pair. |
| MachineIDKey | String | The key to use on MachineIDPlist. |
| EventLogType | String | Defines how event logs are stored. Options are 1) syslog: Sent to ASL or ULS (if built with the 10.12 SDK or later). 2) filelog: Sent to a file on disk. Use EventLogPath to specify a path. 3) protobuf (BETA): Sent to file on disk using a maildir-like format. 4) null: Don't output any event logs. Defaults to filelog. |
| EventLogType | String | Defines how event logs are stored. Options are 1) syslog: Sent to ASL or ULS (if built with the 10.12 SDK or later). 2) filelog: Sent to a file on disk. Use EventLogPath to specify a path. 3) protobuf (BETA): Sent to file on disk using a maildir-like format. 4) json: Same as file but output is one JSON object per line 5) null: Don't output any event logs. Defaults to filelog. |
| EventLogPath | String | If EventLogType is set to filelog or json, EventLogPath will provide the path to save logs. Defaults to /var/db/santa/santa.log. If you change this value ensure you also update com.google.santa.newsyslog.conf with the new path. |
| EventLogPath | String | If EventLogType is set to filelog, EventLogPath will provide the path to save logs. Defaults to /var/db/santa/santa.log. If you change this value ensure you also update com.google.santa.newsyslog.conf with the new path. |
| SpoolDirectory | String | If EventLogType is set to protobuf, SpoolDirectory will provide the the base directory used to save files according to a maildir-like format. Defaults to /var/db/santa/spool. |
| SpoolDirectoryFileSizeThresholdKB | Integer | If EventLogType is set to protobuf, SpoolDirectoryFileSizeThresholdKB defines the per-file size limit for files stored in the spool directory. Events are buffered in memory until this threshold would be exceeded (or SpoolDirectoryEventMaxFlushTimeSec is exceeded). Defaults to 100. |
Expand Down