Skip to content

Commit

Permalink
test: add jaeger docker image with HANA trace information (#1008)
Browse files Browse the repository at this point in the history
  • Loading branch information
BobdenOs authored Feb 5, 2025
1 parent 4368acb commit 1df2ebc
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 27 deletions.
25 changes: 12 additions & 13 deletions hana/lib/drivers/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class HANADriver {
* @returns {import('@cap-js/db-service/lib/SQLService').PreparedStatement}
*/
async prepare(sql) {
const prep = prom(
const prep = module.exports.prom(
this._native,
'prepare',
)(sql).then(stmt => {
Expand All @@ -29,22 +29,22 @@ class HANADriver {
run: async params => {
const { values, streams } = this._extractStreams(params)
const stmt = await prep
let changes = await prom(stmt, 'exec')(values)
let changes = await module.exports.prom(stmt, 'exec')(values)
await this._sendStreams(stmt, streams)
return { changes }
},
runBatch: async params => {
const stmt = await prep
const changes = await prom(stmt, 'exec')(params)
const changes = await module.exports.prom(stmt, 'exec')(params)
return { changes: !Array.isArray(changes) ? changes : changes.reduce((l, c) => l + c, 0) }
},
get: async params => {
const stmt = await prep
return (await prom(stmt, 'exec')(params))[0]
return (await module.exports.prom(stmt, 'exec')(params))[0]
},
all: async params => {
const stmt = await prep
return prom(stmt, 'exec')(params)
return module.exports.prom(stmt, 'exec')(params)
},
drop: async () => {
const stmt = await prep
Expand Down Expand Up @@ -85,12 +85,11 @@ class HANADriver {
*/
async exec(sql) {
await this.connected
return prom(this._native, 'exec')(sql)
return module.exports.prom(this._native, 'exec')(sql)
}

set(variables) {
variables
throw new Error('Implementation missing "set"')
this._native.set(variables)
}

/**
Expand All @@ -105,25 +104,25 @@ class HANADriver {
*/
async commit() {
await this.connected
return prom(this._native, 'commit')()
return module.exports.prom(this._native, 'commit')()
}

/**
* Rolls back the current transaction
*/
async rollback() {
await this.connected
return prom(this._native, 'rollback')()
return module.exports.prom(this._native, 'rollback')()
}

/**
* Connects the driver using the provided credentials
* @returns {Promise<any>}
*/
async connect() {
this.connected = prom(this._native, 'connect')(this._creds)
this.connected = module.exports.prom(this._native, 'connect')(this._creds)
return this.connected.then(async () => {
const version = await prom(this._native, 'exec')('SELECT VERSION FROM "SYS"."M_DATABASE"')
const version = await module.exports.prom(this._native, 'exec')('SELECT VERSION FROM "SYS"."M_DATABASE"')
const split = version[0].VERSION.split('.')
this.server = {
major: split[0],
Expand All @@ -141,7 +140,7 @@ class HANADriver {
if (this.connected) {
await this.connected
this.connected = false
return prom(this._native, 'disconnect')()
return module.exports.prom(this._native, 'disconnect')()
}
}

Expand Down
11 changes: 5 additions & 6 deletions hana/lib/drivers/hana-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,12 @@ class HANAClientDriver extends driver {
super(creds)
this._native = hdb.createConnection(creds)
this._native = wrap_client(this._native, creds, creds.tenant)
this._native.setAutoCommit(false)
}

set(variables) {
for (const key in variables) {
this._native.setClientInfo(key, variables[key])
this._native.set = function (variables) {
for (const key in variables) {
this.setClientInfo(key, variables[key])
}
}
this._native.setAutoCommit(false)
}

async prepare(sql, hasBlobs) {
Expand Down
14 changes: 7 additions & 7 deletions hana/lib/drivers/hdb.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,16 @@ class HDBDriver extends driver {
this._native = wrap_client(this._native, creds, creds.tenant)
this._native.setAutoCommit(false)
this._native.on('close', () => this.destroy?.())
this._native.set = function(variables) {
const clientInfo = this._connection.getClientInfo()
for (const key in variables) {
clientInfo.setProperty(key, variables[key])
}
}

this.connected = false
}

set(variables) {
const clientInfo = this._native._connection.getClientInfo()
for (const key in variables) {
clientInfo.setProperty(key, variables[key])
}
}

async validate() {
return this._native.readyState === 'connected'
}
Expand Down Expand Up @@ -438,6 +437,7 @@ const readString = function (state, isJson = false) {
}

const { readInt64LE } = require('hdb/lib/util/bignum.js')
const { func } = require('@sap/cds/lib/ql/cds-ql')

Check warning on line 440 in hana/lib/drivers/hdb.js

View workflow job for this annotation

GitHub Actions / Tests (22)

'func' is assigned a value but never used
const readBlob = function (state, encoding) {
// Check if the blob is null
let ens = state.ensure(2)
Expand Down
30 changes: 30 additions & 0 deletions hana/tools/docker/hce/hana.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ services:
image: hana-master:current
restart: always
hostname: hcehost
networks:
- backend
command:
- --init
- role=worker:services=indexserver,dpserver,diserver:database=H00:create
Expand All @@ -20,3 +22,31 @@ services:
# - '30040:30040'
# - '30042:30042'
# - '30043:30043'

jaeger:
networks:
backend:
# This is the host name used in Prometheus scrape configuration.
aliases: [ spm_metrics_source ]
image: jaegertracing/jaeger:${JAEGER_VERSION:-latest}
volumes:
- "./jaeger.yaml:/etc/jaeger/config.yml"
command: ["--config", "/etc/jaeger/config.yml"]
ports:
- "16686:16686"
- "8888:8888"
- "8889:8889"
- "4317:4317"
- "4318:4318"

prometheus:
networks:
- backend
image: prom/prometheus:v3.1.0
volumes:
- "./prometheus.yml:/etc/prometheus/prometheus.yml"
ports:
- "9090:9090"

networks:
backend:
55 changes: 55 additions & 0 deletions hana/tools/docker/hce/jaeger.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
service:
extensions: [jaeger_storage, jaeger_query]
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [jaeger_storage_exporter, spanmetrics]
metrics/spanmetrics:
receivers: [spanmetrics]
exporters: [prometheus]
telemetry:
resource:
service.name: jaeger
metrics:
level: detailed
address: 0.0.0.0:8888
logs:
level: DEBUG

extensions:
jaeger_query:
max_clock_skew_adjust: 30s
storage:
traces: some_storage
metrics: some_metrics_storage
jaeger_storage:
backends:
some_storage:
memory:
max_traces: 100000
metric_backends:
some_metrics_storage:
prometheus:
endpoint: http://prometheus:9090
normalize_calls: true
normalize_duration: true

connectors:
spanmetrics:

receivers:
otlp:
protocols:
grpc:
http:
endpoint: "0.0.0.0:4318"

processors:
batch:

exporters:
jaeger_storage_exporter:
trace_storage: some_storage
prometheus:
endpoint: "0.0.0.0:8889"
64 changes: 64 additions & 0 deletions hana/tools/docker/hce/otel.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/bin/bash

# Directory containing the trace files
TRACE_DIR="/hana/mounts/trace/hana/DB_H00"

# OpenTelemetry endpoint
OTEL_ENDPOINT="http://jaeger:4318/v1/traces"

# Function to process a trace file
process_trace_file() {
local trace_file="$1"
tail -F "$trace_file" | awk -v RS='\n\n' 'function generate_span_id() {
cmd = "cat /proc/sys/kernel/random/uuid | tr -d \"-\" | cut -c1-16 | tr -d \"\n\""
cmd | getline span_id
close(cmd)
return span_id
}
{
split($0, fields, ";");
traceId=fields[22];
spanId=generate_span_id();
parentSpanId=substr(fields[24], 17);
startTime=fields[6] "000"; # Convert to nanoseconds
duration=fields[7] "000"; # Convert to nanoseconds
endTime=startTime + duration;
operation=fields[9];
statementString=fields[54];
memSize=fields[19];
cpuTime=fields[21];
gsub(/^#/, "", statementString);
gsub(/\n/, " ", statementString);
gsub(/"/, "\\\"", statementString);
# Prepare the JSON payload according to OpenTelemetry API structure
print sprintf("{\"resourceSpans\":[{\"resource\":{\"attributes\":[{\"key\":\"service.name\",\"value\":{\"stringValue\":\"@sap/hana-cloud\"}}]},\"scopeSpans\":[{\"spans\":[{\"traceId\":\"%s\",\"spanId\":\"%s\",\"parentSpanId\":\"%s\",\"name\":\"%s\",\"kind\":2,\"startTimeUnixNano\":\"%s\",\"endTimeUnixNano\":\"%s\",\"attributes\":[{\"key\":\"db.statement\",\"value\":{\"stringValue\":\"%s\"}},{\"key\":\"db.operation\",\"value\":{\"stringValue\":\"%s\"}},{\"key\":\"db.mem_size\",\"value\":{\"intValue\":%s}},{\"key\":\"db.cpu_time\",\"value\":{\"intValue\":%s}}]}]}]}]}", traceId, spanId, parentSpanId, operation, startTime, endTime, statementString, operation, memSize, cpuTime);
}' | while read -r json_payload; do
echo "$json_payload"
echo "$json_payload" | curl -X POST "$OTEL_ENDPOINT" -H "Content-Type: application/json" -d @-
done
}

# Function to handle script termination
cleanup() {
echo "Cleaning up..."
pkill -P $$
exit 0
}

# Trap signals to ensure cleanup
trap cleanup SIGINT SIGTERM

# Monitor the directory for new trace files and changes
declare -A processed_files

while true; do
for trace_file in "$TRACE_DIR"/*.expensive_statements.*.trc; do
if [ -f "$trace_file" ] && [ -z "${processed_files[$trace_file]}" ]; then
echo "Listening to $trace_file..."
process_trace_file "$trace_file" &
processed_files["$trace_file"]=1
fi
done
sleep 10
done
9 changes: 9 additions & 0 deletions hana/tools/docker/hce/prometheus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).

scrape_configs:
- job_name: aggregated-trace-metrics
static_configs:
- targets: ['spm_metrics_source:8889']
11 changes: 10 additions & 1 deletion hana/tools/docker/hce/ready.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
docker exec hce-hana-1 /bin/bash -c "while ! ./check_hana_health ; do sleep 10 ; done;"
until docker cp ./otel.sh hce-hana-1:/otel.sh
do
sleep 1
done

docker exec hce-hana-1 /bin/bash -c "while ! ./check_hana_health ; do sleep 10 ; done;/otel.sh &;"
docker exec -it hce-hana-1 /bin/bash -c "\
cd /usr/sap/H00/HDB00;\
. ./hdbenv.sh;\
hdbuserstore -i SET SYSDBKEY localhost:30013@SYSTEMDB SYSTEM Manager1;\
hdbsql -U \"SYSDBKEY\" -e -ssltrustcert \"SELECT COUNT(ACTIVE_STATUS) FROM SYS_DATABASES.M_SERVICES WHERE ACTIVE_STATUS='YES'\";\
hdbsql -U \"SYSDBKEY\" -e -ssltrustcert \"ALTER SYSTEM ALTER CONFIGURATION ('indexserver.ini', 'DATABASE', 'H00') SET ('session', 'enable_proxy_protocol') = 'false' WITH RECONFIGURE;\";\
hdbsql -U \"SYSDBKEY\" -e -ssltrustcert \"ALTER SYSTEM ALTER CONFIGURATION ('global.ini', 'System') SET ('public_hostname_resolution', 'use_default_route') = 'name' WITH RECONFIGURE;\";\
hdbsql -U \"SYSDBKEY\" -e -ssltrustcert \"ALTER SYSTEM ALTER CONFIGURATION ('global.ini', 'System') SET ('expensive_statement', 'enable') = 'TRUE' WITH RECONFIGURE;\";\
hdbsql -U \"SYSDBKEY\" -e -ssltrustcert \"ALTER SYSTEM ALTER CONFIGURATION ('global.ini', 'System') SET ('expensive_statement', 'threshold_duration') = '0' WITH RECONFIGURE;\";\
hdbsql -U \"SYSDBKEY\" -e -ssltrustcert \"ALTER SYSTEM ALTER CONFIGURATION ('global.ini', 'System') SET ('expensive_statement', 'trace_parameter_values') = 'FALSE' WITH RECONFIGURE;\";\
hdbsql -U \"SYSDBKEY\" -e -ssltrustcert \"ALTER SYSTEM ALTER CONFIGURATION ('global.ini', 'System') SET ('expensive_statement', 'use_in_memory_tracing') = 'FALSE' WITH RECONFIGURE;\";\
"

0 comments on commit 1df2ebc

Please sign in to comment.