Support log tail/save for instance
Support to show log content and save instance log files: openstack database log tail [--lines LINES] <instance> <log_name> openstack database log save [--file FILE] <instance> <log_name> Change-Id: I2a4eecca663f9126f770fae4c4be28b3667f91c4
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Support to show log content and save instance log files:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
openstack database log tail [--lines LINES] <instance> <log_name>
|
||||
openstack database log save [--file FILE] <instance> <log_name>
|
@@ -81,6 +81,8 @@ openstack.database.v1 =
|
||||
database_log_list = troveclient.osc.v1.database_logs:ListDatabaseLogs
|
||||
database_log_set = troveclient.osc.v1.database_logs:SetDatabaseInstanceLog
|
||||
database_log_show = troveclient.osc.v1.database_logs:ShowDatabaseInstanceLog
|
||||
database_log_tail = troveclient.osc.v1.database_logs:ShowDatabaseInstanceLogContents
|
||||
database_log_save = troveclient.osc.v1.database_logs:SaveDatabaseInstanceLog
|
||||
database_quota_show = troveclient.osc.v1.database_quota:ShowDatabaseQuota
|
||||
database_quota_update = troveclient.osc.v1.database_quota:UpdateDatabaseQuota
|
||||
database_root_disable = troveclient.osc.v1.database_root:DisableDatabaseRoot
|
||||
|
@@ -10,12 +10,13 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Database v1 Logs action implementations"""
|
||||
from __future__ import print_function
|
||||
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils as osc_utils
|
||||
import six
|
||||
|
||||
from troveclient import exceptions
|
||||
from troveclient.i18n import _
|
||||
|
||||
|
||||
@@ -134,3 +135,97 @@ class ShowDatabaseInstanceLog(command.ShowOne):
|
||||
result = log_info._info
|
||||
|
||||
return zip(*sorted(six.iteritems(result)))
|
||||
|
||||
|
||||
class ShowDatabaseInstanceLogContents(command.Command):
|
||||
_description = _("Show the content of log file.")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowDatabaseInstanceLogContents, self).get_parser(
|
||||
prog_name)
|
||||
parser.add_argument(
|
||||
'instance',
|
||||
metavar='<instance>',
|
||||
type=str,
|
||||
help=_('Id or Name of the instance.')
|
||||
)
|
||||
parser.add_argument(
|
||||
'log_name',
|
||||
metavar='<log_name>',
|
||||
type=str,
|
||||
help=_('Name of log to operate.')
|
||||
)
|
||||
parser.add_argument(
|
||||
'--lines', default=50, type=int,
|
||||
help="The number of log lines can be shown in batch.",
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
db_instances = self.app.client_manager.database.instances
|
||||
instance = osc_utils.find_resource(db_instances,
|
||||
parsed_args.instance)
|
||||
|
||||
try:
|
||||
log_gen = db_instances.log_generator(instance,
|
||||
parsed_args.log_name,
|
||||
lines=parsed_args.lines)
|
||||
for log_part in log_gen():
|
||||
print(log_part, end="")
|
||||
except exceptions.GuestLogNotFoundError:
|
||||
print(
|
||||
"ERROR: No published '%(log_name)s' log was found for "
|
||||
"%(instance)s" % {'log_name': parsed_args.log_name,
|
||||
'instance': instance}
|
||||
)
|
||||
except Exception as ex:
|
||||
error_msg = ex.message.split('\n')
|
||||
print(error_msg[0])
|
||||
|
||||
|
||||
class SaveDatabaseInstanceLog(command.Command):
|
||||
_description = _("Save the log file.")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(SaveDatabaseInstanceLog, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'instance',
|
||||
metavar='<instance>',
|
||||
type=str,
|
||||
help=_('Id or Name of the instance.')
|
||||
)
|
||||
parser.add_argument(
|
||||
'log_name',
|
||||
metavar='<log_name>',
|
||||
type=str,
|
||||
help=_('Name of log to operate.')
|
||||
)
|
||||
parser.add_argument(
|
||||
'--file',
|
||||
help="Path of file to save log to for instance.",
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
db_instances = self.app.client_manager.database.instances
|
||||
instance = osc_utils.find_resource(db_instances,
|
||||
parsed_args.instance)
|
||||
|
||||
try:
|
||||
filepath = db_instances.log_save(instance,
|
||||
parsed_args.log_name,
|
||||
filename=parsed_args.file)
|
||||
print(_('Log "%(log_name)s" written to %(file_name)s')
|
||||
% {'log_name': parsed_args.log_name,
|
||||
'file_name': filepath})
|
||||
except exceptions.GuestLogNotFoundError:
|
||||
print(
|
||||
"ERROR: No published '%(log_name)s' log was found for "
|
||||
"%(instance)s" % {'log_name': parsed_args.log_name,
|
||||
'instance': instance}
|
||||
)
|
||||
except Exception as ex:
|
||||
error_msg = ex.message.split('\n')
|
||||
print(error_msg[0])
|
||||
|
@@ -412,9 +412,9 @@ class Instances(base.ManagerWithFind):
|
||||
common.check_for_exceptions(resp, body, url)
|
||||
return DatastoreLog(self, body['log'], loaded=True)
|
||||
|
||||
def _get_container_info(self, instance, log_name, publish):
|
||||
def _get_container_info(self, instance, log_name):
|
||||
try:
|
||||
log_info = self.log_action(instance, log_name, publish=publish)
|
||||
log_info = self.log_show(instance, log_name)
|
||||
container = log_info.container
|
||||
prefix = log_info.prefix
|
||||
metadata_file = log_info.metafile
|
||||
@@ -424,33 +424,33 @@ class Instances(base.ManagerWithFind):
|
||||
raise exceptions.GuestLogNotFoundError()
|
||||
raise
|
||||
|
||||
def log_generator(self, instance, log_name, publish=None, lines=50,
|
||||
swift=None):
|
||||
def log_generator(self, instance, log_name, lines=50, swift=None):
|
||||
"""Return generator to yield the last <lines> lines of guest log.
|
||||
|
||||
:param instance: The :class:`Instance` (or its ID) of the database
|
||||
instance to get the log for.
|
||||
:param log_name: The name of <log> to publish
|
||||
:param publish: Publish updates before displaying log
|
||||
:param lines: Display last <lines> lines of log (0 for all lines)
|
||||
:param swift: Connection to swift
|
||||
:rtype: generator function to yield log as chunks.
|
||||
"""
|
||||
|
||||
if not swift:
|
||||
swift = self._get_swift_client()
|
||||
|
||||
def _log_generator(instance, log_name, publish, lines, swift):
|
||||
def _log_generator(instance, log_name, lines, swift):
|
||||
try:
|
||||
container, prefix, metadata_file = self._get_container_info(
|
||||
instance, log_name, publish)
|
||||
instance, log_name)
|
||||
|
||||
head, body = swift.get_container(container, prefix=prefix)
|
||||
log_obj_to_display = []
|
||||
|
||||
if lines:
|
||||
total_lines = lines
|
||||
partial_results = False
|
||||
parts = sorted(body, key=lambda obj: obj['last_modified'],
|
||||
reverse=True)
|
||||
|
||||
for part in parts:
|
||||
obj_hdrs = swift.head_object(container, part['name'])
|
||||
obj_lines = int(obj_hdrs['x-object-meta-lines'])
|
||||
@@ -461,13 +461,16 @@ class Instances(base.ManagerWithFind):
|
||||
lines -= obj_lines
|
||||
if not partial_results:
|
||||
lines = total_lines
|
||||
|
||||
part = log_obj_to_display.pop(0)
|
||||
hdrs, log_obj = swift.get_object(container, part['name'])
|
||||
log_by_lines = log_obj.decode().splitlines()
|
||||
yield "\n".join(log_by_lines[-1 * lines:]) + "\n"
|
||||
else:
|
||||
# Show all the logs
|
||||
log_obj_to_display = sorted(
|
||||
body, key=lambda obj: obj['last_modified'])
|
||||
|
||||
for log_part in log_obj_to_display:
|
||||
headers, log_obj = swift.get_object(container,
|
||||
log_part['name'])
|
||||
@@ -477,20 +480,19 @@ class Instances(base.ManagerWithFind):
|
||||
raise exceptions.GuestLogNotFoundError()
|
||||
raise
|
||||
|
||||
return lambda: _log_generator(instance, log_name, publish,
|
||||
lines, swift)
|
||||
return lambda: _log_generator(instance, log_name, lines, swift)
|
||||
|
||||
def log_save(self, instance, log_name, publish=None, filename=None):
|
||||
def log_save(self, instance, log_name, filename=None):
|
||||
"""Saves a guest log to a file.
|
||||
|
||||
:param instance: The :class:`Instance` (or its ID) of the database
|
||||
instance to get the log for.
|
||||
:param log_name: The name of <log> to publish
|
||||
:param publish: Publish updates before displaying log
|
||||
:rtype: Filename to which log was saved
|
||||
"""
|
||||
written_file = filename or (instance.name + '-' + log_name + ".log")
|
||||
log_gen = self.log_generator(instance, log_name, publish, 0)
|
||||
written_file = filename or (
|
||||
'trove-' + instance.id + '-' + log_name + ".log")
|
||||
log_gen = self.log_generator(instance, log_name, lines=0)
|
||||
with open(written_file, 'w') as f:
|
||||
for log_obj in log_gen():
|
||||
f.write(log_obj)
|
||||
|
@@ -2292,8 +2292,6 @@ def do_log_discard(cs, args):
|
||||
@utils.arg('instance', metavar='<instance>',
|
||||
help=_('Id or Name of the instance.'))
|
||||
@utils.arg('log_name', metavar='<log_name>', help=_('Name of log to publish.'))
|
||||
@utils.arg('--publish', action='store_true', default=False,
|
||||
help=_('Publish latest entries from guest before display.'))
|
||||
@utils.arg('--lines', metavar='<lines>', default=50, type=int,
|
||||
help=_('Publish latest entries from guest before display.'))
|
||||
@utils.service_type('database')
|
||||
@@ -2302,7 +2300,7 @@ def do_log_tail(cs, args):
|
||||
try:
|
||||
instance = _find_instance(cs, args.instance)
|
||||
log_gen = cs.instances.log_generator(instance, args.log_name,
|
||||
args.publish, args.lines)
|
||||
args.lines)
|
||||
for log_part in log_gen():
|
||||
print(log_part, end="")
|
||||
except exceptions.GuestLogNotFoundError:
|
||||
@@ -2316,8 +2314,6 @@ def do_log_tail(cs, args):
|
||||
@utils.arg('instance', metavar='<instance>',
|
||||
help=_('Id or Name of the instance.'))
|
||||
@utils.arg('log_name', metavar='<log_name>', help=_('Name of log to publish.'))
|
||||
@utils.arg('--publish', action='store_true', default=False,
|
||||
help=_('Publish latest entries from guest before display.'))
|
||||
@utils.arg('--file', metavar='<file>', default=None,
|
||||
help=_('Path of file to save log to for instance.'))
|
||||
@utils.service_type('database')
|
||||
@@ -2326,7 +2322,7 @@ def do_log_save(cs, args):
|
||||
try:
|
||||
instance = _find_instance(cs, args.instance)
|
||||
filename = cs.instances.log_save(instance, args.log_name,
|
||||
args.publish, args.file)
|
||||
filename=args.file)
|
||||
print(_('Log "%(log_name)s" written to %(file_name)s')
|
||||
% {'log_name': args.log_name,
|
||||
'file_name': filename})
|
||||
|
Reference in New Issue
Block a user