Skip to content

Commit

Permalink
render endpoint impl
Browse files Browse the repository at this point in the history
  • Loading branch information
akvlad committed Aug 5, 2024
1 parent 505b6b5 commit decb26c
Show file tree
Hide file tree
Showing 5 changed files with 337 additions and 194 deletions.
3 changes: 2 additions & 1 deletion pyroscope/flamebearer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ type units = string;
export interface Flamebearer {
version: number,
flamebearerProfileV1: flamebearerProfileV1
telemetry: {[key: string]: any}
telemetry?: {[key: string]: any}
}

export interface flamebearerProfileV1 {
flamebearer: flamebearerV1,
metadata: flamebearerMetadataV1,
timeline: flamebearerTimelineV1,
groups: {[key: string]: flamebearerTimelineV1}
heatmap: heatmap,
leftTicks: string,
rightTicks: string,
Expand Down
138 changes: 10 additions & 128 deletions pyroscope/pyroscope.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@ const { QrynBadRequest } = require('../lib/handlers/errors')
const { clusterName } = require('../common')
const logger = require('../lib/logger')
const jsonParsers = require('./json_parsers')
const { parser, wrapResponse, parseTypeId, serviceNameSelectorQuery, labelSelectorQuery } = require('./shared')
const HISTORY_TIMESPAN = 1000 * 60 * 60 * 24 * 7
const {
parser,
wrapResponse,
parseTypeId,
serviceNameSelectorQuery,
labelSelectorQuery,
HISTORY_TIMESPAN
} = require('./shared')
const settings = require('./settings')
const { mergeStackTraces } = require('./merge_stack_traces')
const { selectSeriesImpl } = require('./select_series')
const render = require('./render')

const profileTypesHandler = async (req, res) => {
Expand Down Expand Up @@ -103,138 +110,13 @@ const selectMergeStacktracesV2 = async (req, res) => {
}

const selectSeries = async (req, res) => {
const _req = req.body
const fromTimeSec = Math.floor(req.getStart && req.getStart()
? parseInt(req.getStart()) / 1000
: Date.now() / 1000 - HISTORY_TIMESPAN)
const toTimeSec = Math.floor(req.getEnd && req.getEnd()
? parseInt(req.getEnd()) / 1000
: Date.now() / 1000)
let typeID = _req.getProfileTypeid && _req.getProfileTypeid()
if (!typeID) {
throw new QrynBadRequest('No type provided')
}
typeID = parseTypeId(typeID)
if (!typeID) {
throw new QrynBadRequest('Invalid type provided')
}
const dist = clusterName ? '_dist' : ''
const sampleTypeId = typeID.sampleType + ':' + typeID.sampleUnit
const labelSelector = _req.getLabelSelector && _req.getLabelSelector()
let groupBy = _req.getGroupByList && _req.getGroupByList()
groupBy = groupBy && groupBy.length ? groupBy : null
const step = _req.getStep && parseInt(_req.getStep())
if (!step || isNaN(step)) {
throw new QrynBadRequest('No step provided')
}
const aggregation = _req.getAggregation && _req.getAggregation()

const typeIdSelector = Sql.Eq(
'type_id',
Sql.val(`${typeID.type}:${typeID.periodType}:${typeID.periodUnit}`))
const serviceNameSelector = serviceNameSelectorQuery(labelSelector)

const idxReq = (new Sql.Select())
.select(new Sql.Raw('fingerprint'))
.from(`${DATABASE_NAME()}.profiles_series_gin`)
.where(
Sql.And(
typeIdSelector,
serviceNameSelector,
Sql.Gte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(fromTimeSec)}))`)),
Sql.Lte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(toTimeSec)}))`)),
Sql.Eq(new Sql.Raw(
`has(sample_types_units, (${Sql.quoteVal(typeID.sampleType)}, ${Sql.quoteVal(typeID.sampleUnit)}))`),
1)
)
)
labelSelectorQuery(idxReq, labelSelector)

const withIdxReq = (new Sql.With('idx', idxReq, !!clusterName))

let tagsReq = 'arraySort(p.tags)'
if (groupBy) {
tagsReq = `arraySort(arrayFilter(x -> x.1 in (${groupBy.map(g => Sql.quoteVal(g)).join(',')}), p.tags))`
}

