Skip to content

Commit

Permalink
feat: prom stream scrape and stream process (#1925)
Browse files Browse the repository at this point in the history
  • Loading branch information
catdogpandas authored Dec 30, 2024
1 parent 9800d9e commit 0544cfc
Show file tree
Hide file tree
Showing 19 changed files with 568 additions and 215 deletions.
2 changes: 1 addition & 1 deletion core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ set(SUB_DIRECTORIES_LIST
runner runner/sink/http
protobuf/sls protobuf/models
file_server file_server/event file_server/event_handler file_server/event_listener file_server/reader file_server/polling
prometheus prometheus/labels prometheus/schedulers prometheus/async
prometheus prometheus/labels prometheus/schedulers prometheus/async prometheus/component
ebpf ebpf/observer ebpf/security ebpf/handler
parser sls_control sdk
)
Expand Down
2 changes: 2 additions & 0 deletions core/models/PipelineEventGroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ enum class EventGroupMetaKey {
PROMETHEUS_SAMPLES_SCRAPED,
PROMETHEUS_SCRAPE_TIMESTAMP_MILLISEC,
PROMETHEUS_UP_STATE,
PROMETHEUS_STREAM_ID,
PROMETHEUS_STREAM_TOTAL,

SOURCE_ID
};
Expand Down
112 changes: 64 additions & 48 deletions core/plugin/processor/inner/ProcessorPromRelabelMetricNative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,12 @@ void ProcessorPromRelabelMetricNative::Process(PipelineEventGroup& metricGroup)
metricGroup.DelTag(k);
}

AddAutoMetrics(metricGroup);
if (metricGroup.HasMetadata(EventGroupMetaKey::PROMETHEUS_STREAM_TOTAL)) {
auto autoMetric = prom::AutoMetric();
UpdateAutoMetrics(metricGroup, autoMetric);
AddAutoMetrics(metricGroup, autoMetric);
}


// delete all tags
for (const auto& [k, v] : targetTags) {
Expand Down Expand Up @@ -138,78 +143,89 @@ vector<StringView> ProcessorPromRelabelMetricNative::GetToDeleteTargetLabels(con
return toDelete;
}

void ProcessorPromRelabelMetricNative::AddAutoMetrics(PipelineEventGroup& metricGroup) {
// if up is set, then add self monitor metrics
if (metricGroup.GetMetadata(EventGroupMetaKey::PROMETHEUS_UP_STATE).empty()) {
return;
void ProcessorPromRelabelMetricNative::UpdateAutoMetrics(const PipelineEventGroup& eGroup,
prom::AutoMetric& autoMetric) const {
if (eGroup.HasMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_DURATION)) {
autoMetric.mScrapeDurationSeconds
= StringTo<double>(eGroup.GetMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_DURATION).to_string());
}
if (eGroup.HasMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_RESPONSE_SIZE)) {
autoMetric.mScrapeResponseSizeBytes
= StringTo<uint64_t>(eGroup.GetMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_RESPONSE_SIZE).to_string());
}
autoMetric.mScrapeSamplesLimit = mScrapeConfigPtr->mSampleLimit;
if (eGroup.HasMetadata(EventGroupMetaKey::PROMETHEUS_SAMPLES_SCRAPED)) {
autoMetric.mScrapeSamplesScraped
= StringTo<uint64_t>(eGroup.GetMetadata(EventGroupMetaKey::PROMETHEUS_SAMPLES_SCRAPED).to_string());
}
autoMetric.mScrapeTimeoutSeconds = mScrapeConfigPtr->mScrapeTimeoutSeconds;

auto targetTags = metricGroup.GetTags();
if (eGroup.HasMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_STATE)) {
autoMetric.mScrapeState = eGroup.GetMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_STATE).to_string();
}

if (eGroup.HasMetadata(EventGroupMetaKey::PROMETHEUS_UP_STATE)) {
autoMetric.mUp = StringTo<bool>(eGroup.GetMetadata(EventGroupMetaKey::PROMETHEUS_UP_STATE).to_string());
}
}

void ProcessorPromRelabelMetricNative::AddAutoMetrics(PipelineEventGroup& eGroup,
const prom::AutoMetric& autoMetric) const {
auto targetTags = eGroup.GetTags();
if (!eGroup.HasMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_TIMESTAMP_MILLISEC)) {
LOG_ERROR(sLogger, ("scrape_timestamp_milliseconds is not set", ""));
return;
}

