Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion ext/mariadb_profiler/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ if test "$PHP_MARIADB_PROFILER" != "no"; then
fi

PHP_NEW_EXTENSION(mariadb_profiler,
mariadb_profiler.c profiler_mysqlnd_plugin.c profiler_job.c profiler_log.c profiler_tag.c profiler_trace.c,
mariadb_profiler.c profiler_mysqlnd_plugin.c profiler_job.c profiler_log.c profiler_tag.c profiler_trace.c profiler_xdebug.c,
$ext_shared,, $PROFILER_CFLAGS)

dnl Require mysqlnd
Expand Down
2 changes: 1 addition & 1 deletion ext/mariadb_profiler/config.w32
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ ARG_ENABLE('mariadb_profiler', 'MariaDB Query Profiler support', 'no');

if (PHP_MARIADB_PROFILER != 'no') {
EXTENSION('mariadb_profiler',
'mariadb_profiler.c profiler_mysqlnd_plugin.c profiler_job.c profiler_log.c profiler_tag.c profiler_trace.c',
'mariadb_profiler.c profiler_mysqlnd_plugin.c profiler_job.c profiler_log.c profiler_tag.c profiler_trace.c profiler_xdebug.c',
PHP_MARIADB_PROFILER_SHARED,
'/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1');
ADD_EXTENSION_DEP('mariadb_profiler', 'mysqlnd', true);
Expand Down
17 changes: 17 additions & 0 deletions ext/mariadb_profiler/mariadb_profiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_mariadb_profiler.h"
#include "profiler_xdebug.h"

#include <sys/stat.h>
#include <errno.h>
Expand Down Expand Up @@ -62,6 +63,14 @@ PHP_INI_BEGIN()
trace_depth,
zend_mariadb_profiler_globals,
mariadb_profiler_globals)

STD_PHP_INI_ENTRY("mariadb_profiler.xdebug_break_threshold",
"0",
PHP_INI_ALL,
OnUpdateReal,
xdebug_break_threshold,
zend_mariadb_profiler_globals,
mariadb_profiler_globals)
PHP_INI_END()
/* }}} */

Expand Down Expand Up @@ -226,6 +235,8 @@ PHP_RINIT_FUNCTION(mariadb_profiler)
/* {{{ PHP_RSHUTDOWN_FUNCTION */
PHP_RSHUTDOWN_FUNCTION(mariadb_profiler)
{
profiler_xdebug_request_shutdown();

if (PROFILER_G(enabled)) {
profiler_tag_clear_all();
profiler_job_free_active_jobs();
Expand Down Expand Up @@ -256,6 +267,12 @@ PHP_MINFO_FUNCTION(mariadb_profiler)
php_info_print_table_row(2, "Log directory", PROFILER_G(log_dir));
php_info_print_table_row(2, "Raw logging", PROFILER_G(raw_log) ? "Yes" : "No");
php_info_print_table_row(2, "Trace depth", trace_depth_str);
{
char threshold_str[32];
snprintf(threshold_str, sizeof(threshold_str), "%.3f",
PROFILER_G(xdebug_break_threshold));
php_info_print_table_row(2, "xdebug break threshold (s)", threshold_str);
}
php_info_print_table_end();

DISPLAY_INI_ENTRIES();
Expand Down
19 changes: 15 additions & 4 deletions ext/mariadb_profiler/php_mariadb_profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ ZEND_BEGIN_MODULE_GLOBALS(mariadb_profiler)
int tag_depth;
/* Trace settings */
zend_long trace_depth; /* 0=disabled, N=capture N frames */
/* xdebug integration */
double xdebug_break_threshold; /* seconds; 0=disabled */
#if PHP_VERSION_ID >= 70000
/* Prepared statement query template storage (PHP 7.0+) */
HashTable *stmt_queries; /* stmt ptr -> query template string */
Expand Down Expand Up @@ -99,13 +101,17 @@ void profiler_job_free_active_jobs(void);
int profiler_job_is_any_active(void);
char **profiler_job_get_active_list(int *count);

/* Logging – status is "ok" or "err" (NULL treated as "ok") */
void profiler_log_query(const char *query, size_t query_len, const char *status);
/* Logging – status is "ok" or "err" (NULL treated as "ok")
* duration_ms: query execution time in milliseconds, negative if not measured */
void profiler_log_query(const char *query, size_t query_len,
const char *status, double duration_ms);
void profiler_log_query_with_params(const char *query, size_t query_len,
const char *params_json, const char *status);
const char *params_json, const char *status,
double duration_ms);
void profiler_log_raw(const char *job_key, const char *query, size_t query_len,
const char *tag, const char *trace_json,
const char *params_json, const char *status);
const char *params_json, const char *status,
double duration_ms);
void profiler_log_init(void);
void profiler_log_shutdown(void);

