prod/native/libphpbridge/code/OtlpExporter/LogsConverter.h (100 lines of code) (raw):
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you 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.
*/
#pragma once
#include "opentelemetry/proto/collector/logs/v1/logs_service.pb.h"
#include "opentelemetry/proto/logs/v1/logs.pb.h"
#include "opentelemetry/proto/common/v1/common.pb.h"
#include "opentelemetry/proto/resource/v1/resource.pb.h"
#include "AutoZval.h"
#include "AttributesConverter.h"
#include "ConverterHelpers.h"
#include <string>
#include <string_view>
#include <unordered_map>
namespace elasticapm::php {
using namespace std::string_view_literals;
class LogsConverter {
public:
std::string getStringSerialized(AutoZval const &batch) {
return convert(batch).SerializeAsString();
}
private:
opentelemetry::proto::collector::logs::v1::ExportLogsServiceRequest convert(AutoZval const &logs) {
opentelemetry::proto::collector::logs::v1::ExportLogsServiceRequest request;
std::unordered_map<std::string, opentelemetry::proto::logs::v1::ResourceLogs *> resourceLogsMap;
std::unordered_map<std::string, opentelemetry::proto::logs::v1::ScopeLogs *> scopeLogsMap;
if (!logs.isArray()) {
throw std::runtime_error("Invalid iterable passed to LogsConverter");
}
for (auto const &log : logs) {
auto resourceInfo = log.callMethod("getResource"sv);
auto instrumentationScope = log.callMethod("getInstrumentationScope"sv);
std::string resourceId = ConverterHelpers::getResourceId(resourceInfo);
std::string scopeId = ConverterHelpers::getScopeId(instrumentationScope);
opentelemetry::proto::logs::v1::ResourceLogs *resourceLogs;
if (resourceLogsMap.count(resourceId) == 0) {
resourceLogs = request.add_resource_logs();
convertResourceLogs(resourceInfo, resourceLogs);
resourceLogsMap[resourceId] = resourceLogs;
} else {
resourceLogs = resourceLogsMap[resourceId];
}
opentelemetry::proto::logs::v1::ScopeLogs *scopeLogs;
std::string compositeKey = resourceId + "|" + scopeId;
if (scopeLogsMap.count(compositeKey) == 0) {
scopeLogs = resourceLogs->add_scope_logs();
convertInstrumentationScope(instrumentationScope, scopeLogs);
scopeLogsMap[compositeKey] = scopeLogs;
} else {
scopeLogs = scopeLogsMap[compositeKey];
}
convertLogRecord(log, scopeLogs->add_log_records());
}
return request;
}
void convertResourceLogs(AutoZval &resourceInfo, opentelemetry::proto::logs::v1::ResourceLogs *out) {
auto attributes = resourceInfo.callMethod("getAttributes"sv);
auto resource = out->mutable_resource();
AttributesConverter::convertAttributes(attributes, resource->mutable_attributes());
resource->set_dropped_attributes_count(attributes.callMethod("getDroppedAttributesCount"sv).getLong());
}
void convertInstrumentationScope(AutoZval &scopeInfo, opentelemetry::proto::logs::v1::ScopeLogs *out) {
auto scope = out->mutable_scope();
scope->set_name(scopeInfo.callMethod("getName"sv).getStringView());
if (auto version = scopeInfo.callMethod("getVersion"sv); version.isString()) {
scope->set_version(version.getStringView());
}
auto attributes = scopeInfo.callMethod("getAttributes"sv);
AttributesConverter::convertAttributes(attributes, scope->mutable_attributes());
scope->set_dropped_attributes_count(attributes.callMethod("getDroppedAttributesCount"sv).getLong());
if (auto schemaUrl = scopeInfo.callMethod("getSchemaUrl"sv); schemaUrl.isString()) {
out->set_schema_url(schemaUrl.getStringView());
}
}
void convertLogRecord(AutoZval const &log, opentelemetry::proto::logs::v1::LogRecord *out) {
using namespace std::string_view_literals;
auto body = log.callMethod("getBody"sv);
if (!body.isNull() && !body.isUndef()) {
auto value = AttributesConverter::convertAnyValue(body);
*out->mutable_body() = std::move(value);
}
out->set_time_unix_nano(log.callMethod("getTimestamp"sv).getOptLong().value_or(0));
out->set_observed_time_unix_nano(log.callMethod("getObservedTimestamp"sv).getOptLong().value_or(0));
auto spanContext = log.callMethod("getSpanContext"sv);
if (!spanContext.isNull() && spanContext.callMethod("isValid"sv).getBoolean()) {
out->set_trace_id(spanContext.callMethod("getTraceIdBinary"sv).getStringView());
out->set_span_id(spanContext.callMethod("getSpanIdBinary"sv).getStringView());
out->set_flags(spanContext.callMethod("getTraceFlags"sv).getLong());
}
auto severityNumber = log.callMethod("getSeverityNumber"sv);
if (severityNumber.isLong()) {
out->set_severity_number(static_cast<opentelemetry::proto::logs::v1::SeverityNumber>(severityNumber.getLong()));
}
auto severityText = log.callMethod("getSeverityText"sv);
if (severityText.isString()) {
out->set_severity_text(severityText.getStringView());
}
auto attributes = log.callMethod("getAttributes"sv);
AttributesConverter::convertAttributes(attributes, out->mutable_attributes());
out->set_dropped_attributes_count(attributes.callMethod("getDroppedAttributesCount"sv).getLong());
}
};
} // namespace elasticapm::php