StringView scrapeTimestampMilliSecStr
= metricGroup.GetMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_TIMESTAMP_MILLISEC);
StringView scrapeTimestampMilliSecStr = eGroup.GetMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_TIMESTAMP_MILLISEC);
auto timestampMilliSec = StringTo<uint64_t>(scrapeTimestampMilliSecStr.to_string());
auto timestamp = timestampMilliSec / 1000;
auto nanoSec = timestampMilliSec % 1000 * 1000000;

uint64_t samplesPostMetricRelabel = metricGroup.GetEvents().size();

auto scrapeDurationSeconds
= StringTo<double>(metricGroup.GetMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_DURATION).to_string());

AddMetric(metricGroup, prometheus::SCRAPE_DURATION_SECONDS, scrapeDurationSeconds, timestamp, nanoSec, targetTags);

auto scrapeResponseSize
= StringTo<uint64_t>(metricGroup.GetMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_RESPONSE_SIZE).to_string());
AddMetric(metricGroup, prometheus::SCRAPE_RESPONSE_SIZE_BYTES, scrapeResponseSize, timestamp, nanoSec, targetTags);
AddMetric(
eGroup, prometheus::SCRAPE_DURATION_SECONDS, autoMetric.mScrapeDurationSeconds, timestamp, nanoSec, targetTags);

if (mScrapeConfigPtr->mSampleLimit > 0) {
AddMetric(metricGroup,
prometheus::SCRAPE_SAMPLES_LIMIT,
mScrapeConfigPtr->mSampleLimit,
timestamp,
nanoSec,
targetTags);
}

AddMetric(metricGroup,
prometheus::SCRAPE_SAMPLES_POST_METRIC_RELABELING,
samplesPostMetricRelabel,
AddMetric(eGroup,
prometheus::SCRAPE_RESPONSE_SIZE_BYTES,
autoMetric.mScrapeResponseSizeBytes,
timestamp,
nanoSec,
targetTags);

auto samplesScraped
= StringTo<uint64_t>(metricGroup.GetMetadata(EventGroupMetaKey::PROMETHEUS_SAMPLES_SCRAPED).to_string());
if (autoMetric.mScrapeSamplesLimit > 0) {
AddMetric(
eGroup, prometheus::SCRAPE_SAMPLES_LIMIT, autoMetric.mScrapeSamplesLimit, timestamp, nanoSec, targetTags);
}

AddMetric(metricGroup, prometheus::SCRAPE_SAMPLES_SCRAPED, samplesScraped, timestamp, nanoSec, targetTags);
// AddMetric(eGroup,
// prometheus::SCRAPE_SAMPLES_POST_METRIC_RELABELING,
// autoMetric.mPostRelabel,
// timestamp,
// nanoSec,
// targetTags);

AddMetric(metricGroup,
prometheus::SCRAPE_TIMEOUT_SECONDS,
mScrapeConfigPtr->mScrapeTimeoutSeconds,
timestamp,
nanoSec,
targetTags);
AddMetric(
eGroup, prometheus::SCRAPE_SAMPLES_SCRAPED, autoMetric.mScrapeSamplesScraped, timestamp, nanoSec, targetTags);

// up metric must be the last one
bool upState = StringTo<bool>(metricGroup.GetMetadata(EventGroupMetaKey::PROMETHEUS_UP_STATE).to_string());
AddMetric(
eGroup, prometheus::SCRAPE_TIMEOUT_SECONDS, autoMetric.mScrapeTimeoutSeconds, timestamp, nanoSec, targetTags);

if (metricGroup.HasMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_STATE)) {
auto scrapeState = metricGroup.GetMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_STATE);
AddMetric(metricGroup, prometheus::SCRAPE_STATE, 1.0 * upState, timestamp, nanoSec, targetTags);
auto& last = metricGroup.MutableEvents()[metricGroup.GetEvents().size() - 1];
last.Cast<MetricEvent>().SetTag(METRIC_LABEL_KEY_STATUS, scrapeState);
}
AddMetric(eGroup, prometheus::SCRAPE_STATE, 1.0 * autoMetric.mUp, timestamp, nanoSec, targetTags);
auto& last = eGroup.MutableEvents()[eGroup.GetEvents().size() - 1];
auto scrapeState = eGroup.GetMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_STATE);
last.Cast<MetricEvent>().SetTag(METRIC_LABEL_KEY_STATUS, scrapeState);

