Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add log collection tool and thread #1987

Merged
merged 35 commits into from
Sep 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4b64377
wip @ command-line tool
pgombar Aug 6, 2020
01d4487
command-line tool and conf option added
pgombar Aug 6, 2020
4d9f21a
fix failing tests
pgombar Aug 6, 2020
081faf4
wip @ log collection thread
pgombar Aug 7, 2020
1463ace
fix archive read
pgombar Aug 7, 2020
71e0b87
fix encoding and logging
pgombar Aug 7, 2020
528b4d4
remove encoding
pgombar Aug 7, 2020
70da5a5
fix tests
pgombar Aug 8, 2020
78911e1
wip @ collect logs thread
pgombar Aug 10, 2020
daa2962
fix args for resource limits and add log
pgombar Aug 10, 2020
ba6e78e
add explicit utf-8 encoding
pgombar Aug 11, 2020
aa2d176
don't print verbose for log upload
pgombar Aug 11, 2020
fddd255
improve error handling when decoding
pgombar Aug 11, 2020
7011484
copy manifest files at log collection thread startup
pgombar Aug 11, 2020
2ba0f9c
fix typo in log
pgombar Aug 11, 2020
b04c095
manifest file discovery
pgombar Aug 11, 2020
3a7fc1f
manifest files should be packaged
pgombar Aug 12, 2020
a66ec2d
fix failing tests
pgombar Aug 12, 2020
d8f7871
create manifests dir if needed
pgombar Aug 12, 2020
24b744e
design review feedback
pgombar Aug 18, 2020
6f9cc18
remove unnecessary files
pgombar Aug 18, 2020
f99c7dd
Merge remote-tracking branch 'upstream/develop' into log_tool
pgombar Aug 18, 2020
0f90a21
order classes like develop
pgombar Aug 18, 2020
91bb406
fix failing tests
pgombar Aug 18, 2020
6fd0f75
Merge remote-tracking branch 'upstream/develop' into log_tool
pgombar Aug 20, 2020
d656433
Merge remote-tracking branch 'upstream/develop' into log_tool
pgombar Aug 24, 2020
d13c2ec
fix pylint warnings
pgombar Aug 25, 2020
fc811bc
Merge remote-tracking branch 'upstream/develop' into log_tool
pgombar Sep 3, 2020
49e7ca9
improve mock in log collector tests
pgombar Sep 3, 2020
c883d9e
Merge remote-tracking branch 'upstream/develop' into log_tool
pgombar Sep 9, 2020
c6b1736
address comments
pgombar Sep 9, 2020
ccc8a2c
fix linter errors
pgombar Sep 9, 2020
32ec229
address more comments
pgombar Sep 9, 2020
801ae8a
address more comments
pgombar Sep 10, 2020
80e2056
make systemd path constant and improve verbose log for encoded data
pgombar Sep 10, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 58 additions & 30 deletions azurelinuxagent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,23 @@
from __future__ import print_function

import os
import sys
import re
import subprocess
import sys
import threading
import traceback

import azurelinuxagent.common.logger as logger
import azurelinuxagent.common.event as event
import azurelinuxagent.common.conf as conf
from azurelinuxagent.common.version import AGENT_NAME, AGENT_LONG_VERSION, \
DISTRO_NAME, DISTRO_VERSION, \
PY_VERSION_MAJOR, PY_VERSION_MINOR, \
PY_VERSION_MICRO, GOAL_STATE_AGENT_VERSION
import azurelinuxagent.common.event as event
import azurelinuxagent.common.logger as logger
from azurelinuxagent.common.future import ustr
from azurelinuxagent.common.logcollector import LogCollector, OUTPUT_RESULTS_FILE_PATH
from azurelinuxagent.common.osutil import get_osutil
from azurelinuxagent.common.utils import fileutil
from azurelinuxagent.common.version import AGENT_NAME, AGENT_LONG_VERSION, \
DISTRO_NAME, DISTRO_VERSION, \
PY_VERSION_MAJOR, PY_VERSION_MINOR, \
PY_VERSION_MICRO, GOAL_STATE_AGENT_VERSION


class Agent(object):
Expand All @@ -49,17 +51,17 @@ def __init__(self, verbose, conf_file_path=None):
self.conf_file_path = conf_file_path
self.osutil = get_osutil()

#Init stdout log
# Init stdout log
level = logger.LogLevel.VERBOSE if verbose else logger.LogLevel.INFO
logger.add_logger_appender(logger.AppenderType.STDOUT, level)

#Init config
# Init config
conf_file_path = self.conf_file_path \
if self.conf_file_path is not None \
else self.osutil.get_agent_conf_file_path()
conf.load_conf_from_file(conf_file_path)

