Robot Framework Integrated Development Environment (RIDE)
parserlog.py
Go to the documentation of this file.
1 # Copyright 2019- Robot Framework Foundation
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import atexit
16 import glob
17 import io
18 import os
19 import sys
20 import tempfile
21 import uuid
22 
23 import wx
24 from wx import Colour
25 
26 from .. import context
27 from .. import widgets
28 from ..pluginapi import Plugin
29 from ..action import ActionInfo
30 from ..publish.messages import RideParserLogMessage
31 from ..widgets import RIDEDialog
32 
34  return '%s [%s]: %s\n\n' % (msg.timestamp, msg.level, msg.message.replace('\n\t', ''))
35 
36 
37 
38 class ParserLogPlugin(Plugin):
39 
40  def __init__(self, app):
41  Plugin.__init__(self, app, default_settings={
42  'log_to_console': False,
43  'log_to_file': True
44  })
45  self._log_log = []
46  self._panel_panel = None
47  self._path_path = os.path.join(
48  tempfile.gettempdir(), '{}-ride_parser.log'.format(uuid.uuid4()))
49  self._outfile_outfile = None
50  self._remove_old_log_files_remove_old_log_files()
51  atexit.register(self._close_close)
52 
53  def _close(self):
54  if self._outfile_outfile is not None:
55  self._outfile_outfile.close()
56 
58  for fname in glob.glob(
59  os.path.join(tempfile.gettempdir(), '*-ride_parser.log')):
60  try:
61  os.remove(fname)
62  except OSError or IOError or PermissionError as e:
63  sys.stderr.write(f"Removing old *-ride_parser.log files failed with: {repr(e)}\n")
64  finally:
65  pass
66 
67  @property
68  _logfile = property
69 
70  def _logfile(self):
71  if self._outfile_outfile is None:
72  self._outfile_outfile = io.open(self._path_path, 'w', encoding='utf8')
73  return self._outfile_outfile
74 
75  def enable(self):
76  self._create_menu_create_menu()
77  self.subscribe(self._log_message_log_message, RideParserLogMessage)
78 
79  def disable(self):
80  self.unsubscribe_all()
81  self.unregister_actions()
82  if self._panel_panel:
83  self._panel_panel.close(self.notebook)
84 
85  def _create_menu(self):
86  self.unregister_actions()
87  self.register_action(ActionInfo(
88  'Tools', 'View Parser Log', self.OnViewLogOnViewLog, position=83))
89 
90  def _log_message(self, message):
91  self._log_log.append(message)
92  if self._panel_panel:
93  self._panel_panel.update_log()
94  if self.log_to_console:
95  print("".format(_message_to_string(message))) # >> sys.stdout, _message_to_string(message)
96  if self.log_to_file:
97  self._logfile_logfile_logfile.write(_message_to_string(message))
98  self._outfile_outfile.flush()
99  if message.notify_user:
100  font_size = 13 if context.IS_MAC else -1
101  widgets.HtmlDialog(message.level, message.message,
102  padding=10, font_size=font_size).Show()
103  self.OnViewLogOnViewLog(message, show_tab=False)
104 
105  def OnViewLog(self, event, show_tab=True):
106  if not self._panel_panel:
107  self._panel_panel = _LogWindow(self.notebook, self._log_log)
108  self.notebook.SetPageTextColour(self.notebook.GetPageCount()-1, wx.Colour(255, 165, 0))
109  self._panel_panel.update_log()
110  self.register_shortcut('CtrlCmd-C', lambda e: self._panel_panel.Copy())
111  if show_tab:
112  self.notebook.show_tab(self._panel_panel)
113 
114 
115 class _LogWindow(wx.Panel):
116 
117  def __init__(self, notebook, log):
118  wx.Panel.__init__(self, notebook)
119  self.dlgdlg = RIDEDialog()
120  self._output_output = wx.TextCtrl(self, style=wx.TE_READONLY | wx.TE_MULTILINE | wx.TE_NOHIDESEL)
121  self._output_output.SetBackgroundColour(Colour(self.dlgdlg.color_background))
122  self._output_output.SetForegroundColour(Colour(self.dlgdlg.color_foreground))
123  self._output_output.Bind(wx.EVT_KEY_DOWN, self.OnKeyDownOnKeyDown)
124  self._log_log = log
125  self._notebook_notebook = notebook
126  self._add_to_notebook_add_to_notebook(notebook)
127  self.SetFont(widgets.Font().fixed_log)
128  self.Bind(wx.EVT_SIZE, self.OnSizeOnSize)
129 
130  def _add_to_notebook(self, notebook):
131  notebook.add_tab(self, 'Parser Log', allow_closing=True)
132  self._output_output.SetSize(self.Size)
133 
134  def close(self, notebook):
135  notebook.delete_tab(self)
136 
137  def _create_ui(self):
138  self.SetSizer(widgets.VerticalSizer())
139  self.Sizer.add_expanding(self._output_output)
140 
141  def update_log(self):
142  self._output_output.SetValue(self._decode_log_decode_log(self._log_log))
143 
144  def _decode_log(self, log):
145  result = ''
146  for msg in log:
147  result += _message_to_string(msg)
148  return result
149 
150  def OnSize(self, evt):
151  self._output_output.SetSize(self.Size)
152 
153  def OnKeyDown(self, event):
154  keycode = event.GetKeyCode()
155 
156  if event.ControlDown() and keycode == ord('A'):
157  self.SelectAllSelectAll()
158  else:
159  event.Skip()
160 
161  def Copy(self):
162  pass
163 
164  def SelectAll(self):
165  self._output.SetSelection(-1, -1)
Used to create menu entries, keyboard shortcuts and/or toolbar buttons.
Definition: actioninfo.py:176
Viewer for internal log messages.
Definition: parserlog.py:38
def OnViewLog(self, event, show_tab=True)
Definition: parserlog.py:105
def _add_to_notebook(self, notebook)
Definition: parserlog.py:130
def __init__(self, notebook, log)
Definition: parserlog.py:117
def write(msg, level='INFO', html=False)
Writes the message to the log file using the given level.
Definition: logger.py:86