AddMetric(metricGroup, prometheus::UP, 1.0 * upState, timestamp, nanoSec, targetTags);
// up metric must be the last one
AddMetric(eGroup, prometheus::UP, 1.0 * autoMetric.mUp, timestamp, nanoSec, targetTags);
}

void ProcessorPromRelabelMetricNative::AddMetric(PipelineEventGroup& metricGroup,
const string& name,
double value,
time_t timestamp,
uint32_t nanoSec,
const GroupTags& targetTags) {
const GroupTags& targetTags) const {
auto* metricEvent = metricGroup.AddMetricEvent(true);
metricEvent->SetName(name);
metricEvent->SetValue<UntypedSingleValue>(value);
Expand Down
19 changes: 17 additions & 2 deletions core/plugin/processor/inner/ProcessorPromRelabelMetricNative.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@
#include "prometheus/schedulers/ScrapeConfig.h"

namespace logtail {

namespace prom {
struct AutoMetric {
double mScrapeDurationSeconds;
uint64_t mScrapeResponseSizeBytes;
uint64_t mScrapeSamplesLimit;
// uint64_t mPostRelabel;
uint64_t mScrapeSamplesScraped;
uint64_t mScrapeTimeoutSeconds;
std::string mScrapeState;
bool mUp;
};
} // namespace prom

class ProcessorPromRelabelMetricNative : public Processor {
public:
static const std::string sName;
Expand All @@ -39,13 +53,14 @@ class ProcessorPromRelabelMetricNative : public Processor {
bool ProcessEvent(PipelineEventPtr& e, const GroupTags& targetTags, const std::vector<StringView>& toDelete);
std::vector<StringView> GetToDeleteTargetLabels(const GroupTags& targetTags) const;

void AddAutoMetrics(PipelineEventGroup& metricGroup);
void AddAutoMetrics(PipelineEventGroup& eGroup, const prom::AutoMetric& autoMetric) const;
void UpdateAutoMetrics(const PipelineEventGroup& eGroup, prom::AutoMetric& autoMetric) const;
void AddMetric(PipelineEventGroup& metricGroup,
const std::string& name,
double value,
time_t timestamp,
uint32_t nanoSec,
const GroupTags& targetTags);
const GroupTags& targetTags) const;

std::unique_ptr<ScrapeConfig> mScrapeConfigPtr;
std::string mLoongCollectorScraper;
Expand Down
1 change: 0 additions & 1 deletion core/prometheus/async/PromHttpRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include <string>

#include "common/http/HttpRequest.h"
#include "models/PipelineEventGroup.h"
#include "prometheus/async/PromFuture.h"

namespace logtail {
Expand Down
132 changes: 132 additions & 0 deletions core/prometheus/component/StreamScraper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#include "prometheus/component/StreamScraper.h"

#include <cstddef>
#include <memory>
#include <string>
#include <utility>

#include "Flags.h"
#include "Labels.h"
#include "common/StringTools.h"
#include "models/PipelineEventGroup.h"
#include "pipeline/queue/ProcessQueueItem.h"
#include "pipeline/queue/ProcessQueueManager.h"
#include "prometheus/Utils.h"

DEFINE_FLAG_INT64(prom_stream_bytes_size, "stream bytes size", 1024 * 1024);

DEFINE_FLAG_BOOL(enable_prom_stream_scrape, "enable prom stream scrape", true);

using namespace std;

namespace logtail::prom {
size_t StreamScraper::MetricWriteCallback(char* buffer, size_t size, size_t nmemb, void* data) {
uint64_t sizes = size * nmemb;

if (buffer == nullptr || data == nullptr) {
return 0;
}

auto* body = static_cast<StreamScraper*>(data);

size_t begin = 0;
for (size_t end = begin; end < sizes; ++end) {
if (buffer[end] == '\n') {
if (begin == 0 && !body->mCache.empty()) {
body->mCache.append(buffer, end);
body->AddEvent(body->mCache.data(), body->mCache.size());
body->mCache.clear();
} else if (begin != end) {
body->AddEvent(buffer + begin, end - begin);
}
begin = end + 1;
}
}

if (begin < sizes) {
body->mCache.append(buffer + begin, sizes - begin);
}
body->mRawSize += sizes;
body->mCurrStreamSize += sizes;

if (BOOL_FLAG(enable_prom_stream_scrape) && body->mCurrStreamSize >= (size_t)INT64_FLAG(prom_stream_bytes_size)) {
body->mStreamIndex++;
body->SendMetrics();
}

return sizes;
}

void StreamScraper::AddEvent(const char* line, size_t len) {
if (IsValidMetric(StringView(line, len))) {
auto* e = mEventGroup.AddRawEvent(true, mEventPool);
auto sb = mEventGroup.GetSourceBuffer()->CopyString(line, len);
e->SetContentNoCopy(sb);
mScrapeSamplesScraped++;
}
}

void StreamScraper::FlushCache() {
if (!mCache.empty()) {
AddEvent(mCache.data(), mCache.size());
mCache.clear();
}
}

void StreamScraper::SetTargetLabels(PipelineEventGroup& eGroup) const {
mTargetLabels.Range([&eGroup](const std::string& key, const std::string& value) { eGroup.SetTag(key, value); });
}

void StreamScraper::PushEventGroup(PipelineEventGroup&& eGroup) const {
auto item = make_unique<ProcessQueueItem>(std::move(eGroup), mInputIndex);
#ifdef APSARA_UNIT_TEST_MAIN
mItem.emplace_back(std::move(item));
return;
#endif
while (true) {
if (ProcessQueueManager::GetInstance()->PushQueue(mQueueKey, std::move(item)) == 0) {
break;
}
usleep(10 * 1000);
}
}

void StreamScraper::SendMetrics() {
mEventGroup.SetMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_TIMESTAMP_MILLISEC,
ToString(mScrapeTimestampMilliSec));
mEventGroup.SetMetadata(EventGroupMetaKey::PROMETHEUS_STREAM_ID, GetId() + ToString(mScrapeTimestampMilliSec));

SetTargetLabels(mEventGroup);
PushEventGroup(std::move(mEventGroup));
mEventGroup = PipelineEventGroup(std::make_shared<SourceBuffer>());
mCurrStreamSize = 0;
}

void StreamScraper::Reset() {
mEventGroup = PipelineEventGroup(std::make_shared<SourceBuffer>());
mRawSize = 0;
mCurrStreamSize = 0;
mCache.clear();
mStreamIndex = 0;
mScrapeSamplesScraped = 0;
}

void StreamScraper::SetAutoMetricMeta(double scrapeDurationSeconds, bool upState, const string& scrapeState) {
mEventGroup.SetMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_STATE, scrapeState);
mEventGroup.SetMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_TIMESTAMP_MILLISEC,
ToString(mScrapeTimestampMilliSec));
mEventGroup.SetMetadata(EventGroupMetaKey::PROMETHEUS_SAMPLES_SCRAPED, ToString(mScrapeSamplesScraped));
mEventGroup.SetMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_DURATION, ToString(scrapeDurationSeconds));
mEventGroup.SetMetadata(EventGroupMetaKey::PROMETHEUS_SCRAPE_RESPONSE_SIZE, ToString(mRawSize));
mEventGroup.SetMetadata(EventGroupMetaKey::PROMETHEUS_UP_STATE, ToString(upState));
mEventGroup.SetMetadata(EventGroupMetaKey::PROMETHEUS_STREAM_ID, GetId() + ToString(mScrapeTimestampMilliSec));
mEventGroup.SetMetadata(EventGroupMetaKey::PROMETHEUS_STREAM_TOTAL, ToString(mStreamIndex));
}
std::string StreamScraper::GetId() {
return mHash;
}
void StreamScraper::SetScrapeTime(std::chrono::system_clock::time_point scrapeTime) {
mScrapeTimestampMilliSec
= std::chrono::duration_cast<std::chrono::milliseconds>(scrapeTime.time_since_epoch()).count();
}
} // namespace logtail::prom
Loading

0 comments on commit 0544cfc

Please sign in to comment.