Skip to content

Commit 010cc18

Browse files
authored
Handle when no sys.arv; Better procfs parsing (#206)
1 parent da98237 commit 010cc18

File tree

1 file changed

+83
-53
lines changed

1 file changed

+83
-53
lines changed

instana/meter.py

Lines changed: 83 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -241,78 +241,108 @@ def handle_agent_tasks(self, task):
241241

242242
self.agent.task_response(task["messageId"], payload)
243243

244-
def get_proc_cmdline(self):
245-
name = None
244+
def get_proc_cmdline(self, as_string=False):
245+
"""
246+
Parse the proc file system for the command line of this process. If not available, then return a default.
247+
Return is dependent on the value of `as_string`. If True, return the full command line as a string,
248+
otherwise a list.
249+
"""
250+
name = "python"
246251
if os.path.isfile("/proc/self/cmdline"):
247252
with open("/proc/self/cmdline") as cmd:
248253
name = cmd.read()
249-
return name
254+
else:
255+
# Most likely not on a *nix based OS. Return a default
256+
if as_string is True:
257+
return name
258+
else:
259+
return [name]
260+
261+
# /proc/self/command line will have strings with null bytes such as "/usr/bin/python\0-s\0-d\0". This
262+
# bit will prep the return value and drop the trailing null byte
263+
parts = name.split('\0')
264+
parts.pop()
265+
266+
if as_string is True:
267+
parts = " ".join(parts)
268+
269+
return parts
250270

251271
def get_application_name(self):
272+
""" This function makes a best effort to name this application process. """
273+
252274
# One environment variable to rule them all
253275
if "INSTANA_SERVICE_NAME" in os.environ:
254276
return os.environ["INSTANA_SERVICE_NAME"]
255277

256-
# Now best effort in naming this process. No nice package.json like in Node.js
257-
# so we do best effort detection here.
258-
259-
basename = os.path.basename(sys.argv[0])
260-
if basename == "gunicorn":
261-
# gunicorn renames their processes to pretty things - we use those by default
262-
# gunicorn: master [djface.wsgi]
263-
# gunicorn: worker [djface.wsgi]
264-
app_name = self.get_proc_cmdline()
265-
266-
if app_name is None:
267-
app_name = basename
268-
elif "FLASK_APP" in os.environ:
269-
app_name = os.environ["FLASK_APP"]
270-
elif "DJANGO_SETTINGS_MODULE" in os.environ:
271-
app_name = os.environ["DJANGO_SETTINGS_MODULE"].split('.')[0]
272-
elif basename == '':
273-
if sys.stdout.isatty():
274-
app_name = "Interactive Console"
275-
else:
276-
# No arguments. Take executable as app_name
277-
app_name = os.path.basename(sys.executable)
278-
else:
279-
# Last chance. app_name for "python main.py" would be "main.py" here.
280-
app_name = basename
281-
282-
# We should have a good app_name by this point.
283-
# Last conditional, if uwsgi, then wrap the name
284-
# with the uwsgi process type
285-
if basename == "uwsgi":
286-
# We have an app name by this point. Now if running under
287-
# uwsgi, augment the appname
288-
try:
289-
import uwsgi
290-
291-
if app_name == "uwsgi":
292-
app_name = ""
293-
else:
294-
app_name = " [%s]" % app_name
295-
296-
if os.getpid() == uwsgi.masterpid():
297-
uwsgi_type = "uWSGI master%s"
278+
try:
279+
# Now best effort in naming this process. No nice package.json like in Node.js
280+
# so we do best effort detection here.
281+
app_name = "python" # the default name
282+
283+
if not hasattr(sys, 'argv'):
284+
proc_cmdline = self.get_proc_cmdline(as_string=False)
285+
return os.path.basename(proc_cmdline[0])
286+
287+
basename = os.path.basename(sys.argv[0])
288+
if basename == "gunicorn":
289+
# gunicorn renames their processes to pretty things - we use those by default
290+
# gunicorn: master [djface.wsgi]
291+
# gunicorn: worker [djface.wsgi]
292+
app_name = self.get_proc_cmdline(as_string=True)
293+
294+
if app_name is None:
295+
app_name = basename
296+
elif "FLASK_APP" in os.environ:
297+
app_name = os.environ["FLASK_APP"]
298+
elif "DJANGO_SETTINGS_MODULE" in os.environ:
299+
app_name = os.environ["DJANGO_SETTINGS_MODULE"].split('.')[0]
300+
elif basename == '':
301+
if sys.stdout.isatty():
302+
app_name = "Interactive Console"
298303
else:
299-
uwsgi_type = "uWSGI worker%s"
300-
301-
app_name = uwsgi_type % app_name
302-
except ImportError:
303-
pass
304+
# No arguments. Take executable as app_name
305+
app_name = os.path.basename(sys.executable)
306+
else:
307+
# Last chance. app_name for "python main.py" would be "main.py" here.
308+
app_name = basename
304309

305-
return app_name
310+
# We should have a good app_name by this point.
311+
# Last conditional, if uwsgi, then wrap the name
312+
# with the uwsgi process type
313+
if basename == "uwsgi":
314+
# We have an app name by this point. Now if running under
315+
# uwsgi, augment the app name
316+
try:
317+
import uwsgi
318+
319+
if app_name == "uwsgi":
320+
app_name = ""
321+
else:
322+
app_name = " [%s]" % app_name
323+
324+
if os.getpid() == uwsgi.masterpid():
325+
uwsgi_type = "uWSGI master%s"
326+
else:
327+
uwsgi_type = "uWSGI worker%s"
328+
329+
app_name = uwsgi_type % app_name
330+
except ImportError:
331+
pass
332+
return app_name
333+
except Exception as e:
334+
logger.debug("get_application_name: ", exc_info=True)
335+
return app_name
306336

307337
def collect_snapshot(self):
308338
""" Collects snapshot related information to this process and environment """
309339
try:
310340
if self.cached_snapshot is not None:
311341
return self.cached_snapshot
312342

313-
appname = self.get_application_name()
343+
app_name = self.get_application_name()
314344

315-
s = Snapshot(name=appname, version=platform.version(),
345+
s = Snapshot(name=app_name, version=platform.version(),
316346
f=platform.python_implementation(),
317347
a=platform.architecture()[0],
318348
djmw=self.djmw)

0 commit comments

Comments
 (0)