Expand All @@ -119,6 +125,11 @@ void profiler_tag_clear_all(void);
/* Trace */
char *profiler_trace_capture_json(void);

/* xdebug integration */
int profiler_xdebug_is_debugger_active(void);
void profiler_xdebug_break(void);
void profiler_xdebug_request_shutdown(void);

/* PHP functions */
PHP_FUNCTION(mariadb_profiler_tag);
PHP_FUNCTION(mariadb_profiler_untag);
Expand Down
62 changes: 44 additions & 18 deletions ext/mariadb_profiler/profiler_log.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,12 @@ static double profiler_log_get_microtime(void)

/* {{{ profiler_log_raw
* Write raw query to job's raw log file.
* tag, trace_json, params_json, and status may be NULL. */
* tag, trace_json, params_json, and status may be NULL.
* duration_ms: query execution time in milliseconds, negative if not measured. */
void profiler_log_raw(const char *job_key, const char *query, size_t query_len,
const char *tag, const char *trace_json,
const char *params_json, const char *status)
const char *params_json, const char *status,
double duration_ms)
{
char *filepath;
FILE *fp;
Expand All @@ -134,12 +136,24 @@ void profiler_log_raw(const char *job_key, const char *query, size_t query_len,

timestamp = profiler_log_get_timestamp();

if (tag) {
fprintf(fp, "[%s] [%s] [%s] %.*s\n", timestamp,
status ? status : "ok", tag, (int)query_len, query);
if (duration_ms >= 0) {
if (tag) {
fprintf(fp, "[%s] [%s] [%.3fms] [%s] %.*s\n", timestamp,
status ? status : "ok", duration_ms, tag,
(int)query_len, query);
} else {
fprintf(fp, "[%s] [%s] [%.3fms] %.*s\n", timestamp,
status ? status : "ok", duration_ms,
(int)query_len, query);
}
} else {
fprintf(fp, "[%s] [%s] %.*s\n", timestamp,
status ? status : "ok", (int)query_len, query);
if (tag) {
fprintf(fp, "[%s] [%s] [%s] %.*s\n", timestamp,
status ? status : "ok", tag, (int)query_len, query);
} else {
fprintf(fp, "[%s] [%s] %.*s\n", timestamp,
status ? status : "ok", (int)query_len, query);
}
}

/* Append bound parameter values if present */
Expand Down Expand Up @@ -207,10 +221,12 @@ void profiler_log_raw(const char *job_key, const char *query, size_t query_len,
/* {{{ profiler_log_jsonl
* Write JSON line to job's parsed log file.
* tag, trace_json, params_json, and status may be NULL.
* duration_ms: query execution time in milliseconds, negative if not measured.
* SQL parsing (table/column extraction) is done by the CLI tool. */
static void profiler_log_jsonl(const char *job_key, const char *query, size_t query_len,
const char *tag, const char *trace_json,
const char *params_json, const char *status)
const char *params_json, const char *status,
double duration_ms)
{
char *filepath;
FILE *fp;
Expand Down Expand Up @@ -259,6 +275,10 @@ static void profiler_log_jsonl(const char *job_key, const char *query, size_t qu
fprintf(fp, ",\"s\":\"%s\"", status);
}

if (duration_ms >= 0) {
fprintf(fp, ",\"duration_ms\":%.3f", duration_ms);
}
Comment on lines +278 to +280

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for QueryEntry.kt and check if it contains duration_ms or durationMs
fd "QueryEntry.kt" -x grep -n "duration" {} \; || echo "File not found or no duration references"

Repository: 39ff/php-ext-mariadb-salvage

Length of output: 112


🏁 Script executed:

#!/bin/bash
# Also check the directory structure to understand the layout
find . -name "*.kt" -type f | head -20

Repository: 39ff/php-ext-mariadb-salvage

Length of output: 1837


🏁 Script executed:

#!/bin/bash
# Check the profiler_log.c file around lines 278-280
if [ -f "ext/mariadb_profiler/profiler_log.c" ]; then
    sed -n '275,285p' ext/mariadb_profiler/profiler_log.c
else
    echo "File not found"
fi

Repository: 39ff/php-ext-mariadb-salvage

Length of output: 309


🏁 Script executed:

#!/bin/bash
# Read the QueryEntry.kt file to see its current structure
cat -n ./jetbrains-plugin/src/main/kotlin/com/mariadbprofiler/plugin/model/QueryEntry.kt

Repository: 39ff/php-ext-mariadb-salvage

Length of output: 9818


🏁 Script executed:

#!/bin/bash
# Check the git status or recent changes to see if QueryEntry.kt was supposed to be modified
git log --oneline -20

Repository: 39ff/php-ext-mariadb-salvage

Length of output: 143


🏁 Script executed:

#!/bin/bash
# Search for any recent mentions of durationMs or duration_ms in the codebase
rg "durationMs|duration_ms" --max-count=20

Repository: 39ff/php-ext-mariadb-salvage

Length of output: 4438


LGTM!

JSONL出力の duration_ms フィールドは計測済みの場合のみ出力され、%.3f フォーマットでミリ秒精度を保持しています。ただし、JetBrains プラグイン側の QueryEntry データクラスに durationMs フィールド(@SerialName("duration_ms") 付き)の追加がまだ必要です。このフィールドなしではJSON逆シリアル化時に値が失われます。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ext/mariadb_profiler/profiler_log.c` around lines 278 - 280, Add a nullable,
serializable durationMs property to the JetBrains plugin's QueryEntry data class
so the JSONL "duration_ms" field is preserved; specifically, in QueryEntry
declare something like `@SerialName`("duration_ms") val durationMs: Double? = null
(or equivalent nullable numeric type) so missing fields deserialize safely and
present values are captured.


fprintf(fp, ",\"ts\":%.6f}\n", ts);

efree(escaped_query);
Expand All @@ -274,10 +294,12 @@ static void profiler_log_jsonl(const char *job_key, const char *query, size_t qu

/* {{{ profiler_log_query_internal
* Internal: log a query to all active jobs with optional params and status.
* Captures the current context tag and PHP trace once, shared across all jobs. */
* Captures the current context tag and PHP trace once, shared across all jobs.
* duration_ms: query execution time in milliseconds, negative if not measured. */
static void profiler_log_query_internal(const char *query, size_t query_len,
const char *params_json,
const char *status)
const char *status,
double duration_ms)
{
char **jobs;
int job_count;
Expand All @@ -298,11 +320,11 @@ static void profiler_log_query_internal(const char *query, size_t query_len,

for (i = 0; i < job_count; i++) {
/* Write JSONL entry */
profiler_log_jsonl(jobs[i], query, query_len, tag, trace_json, params_json, status);
profiler_log_jsonl(jobs[i], query, query_len, tag, trace_json, params_json, status, duration_ms);

/* Write raw log if enabled */
if (PROFILER_G(raw_log)) {
profiler_log_raw(jobs[i], query, query_len, tag, trace_json, params_json, status);
profiler_log_raw(jobs[i], query, query_len, tag, trace_json, params_json, status, duration_ms);
}
}

Expand All @@ -314,20 +336,24 @@ static void profiler_log_query_internal(const char *query, size_t query_len,

/* {{{ profiler_log_query
* Main entry point: log a query (without params) to all active jobs.
* status is "ok" or "err" (NULL treated as "ok"). */
void profiler_log_query(const char *query, size_t query_len, const char *status)
* status is "ok" or "err" (NULL treated as "ok").
* duration_ms: query execution time in milliseconds, negative if not measured. */
void profiler_log_query(const char *query, size_t query_len,
const char *status, double duration_ms)
{
profiler_log_query_internal(query, query_len, NULL, status);
profiler_log_query_internal(query, query_len, NULL, status, duration_ms);
}
/* }}} */

/* {{{ profiler_log_query_with_params
* Log a prepared statement query with bound parameter values to all active jobs.
* status is "ok" or "err" (NULL treated as "ok"). */
* status is "ok" or "err" (NULL treated as "ok").
* duration_ms: query execution time in milliseconds, negative if not measured. */
void profiler_log_query_with_params(const char *query, size_t query_len,
const char *params_json, const char *status)
const char *params_json, const char *status,
double duration_ms)
{
profiler_log_query_internal(query, query_len, params_json, status);
profiler_log_query_internal(query, query_len, params_json, status, duration_ms);
}
/* }}} */

Expand Down
Loading