bdc617db1892f9160d1d61bfe85bc3e6579a9a62
[dpdk.git] / usertools / dpdk-telemetry.py
1 #! /usr/bin/env python3
2 # SPDX-License-Identifier: BSD-3-Clause
3 # Copyright(c) 2020 Intel Corporation
4
5 """
6 Script to be used with V2 Telemetry.
7 Allows the user input commands and read the Telemetry response.
8 """
9
10 import socket
11 import os
12 import json
13 import errno
14 import readline
15 import argparse
16
17 # global vars
18 TELEMETRY_VERSION = "v2"
19 CMDS = []
20
21
22 def read_socket(sock, buf_len, echo=True):
23     """ Read data from socket and return it in JSON format """
24     reply = sock.recv(buf_len).decode()
25     try:
26         ret = json.loads(reply)
27     except json.JSONDecodeError:
28         print("Error in reply: ", reply)
29         sock.close()
30         raise
31     if echo:
32         print(json.dumps(ret))
33     return ret
34
35
36 def get_app_name(pid):
37     """ return the app name for a given PID, for printing """
38     proc_cmdline = os.path.join('/proc', str(pid), 'cmdline')
39     try:
40         with open(proc_cmdline) as f:
41             argv0 = f.read(1024).split('\0')[0]
42             return os.path.basename(argv0)
43     except IOError as e:
44         # ignore file not found errors
45         if e.errno != errno.ENOENT:
46             raise
47     return None
48
49
50 def handle_socket(path):
51     """ Connect to socket and handle user input """
52     sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
53     global CMDS
54     print("Connecting to " + path)
55     try:
56         sock.connect(path)
57     except OSError:
58         print("Error connecting to " + path)
59         sock.close()
60         return
61     json_reply = read_socket(sock, 1024)
62     output_buf_len = json_reply["max_output_len"]
63     app_name = get_app_name(json_reply["pid"])
64     if app_name:
65         print('Connected to application: "%s"' % app_name)
66
67     # get list of commands for readline completion
68     sock.send("/".encode())
69     CMDS = read_socket(sock, output_buf_len, False)["/"]
70
71     # interactive prompt
72     text = input('--> ').strip()
73     while text != "quit":
74         if text.startswith('/'):
75             sock.send(text.encode())
76             read_socket(sock, output_buf_len)
77         text = input('--> ').strip()
78     sock.close()
79
80
81 def readline_complete(text, state):
82     """ Find any matching commands from the list based on user input """
83     all_cmds = ['quit'] + CMDS
84     if text:
85         matches = [c for c in all_cmds if c.startswith(text)]
86     else:
87         matches = all_cmds
88     return matches[state]
89
90
91 def get_dpdk_runtime_dir(fp):
92     """ Using the same logic as in DPDK's EAL, get the DPDK runtime directory
93     based on the file-prefix and user """
94     if (os.getuid() == 0):
95         return os.path.join('/var/run/dpdk', fp)
96     return os.path.join(os.environ.get('XDG_RUNTIME_DIR', '/tmp'), 'dpdk', fp)
97
98
99 readline.parse_and_bind('tab: complete')
100 readline.set_completer(readline_complete)
101 readline.set_completer_delims(readline.get_completer_delims().replace('/', ''))
102
103 parser = argparse.ArgumentParser()
104 parser.add_argument('-f', '--file-prefix', default='rte',
105                     help='Provide file-prefix for DPDK runtime directory')
106 args = parser.parse_args()
107 rd = get_dpdk_runtime_dir(args.file_prefix)
108 handle_socket(os.path.join(rd, 'dpdk_telemetry.{}'.format(TELEMETRY_VERSION)))