const labelsReq = (new Sql.Select()).with(withIdxReq).select(
'fingerprint',
[new Sql.Raw(tagsReq), 'tags'],
[groupBy ? new Sql.Raw('cityHash64(tags)') : 'fingerprint', 'new_fingerprint']
).distinct(true).from([`${DATABASE_NAME()}.profiles_series`, 'p'])
.where(Sql.And(
new Sql.In('fingerprint', 'IN', new Sql.WithReference(withIdxReq)),
Sql.Gte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(fromTimeSec)}))`)),
Sql.Lte('date', new Sql.Raw(`toDate(FROM_UNIXTIME(${Math.floor(toTimeSec)}))`)),
typeIdSelector,
serviceNameSelector
))

const withLabelsReq = new Sql.With('labels', labelsReq, !!clusterName)

let valueCol = new Sql.Raw(
`sum(toFloat64(arrayFirst(x -> x.1 == ${Sql.quoteVal(sampleTypeId)}, p.values_agg).2))`)
if (aggregation === types.TimeSeriesAggregationType.TIME_SERIES_AGGREGATION_TYPE_AVERAGE) {
valueCol = new Sql.Raw(
`sum(toFloat64(arrayFirst(x -> x.1 == ${Sql.quoteVal(sampleTypeId)}).2, p.values_agg)) / ` +
`sum(toFloat64(arrayFirst(x -> x.1 == ${Sql.quoteVal(sampleTypeId)}).3, p.values_agg))`
)
}

const mainReq = (new Sql.Select()).with(withIdxReq, withLabelsReq).select(
[new Sql.Raw(`intDiv(p.timestamp_ns, 1000000000 * ${step}) * ${step} * 1000`), 'timestamp_ms'],
[new Sql.Raw('labels.new_fingerprint'), 'fingerprint'],
[new Sql.Raw('min(labels.tags)'), 'labels'],
[valueCol, 'value']
).from([`${DATABASE_NAME()}.profiles${dist}`, 'p']).join(
[new Sql.WithReference(withLabelsReq), 'labels'],
'ANY LEFT',
Sql.Eq(new Sql.Raw('p.fingerprint'), new Sql.Raw('labels.fingerprint'))
).where(
Sql.And(
new Sql.In('p.fingerprint', 'IN', new Sql.WithReference(withIdxReq)),
Sql.Gte('p.timestamp_ns', new Sql.Raw(`${fromTimeSec}000000000`)),
Sql.Lt('p.timestamp_ns', new Sql.Raw(`${toTimeSec}000000000`)),
typeIdSelector,
serviceNameSelector
)
).groupBy('timestamp_ns', 'fingerprint')
.orderBy(['fingerprint', 'ASC'], ['timestamp_ns', 'ASC'])
const strMainReq = mainReq.toString()
const chRes = await clickhouse
.rawRequest(strMainReq + ' FORMAT JSON', null, DATABASE_NAME())

let lastFingerprint = null
const seriesList = []
let lastSeries = null
let lastPoints = []
for (let i = 0; i < chRes.data.data.length; i++) {
const e = chRes.data.data[i]
if (lastFingerprint !== e.fingerprint) {
lastFingerprint = e.fingerprint
lastSeries && lastSeries.setPointsList(lastPoints)
lastSeries && seriesList.push(lastSeries)
lastPoints = []
lastSeries = new types.Series()
lastSeries.setLabelsList(e.labels.map(l => {
const lp = new types.LabelPair()
lp.setName(l[0])
lp.setValue(l[1])
return lp
}))
}

const p = new types.Point()
p.setValue(e.value)
p.setTimestamp(e.timestamp_ms)
lastPoints.push(p)
}
lastSeries && lastSeries.setPointsList(lastPoints)
lastSeries && seriesList.push(lastSeries)

const resp = new messages.SelectSeriesResponse()
resp.setSeriesList(seriesList)
return resp
return selectSeriesImpl(fromTimeSec, toTimeSec, req.body)
}

const selectMergeProfile = async (req, res) => {
Expand Down
Loading

0 comments on commit decb26c

Please sign in to comment.