Repository URL to install this package:
|
Version:
2.68.0.50 ▾
|
from __future__ import print_function
import atexit
import cmd
import code
import functools
import glob
import inspect
import optparse
import os
import shlex
import socket
import sys
import threading
import traceback
import os
import time
try:
import ConfigParser
except ImportError:
import configparser as ConfigParser
try:
import __builtin__
except ImportError:
import builtins as __builtin__
from newrelic.core.agent import agent_instance
from newrelic.core.config import global_settings, flatten_settings
from newrelic.api.transaction import Transaction
from newrelic.api.object_wrapper import ObjectWrapper
from newrelic.core.transaction_cache import transaction_cache
_transaction_cache = transaction_cache()
def shell_command(wrapped):
args, varargs, keywords, defaults = inspect.getargspec(wrapped)
parser = optparse.OptionParser()
for name in args[1:]:
parser.add_option('--%s' % name, dest=name)
@functools.wraps(wrapped)
def wrapper(self, line):
result = shlex.split(line)
(options, args) = parser.parse_args(result)
kwargs = {}
for key, value in options.__dict__.items():
if value is not None:
kwargs[key] = value
return wrapped(self, *args, **kwargs)
if wrapper.__name__.startswith('do_'):
prototype = wrapper.__name__[3:] + ' ' + inspect.formatargspec(
args[1:], varargs, keywords, defaults)
if hasattr(wrapper, '__doc__') and wrapper.__doc__ is not None:
wrapper.__doc__ = '\n'.join((prototype,
wrapper.__doc__.lstrip('\n')))
return wrapper
_consoles = threading.local()
def acquire_console(shell):
_consoles.active = shell
def release_console():
del _consoles.active
def setquit():
"""Define new built-ins 'quit' and 'exit'.
These are simply strings that display a hint on how to exit.
"""
if os.sep == ':':
eof = 'Cmd-Q'
elif os.sep == '\\':
eof = 'Ctrl-Z plus Return'
else:
eof = 'Ctrl-D (i.e. EOF)'
class Quitter(object):
def __init__(self, name):
self.name = name
def __repr__(self):
return 'Use %s() or %s to exit' % (self.name, eof)
def __call__(self, code=None):
# If executed with our interactive console, only raise the
# SystemExit exception but don't close sys.stdout as we are
# not the owner of it.
if hasattr(_consoles, 'active'):
raise SystemExit(code)
# Shells like IDLE catch the SystemExit, but listen when their
# stdin wrapper is closed.
try:
sys.stdin.close()
except Exception:
pass
raise SystemExit(code)
__builtin__.quit = Quitter('quit')
__builtin__.exit = Quitter('exit')
class OutputWrapper(ObjectWrapper):
def flush(self):
try:
shell = _consoles.active
return shell.stdout.flush()
except Exception:
return self._nr_next_object.flush()
def write(self, data):
try:
shell = _consoles.active
return shell.stdout.write(data)
except Exception:
return self._nr_next_object.write(data)
def writelines(self, data):
try:
shell = _consoles.active
return shell.stdout.writelines(data)
except Exception:
return self._nr_next_object.writelines(data)
def intercept_console():
setquit()
sys.stdout = OutputWrapper(sys.stdout, None, None)
sys.stderr = OutputWrapper(sys.stderr, None, None)
class EmbeddedConsole(code.InteractiveConsole):
def write(self, data):
self.stdout.write(data)
self.stdout.flush()
def raw_input(self, prompt):
self.stdout.write(prompt)
self.stdout.flush()
line = self.stdin.readline()
line = line.rstrip('\r\n')
return line
class ConsoleShell(cmd.Cmd):
use_rawinput = 0
def __init__(self):
cmd.Cmd.__init__(self)
self.do_prompt('on')
def emptyline(self):
pass
def help_help(self):
print("""help (command)
Output list of commands or help details for named command.""",
file=self.stdout)
@shell_command
def do_prompt(self, flag=None):
"""
Enable or disable the console prompt."""
if flag == 'on':
self.prompt = '(newrelic:%d) ' % os.getpid()
elif flag == 'off':
self.prompt = ''
@shell_command
def do_exit(self):
"""
Exit the console."""
return True
@shell_command
def do_process_id(self):
"""
Displays the process ID of the process."""
print(os.getpid(), file=self.stdout)
@shell_command
def do_sys_prefix(self):
"""
Displays the value of sys.prefix."""
print(sys.prefix, file=self.stdout)
@shell_command
def do_sys_path(self):
"""
Displays the value of sys.path."""
print(sys.path, file=self.stdout)
@shell_command
def do_sys_modules(self):
"""
Displays the list of Python modules loaded."""
for name, module in sorted(sys.modules.items()):
if module is not None:
file = getattr(module, '__file__', None)
print("%s - %s" % (name, file), file=self.stdout)
@shell_command
def do_sys_meta_path(self):
"""
Displays the value of sys.meta_path."""
print(sys.meta_path, file=self.stdout)
@shell_command
def do_os_environ(self):
"""
Displays the set of user environment variables."""
for key, name in os.environ.items():
print("%s = %r" % (key, name), file=self.stdout)
@shell_command
def do_current_time(self):
"""
Displays the current time."""
print(time.asctime(), file=self.stdout)
@shell_command
def do_config_args(self):
"""
Displays the configure arguments used to build Python."""
args = ''
try:
# This may fail if using package Python and the
# developer package for Python isn't also installed.
import distutils.sysconfig
args = distutils.sysconfig.get_config_var('CONFIG_ARGS')
except Exception:
pass
print(args, file=self.stdout)
@shell_command
def do_dump_config(self, name=None):
"""
Displays global configuration or that of the named application.
"""
if name is None:
config = agent_instance().global_settings()
else:
config = agent_instance().application_settings(name)
if config is not None:
config = flatten_settings(config)
keys = sorted(config.keys())
for key in keys:
print('%s = %r' % (key, config[key]), file=self.stdout)
@shell_command
def do_agent_status(self):
"""
Displays general status information about the agent, registered
applications, harvest cycles etc.
"""
agent_instance().dump(self.stdout)
@shell_command
def do_applications(self):
"""
Displays a list of the applications.
"""
print(repr(sorted(
agent_instance().applications.keys())), file=self.stdout)
@shell_command
def do_application_status(self, name=None):
"""
Displays general status information about an application, last
harvest cycle, etc.
"""
if name is not None:
applications = [agent_instance().application(name)]
else:
applications = agent_instance().applications.values()
for application in applications:
if application is not None:
application.dump(self.stdout)
print(file=self.stdout)
@shell_command
def do_import_hooks(self):
"""
Displays list of registered import hooks, which have fired and
which encountered errors.
"""
from newrelic.config import module_import_hook_results
results = module_import_hook_results()
for key in sorted(results.keys()):
result = results[key]
if result is None:
if key[0] not in sys.modules:
print('%s: PENDING' % (key,), file=self.stdout)
else:
print('%s: IMPORTED' % (key,), file=self.stdout)
elif not result:
print('%s: INSTRUMENTED' % (key,), file=self.stdout)
else:
print('%s: FAILED' % (key,), file=self.stdout)
for line in result:
print(line, end='', file=self.stdout)
@shell_command
def do_transactions(self):
"""
"""
for item in _transaction_cache.active_threads():
transaction, thread_id, thread_type, frame = item
print('THREAD', item, file=self.stdout)
if transaction is not None:
transaction.dump(self.stdout)
print(file=self.stdout)
@shell_command
def do_interpreter(self):
"""
When enabled in the configuration file, will startup up an embedded
interactive Python interpreter. Invoke 'exit()' or 'quit()' to
escape the interpreter session."""
enabled = False
_settings = global_settings()
if not _settings.console.allow_interpreter_cmd:
print('Sorry, the embedded Python ' \
'interpreter is disabled.', file=self.stdout)
return
locals = {}
locals['stdin'] = self.stdin
locals['stdout'] = self.stdout
console = EmbeddedConsole(locals)
console.stdin = self.stdin
console.stdout = self.stdout
acquire_console(self)
try:
console.interact()
except SystemExit:
pass
finally:
release_console()
@shell_command
def do_threads(self):
"""
Display stack trace dumps for all threads currently executing
within the Python interpreter.
Note that if coroutines are being used, such as systems based
on greenlets, then only the thread stack of the currently
executing coroutine will be displayed."""
all = []
for threadId, stack in sys._current_frames().items():
block = []
block.append('# ThreadID: %s' % threadId)
thr = threading._active.get(threadId)
if thr:
block.append('# Type: %s' % type(thr).__name__)
block.append('# Name: %s' % thr.name)
for filename, lineno, name, line in traceback.extract_stack(
stack):
block.append('File: \'%s\', line %d, in %s' % (filename,
lineno, name))
if line:
block.append(' %s' % (line.strip()))
all.append('\n'.join(block))
print('\n\n'.join(all), file=self.stdout)
class ConnectionManager(object):
def __init__(self, listener_socket):
self.__listener_socket = listener_socket
self.__console_initialized = False
if not os.path.isabs(self.__listener_socket):
host, port = self.__listener_socket.split(':')
port = int(port)
self.__listener_socket = (host, port)
self.__thread = threading.Thread(target=self.__thread_run,
name='NR-Console-Manager')
self.__thread.setDaemon(True)
self.__thread.start()
def __socket_cleanup(self, path):
try:
os.unlink(path)
except Exception:
pass
def __thread_run(self):
if type(self.__listener_socket) == type(()):
listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listener.bind(self.__listener_socket)
else:
try:
os.unlink(self.__listener_socket)
except Exception:
pass
listener = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
listener.bind(self.__listener_socket)
atexit.register(self.__socket_cleanup, self.__listener_socket)
os.chmod(self.__listener_socket, 0o600)
listener.listen(5)
while True:
client, addr = listener.accept()
if not self.__console_initialized:
self.__console_initialized = True
intercept_console()
shell = ConsoleShell()
shell.stdin = client.makefile('r')
shell.stdout = client.makefile('w')
while True:
try:
shell.cmdloop()
except Exception:
shell.stdout.flush()
print('Unexpected exception.', file=shell.stdout)
exc_info = sys.exc_info()
traceback.print_exception(exc_info[0], exc_info[1],
exc_info[2], file=shell.stdout)
exc_info = None
else:
break
shell.stdin = None
shell.stdout = None
del shell
client.close()
class ClientShell(cmd.Cmd):
prompt = '(newrelic) '
def __init__(self, config_file, stdin=None, stdout=None, log=None):
cmd.Cmd.__init__(self, stdin=stdin, stdout=stdout)
self.__config_file = config_file
self.__config_object = ConfigParser.RawConfigParser()
self.__log_object = log
if not self.__config_object.read([config_file]):
raise RuntimeError('Unable to open configuration file %s.' %
config_file)
listener_socket = self.__config_object.get('newrelic',
'console.listener_socket') % {'pid': '*'}
if os.path.isabs(listener_socket):
self.__servers = [(socket.AF_UNIX, path) for path in
sorted(glob.glob(listener_socket))]
else:
host, port = listener_socket.split(':')
port = int(port)
self.__servers = [(socket.AF_INET, (host, port))]
def emptyline(self):
pass
def help_help(self):
print("""help (command)
Output list of commands or help details for named command.""",
file=self.stdout)
def do_exit(self, line):
"""exit
Exit the client shell."""
return True
def do_servers(self, line):
"""servers
Display a list of the servers which can be connected to."""
for i in range(len(self.__servers)):
print('%s: %s' % (i+1, self.__servers[i]), file=self.stdout)
def do_connect(self, line):
"""connect [index]
Connect to the server from the servers lift with given index. If
there is only one server then the index position does not need to
be supplied."""
if len(self.__servers) == 0:
print('No servers to connect to.', file=self.stdout)
return
if not line:
if len(self.__servers) != 1:
print('Multiple servers, which should be used?',
file=self.stdout)
return
else:
line = '1'
try:
selection = int(line)
except Exception:
selection = None
if selection is None:
print('Server selection not an integer.', file=self.stdout)
return
if selection <= 0 or selection > len(self.__servers):
print('Invalid server selected.', file=self.stdout)
return
server = self.__servers[selection-1]
client = socket.socket(server[0], socket.SOCK_STREAM)
client.connect(server[1])
def write():
while 1:
try:
c = sys.stdin.read(1)
if not c:
client.shutdown(socket.SHUT_RD)
break
if self.__log_object:
self.__log_object.write(c)
client.sendall(c)
except Exception:
break
def read():
while 1:
try:
c = client.recv(1)
if not c:
break
if self.__log_object:
self.__log_object.write(c)
sys.stdout.write(c)
sys.stdout.flush()
except Exception:
break
thread1 = threading.Thread(target=write)
thread1.setDaemon(True)
thread2 = threading.Thread(target=read)
thread2.setDaemon(True)
thread1.start()
thread2.start()
thread2.join()
return True
def main():
if len(sys.argv) == 1:
print("Usage: newrelic-console config_file")
sys.exit(1)
shell = ClientShell(sys.argv[1])
shell.cmdloop()
if __name__ == '__main__':
main()