3737from json import JSONEncoder
3838import logging
3939import os
40+ import socket
4041import struct
4142import sys
4243import uuid
@@ -823,14 +824,38 @@ def printable(b):
823824 return "" .join ("\\ \\ " if c == 92 else chr (c ) if 32 <= c < 127 else "\\ x%02x" % c for c in b )
824825
825826
826- def cluster_description (cluster_file ):
827- """The description part of the cluster file's connection string, looked up the same way fdb.open finds the file."""
827+ def connection_string (cluster_file ):
828+ """The cluster file's connection string, looked up the same way fdb.open finds the file."""
828829 for path in [cluster_file , os .environ .get ("FDB_CLUSTER_FILE" ), "fdb.cluster" ,
829830 "/etc/foundationdb/fdb.cluster" , "/usr/local/etc/foundationdb/fdb.cluster" ]:
830831 if path and os .path .exists (path ):
831832 with open (path ) as f :
832833 lines = [line .strip () for line in f if line .strip () and not line .startswith ("#" )]
833- return lines [- 1 ].split (":" )[0 ]
834+ return lines [- 1 ]
835+ return ""
836+
837+
838+ def cluster_description (cluster_file ):
839+ """The description part of the connection string, description:id@coordinators."""
840+ return connection_string (cluster_file ).split (":" )[0 ]
841+
842+
843+ def local_ip (cluster_file ):
844+ """The local IP this client reaches the coordinators from, i.e. what the OS picks for a UDP socket aimed at a
845+ coordinator (nothing is sent). Same way fdb picks the IP for client trace files."""
846+ coordinators = connection_string (cluster_file ).partition ("@" )[2 ]
847+ for coordinator in coordinators .split ("," ):
848+ address = coordinator .strip ()
849+ if address .endswith (":tls" ):
850+ address = address [:- len (":tls" )]
851+ host , _ , port = address .rpartition (":" )
852+ try :
853+ for family , _ , _ , _ , sockaddr in socket .getaddrinfo (host .strip ("[]" ), int (port ), type = socket .SOCK_DGRAM ):
854+ with socket .socket (family , socket .SOCK_DGRAM ) as s :
855+ s .connect (sockaddr )
856+ return s .getsockname ()[0 ]
857+ except (OSError , ValueError ):
858+ continue
834859 return ""
835860
836861
@@ -852,10 +877,11 @@ def audit_log_path():
852877class AuditLog (object ):
853878 """Appends one JSON line per output the tool prints. Entries from the same input share a reqid."""
854879
855- def __init__ (self , path , cluster ):
880+ def __init__ (self , path , cluster , ip_address = "" ):
856881 open (path , "a" ).close () # fail at startup, not mid-run, if the file isn't writable
857882 self .path = path
858883 self .cluster = cluster
884+ self .ip_address = ip_address
859885
860886 @staticmethod
861887 def new_reqid ():
@@ -867,6 +893,7 @@ def log(self, reqid, operation, input, **output):
867893 "level" : "info" ,
868894 "msg" : "TransactionProfilingAnalyzerAudit" ,
869895 "cluster" : self .cluster ,
896+ "ip_address" : self .ip_address ,
870897 "reqid" : reqid ,
871898 "operation" : operation ,
872899 "input" : input ,
@@ -948,7 +975,7 @@ def main():
948975
949976 audit = None
950977 if args .audit_log or "FDB_TRANSACTION_PROFILER_AUDIT_LOG_ENABLE" in os .environ :
951- audit = AuditLog (audit_log_path (), cluster_description (args .cluster_file ))
978+ audit = AuditLog (audit_log_path (), cluster_description (args .cluster_file ), local_ip ( args . cluster_file ) )
952979
953980 type_filter = set ()
954981 if args .filter_get_version :
0 commit comments