#Init log
# Init log
verbose = verbose or conf.get_logs_verbose()
level = logger.LogLevel.VERBOSE if verbose else logger.LogLevel.INFO
logger.add_logger_appender(logger.AppenderType.FILE, level,
Expand Down Expand Up @@ -104,7 +106,6 @@ def daemon(self):
child_args = None \
if self.conf_file_path is None \
else "-configuration-path:{0}".format(self.conf_file_path)

from azurelinuxagent.daemon import get_daemon_handler
daemon_handler = get_daemon_handler()
daemon_handler.run(child_args=child_args)
Expand Down Expand Up @@ -151,6 +152,22 @@ def show_configuration(self):
for k in sorted(configuration.keys()):
print("{0} = {1}".format(k, configuration[k]))

def collect_logs(self, is_full_mode):
if is_full_mode:
print("Running log collector mode full")
else:
print("Running log collector mode normal")

try:
log_collector = LogCollector(is_full_mode)
archive = log_collector.collect_logs_and_get_archive()
print("Log collection successfully completed. Archive can be found at {0} "
"and detailed log output can be found at {1}".format(archive, OUTPUT_RESULTS_FILE_PATH))
except Exception as e: # pylint: disable=C0103
print("Log collection completed unsuccessfully. Error: {0}".format(ustr(e)))
print("Detailed log output can be found at {0}".format(OUTPUT_RESULTS_FILE_PATH))
sys.exit(1)


def main(args=[]): # pylint: disable=R0912,W0102
"""
Expand All @@ -159,7 +176,7 @@ def main(args=[]): # pylint: disable=R0912,W0102
"""
if len(args) <= 0: # pylint: disable=len-as-condition
args = sys.argv[1:]
command, force, verbose, debug, conf_file_path = parse_args(args)
command, force, verbose, debug, conf_file_path, log_collector_full_mode = parse_args(args)
if command == "version":
version()
elif command == "help":
Expand All @@ -183,11 +200,14 @@ def main(args=[]): # pylint: disable=R0912,W0102
agent.run_exthandlers(debug)
elif command == "show-configuration":
agent.show_configuration()
elif command == "collect-logs":
pgombar marked this conversation as resolved.
Show resolved Hide resolved
agent.collect_logs(log_collector_full_mode)
except Exception:
logger.error(u"Failed to run '{0}': {1}",
command,
traceback.format_exc())


def parse_args(sys_args): # pylint: disable=R0912
"""
Parse command line arguments
Expand All @@ -197,45 +217,50 @@ def parse_args(sys_args): # pylint: disable=R0912
verbose = False
debug = False
conf_file_path = None
for a in sys_args: # pylint: disable=C0103
m = re.match("^(?:[-/]*)configuration-path:([\w/\.\-_]+)", a) # pylint: disable=W1401,C0103
log_collector_full_mode = False

for arg in sys_args:
m = re.match("^(?:[-/]*)configuration-path:([\w/\.\-_]+)", arg) # pylint: disable=W1401,C0103
if not m is None:
conf_file_path = m.group(1)
if not os.path.exists(conf_file_path):
print("Error: Configuration file {0} does not exist".format(
conf_file_path), file=sys.stderr)
usage()
print(usage())
sys.exit(1)
pgombar marked this conversation as resolved.
Show resolved Hide resolved

elif re.match("^([-/]*)deprovision\\+user", a):
elif re.match("^([-/]*)deprovision\\+user", arg):
cmd = "deprovision+user"
elif re.match("^([-/]*)deprovision", a):
elif re.match("^([-/]*)deprovision", arg):
cmd = "deprovision"
elif re.match("^([-/]*)daemon", a):
elif re.match("^([-/]*)daemon", arg):
cmd = "daemon"
elif re.match("^([-/]*)start", a):
elif re.match("^([-/]*)start", arg):
cmd = "start"
elif re.match("^([-/]*)register-service", a):
elif re.match("^([-/]*)register-service", arg):
cmd = "register-service"
elif re.match("^([-/]*)run-exthandlers", a):
elif re.match("^([-/]*)run-exthandlers", arg):
cmd = "run-exthandlers"
elif re.match("^([-/]*)version", a):
elif re.match("^([-/]*)version", arg):
cmd = "version"
elif re.match("^([-/]*)verbose", a):
elif re.match("^([-/]*)verbose", arg):
verbose = True
elif re.match("^([-/]*)debug", a):
elif re.match("^([-/]*)debug", arg):
debug = True
elif re.match("^([-/]*)force", a):
elif re.match("^([-/]*)force", arg):
force = True
elif re.match("^([-/]*)show-configuration", a):
elif re.match("^([-/]*)show-configuration", arg):
cmd = "show-configuration"
elif re.match("^([-/]*)(help|usage|\\?)", a):
elif re.match("^([-/]*)(help|usage|\\?)", arg):
cmd = "help"
elif re.match("^([-/]*)collect-logs", arg):
cmd = "collect-logs"
elif re.match("^([-/]*)full", arg):
log_collector_full_mode = True
else:
cmd = "help"
break

return cmd, force, verbose, debug, conf_file_path
return cmd, force, verbose, debug, conf_file_path, log_collector_full_mode


def version():
Expand All @@ -250,6 +275,7 @@ def version():
PY_VERSION_MICRO))
print("Goal state agent: {0}".format(GOAL_STATE_AGENT_VERSION))


def usage():
"""
Return agent usage message
Expand All @@ -258,11 +284,12 @@ def usage():
s += ("usage: {0} [-verbose] [-force] [-help] " # pylint: disable=C0103
"-configuration-path:<path to configuration file>"
"-deprovision[+user]|-register-service|-version|-daemon|-start|"
"-run-exthandlers|-show-configuration]"
"-run-exthandlers|-show-configuration|-collect-logs [-full]"
"").format(sys.argv[0])
s += "\n" # pylint: disable=C0103
return s


def start(conf_file_path=None):
"""
Start agent daemon in a background process and set stdout/stderr to
Expand All @@ -274,5 +301,6 @@ def start(conf_file_path=None):
args.append('-configuration-path:{0}'.format(conf_file_path))
subprocess.Popen(args, stdout=devnull, stderr=devnull)


if __name__ == '__main__' :
main()
7 changes: 4 additions & 3 deletions azurelinuxagent/common/cgroupapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
VM_AGENT_CGROUP_NAME = "walinuxagent.service"
EXTENSIONS_ROOT_CGROUP_NAME = "walinuxagent.extensions"
UNIT_FILES_FILE_SYSTEM_PATH = "/etc/systemd/system"
SYSTEMD_RUN_PATH = "/run/systemd/system/"


class CGroupsApi(object):
Expand Down Expand Up @@ -94,15 +95,15 @@ def create():
"""
Factory method to create the correct API for the current platform
"""
return SystemdCgroupsApi() if CGroupsApi._is_systemd() else FileSystemCgroupsApi()
return SystemdCgroupsApi() if CGroupsApi.is_systemd() else FileSystemCgroupsApi()

@staticmethod
def _is_systemd():
def is_systemd():
"""
Determine if systemd is managing system services; the implementation follows the same strategy as, for example,
sd_booted() in libsystemd, or /usr/sbin/service
"""
return os.path.exists('/run/systemd/system/')
return os.path.exists(SYSTEMD_RUN_PATH)

@staticmethod
def _foreach_controller(operation, message):
Expand Down
18 changes: 16 additions & 2 deletions azurelinuxagent/common/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ def load_conf_from_file(conf_file_path, conf=__conf__):
"OS.CheckRdmaDriver": False,
"Logs.Verbose": False,
"Logs.Console": True,
"Logs.Collect": False,
pgombar marked this conversation as resolved.
Show resolved Hide resolved
"Extensions.Enabled": True,
"Provisioning.AllowResetSysUser": False,
"Provisioning.RegenerateSshHostKeyPair": False,
Expand Down Expand Up @@ -149,7 +150,8 @@ def load_conf_from_file(conf_file_path, conf=__conf__):
"Provisioning.PasswordCryptSaltLength": 10,
"HttpProxy.Port": None,
"ResourceDisk.SwapSizeMB": 0,
"Autoupdate.Frequency": 3600
"Autoupdate.Frequency": 3600,
"Logs.CollectPeriod": 3600
}


Expand Down Expand Up @@ -223,6 +225,14 @@ def get_logs_console(conf=__conf__):
return conf.get_switch("Logs.Console", True)


def get_collect_logs(conf=__conf__):
return conf.get_switch("Logs.Collect", False)


def get_collect_logs_period(conf=__conf__):
return conf.get_int("Logs.CollectPeriod", 3600)
larohra marked this conversation as resolved.
Show resolved Hide resolved


def get_lib_dir(conf=__conf__):
return conf.get("Lib.Dir", "/var/lib/waagent")

Expand Down Expand Up @@ -374,9 +384,11 @@ def get_password_crypt_salt_len(conf=__conf__):
def get_monitor_hostname(conf=__conf__):
return conf.get_switch("Provisioning.MonitorHostName", False)


def get_monitor_hostname_period(conf=__conf__):
return conf.get_int("Provisioning.MonitorHostNamePeriod", 30)


def get_httpproxy_host(conf=__conf__):
return conf.get("HttpProxy.Host", None)

Expand All @@ -395,10 +407,12 @@ def get_resourcedisk_format(conf=__conf__):

def get_resourcedisk_enable_swap(conf=__conf__):
return conf.get_switch("ResourceDisk.EnableSwap", False)



def get_resourcedisk_enable_swap_encryption(conf=__conf__):
return conf.get_switch("ResourceDisk.EnableSwapEncryption", False)


def get_resourcedisk_mountpoint(conf=__conf__):
return conf.get("ResourceDisk.MountPoint", "/mnt/resource")

Expand Down
1 change: 1 addition & 0 deletions azurelinuxagent/common/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ class WALAEventOperation: # pylint: disable=R0903,no-init
InitializeHostPlugin = "InitializeHostPlugin"
InvokeCommandUsingSystemd = "InvokeCommandUsingSystemd"
Log = "Log"
LogCollection = "LogCollection"
OSInfo = "OSInfo"
Partition = "Partition"
PluginSettingsVersionMismatch = "PluginSettingsVersionMismatch"
Expand Down
Loading