File: RecordMySQLQuery.cc

package info (click to toggle)
bpfcc 0.26.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 20,568 kB
  • sloc: ansic: 488,515; python: 38,439; cpp: 25,333; sh: 780; makefile: 262
file content (104 lines) | stat: -rw-r--r-- 2,602 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
 * RecordMySQLQuery Record MySQL queries by probing the alloc_query() function
 *                  in mysqld. For Linux, uses BCC, eBPF. Embedded C.
 *
 * Basic example of BCC and uprobes.
 *
 * Copyright (c) Facebook, Inc.
 * Licensed under the Apache License, Version 2.0 (the "License")
 */

#include <unistd.h>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <string>

#include "BPF.h"

const std::string BPF_PROGRAM = R"(
#include <linux/ptrace.h>

struct query_probe_t {
  uint64_t ts;
  pid_t pid;
  char query[100];
};

BPF_HASH(queries, struct query_probe_t, int);

int probe_mysql_query(struct pt_regs *ctx, void* thd, char* query, size_t len) {
  if (query) {
    struct query_probe_t key = {};

    key.ts = bpf_ktime_get_ns();
    key.pid = bpf_get_current_pid_tgid();

    bpf_probe_read_user_str(&key.query, sizeof(key.query), query);

    int one = 1;
    queries.update(&key, &one);
  }
  return 0;
}
)";
const std::string ALLOC_QUERY_FUNC = "_Z11alloc_queryP3THDPKcj";

// Define the same struct to use in user space.
struct query_probe_t {
  uint64_t ts;
  pid_t pid;
  char query[100];
};

int main(int argc, char** argv) {
  if (argc < 2) {
    std::cout << "USAGE: RecordMySQLQuery PATH_TO_MYSQLD [duration]"
              << std::endl;
    exit(1);
  }

  std::string mysql_path(argv[1]);
  std::cout << "Using mysqld path: " << mysql_path << std::endl;

  ebpf::BPF bpf;
  auto init_res = bpf.init(BPF_PROGRAM);
  if (!init_res.ok()) {
    std::cerr << init_res.msg() << std::endl;
    return 1;
  }

  auto attach_res =
      bpf.attach_uprobe(mysql_path, ALLOC_QUERY_FUNC, "probe_mysql_query");
  if (!attach_res.ok()) {
    std::cerr << attach_res.msg() << std::endl;
    return 1;
  }

  int probe_time = 10;
  if (argc >= 3)
    probe_time = atoi(argv[2]);
  std::cout << "Probing for " << probe_time << " seconds" << std::endl;
  sleep(probe_time);

  auto table_handle = bpf.get_hash_table<query_probe_t, int>("queries");
  auto table = table_handle.get_table_offline();
  std::sort(
      table.begin(), table.end(),
      [](std::pair<query_probe_t, int> a, std::pair<query_probe_t, int> b) {
        return a.first.ts < b.first.ts;
      });
  std::cout << table.size() << " queries recorded:" << std::endl;
  for (auto it : table) {
    std::cout << "Time: " << it.first.ts << " PID: " << it.first.pid
              << " Query: " << it.first.query << std::endl;
  }

  auto detach_res = bpf.detach_uprobe(mysql_path, ALLOC_QUERY_FUNC);
  if (!detach_res.ok()) {
    std::cerr << detach_res.msg() << std::endl;
    return 1;
  }

  return 0;
}