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

[rqd] [cuegui] Consolidate log read and write into a single package #1474

Draft
wants to merge 44 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
e840254
Remove rqd.compiled_proto and use from opencue.compiled_proto instead.
lithorus Aug 14, 2024
641e74d
Move RQDLogger into opencue.cuelogging
lithorus Aug 14, 2024
4612cc0
Replace LogViewPlugin.LogReader with opencue.cuelogging.CueLogger
lithorus Aug 14, 2024
9a7742f
Small change to default mode
lithorus Aug 14, 2024
2d59cd9
Merge branch 'master' into consolidate-logger
lithorus Aug 14, 2024
d87dacb
Remove rqd/compiled_proto from tests and documentation
lithorus Aug 14, 2024
eebc594
Merge remote-tracking branch 'lithorus/consolidate-logger' into conso…
lithorus Aug 14, 2024
c27b608
Remove rqd/compiled_proto from tests and documentation
lithorus Aug 14, 2024
beaf975
Some linting fixes
lithorus Aug 14, 2024
d13e589
Fix more tests
lithorus Aug 14, 2024
9027437
Fix linting
lithorus Aug 14, 2024
b4d3638
Add documentation to new parameters
lithorus Aug 14, 2024
8c9944b
Removed unused type attribute
lithorus Aug 14, 2024
8873acd
Add small comment about default mode
lithorus Aug 14, 2024
55aeb7a
Merge branch 'AcademySoftwareFoundation:master' into consolidate-logger
lithorus Aug 16, 2024
fa4eec9
Merge branch 'master' into consolidate-logger
DiegoTavares Aug 20, 2024
958e462
Split log reading and writing into separate classes
lithorus Aug 20, 2024
9c38c8d
Split up init of CueLogWriter into smaller functions and internalize …
lithorus Aug 20, 2024
84d0462
Make CueLogReader.filepath public and raise IOError if file doesn't e…
lithorus Aug 20, 2024
b3e6370
Remove file handler creation in CueLogReader.__init__()
lithorus Aug 20, 2024
b7a8648
Merge branch 'AcademySoftwareFoundation:master' into consolidate-logger
lithorus Sep 6, 2024
46fc54b
Merge remote-tracking branch 'origin/master' into consolidate-logger
lithorus Sep 11, 2024
956a58d
Move cuelogging into separate package so the compiled_prot can be dup…
lithorus Sep 11, 2024
a7f3445
Re-duplicate compiled_proto into rqd again and update test
lithorus Sep 11, 2024
d10d012
Fix linting and test scripts
lithorus Sep 11, 2024
6253fae
Small type fix to the pyside6 test
lithorus Sep 11, 2024
fde5d48
Split cuelogging into separate files/modules
lithorus Sep 11, 2024
59b6b71
Fix linting of the new proto modules
lithorus Sep 11, 2024
c524aa1
More fixes to the linting
lithorus Sep 11, 2024
d6a3310
Small change to coverage
lithorus Sep 11, 2024
5384013
Revert changes for proto/README.md
lithorus Sep 11, 2024
21b56c3
Revert changes
lithorus Sep 11, 2024
3e31bd0
Merge branch 'master' into consolidate-logger
lithorus Sep 19, 2024
39c5782
Fix logger in CueLogWriter.py
lithorus Sep 19, 2024
1a6fc3a
Merge remote-tracking branch 'origin/master' into consolidate-logger
lithorus Oct 1, 2024
143f93b
Merge branch 'master' into consolidate-logger
DiegoTavares Oct 9, 2024
c1d344d
Add coverage report temporarily to check if it works
lithorus Oct 9, 2024
af5648f
Add pycue to pythonpath when testing rqd
lithorus Oct 9, 2024
ed212de
Dummy change to force CI to run again
lithorus Oct 9, 2024
c2efce6
Remove temporary test
lithorus Oct 9, 2024
b57323a
Merge remote-tracking branch 'origin/master' into consolidate-logger
lithorus Oct 15, 2024
5ff0959
Merge remote-tracking branch 'origin/master' into consolidate-logger
lithorus Nov 4, 2024
061de53
Merge remote-tracking branch 'origin/master' into consolidate-logger
lithorus Nov 5, 2024
6527d93
Add pycue to rqd tests
lithorus Nov 5, 2024
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
2 changes: 2 additions & 0 deletions ci/build_sphinx_docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ pip install --user -r requirements.txt -r docs/requirements.txt

# Must generate Python code from Protos in order for Sphinx to build the docs.
python -m grpc_tools.protoc -I=proto/ --python_out=pycue/opencue/compiled_proto --grpc_python_out=pycue/opencue/compiled_proto proto/*.proto
python -m grpc_tools.protoc -I=proto/ --python_out=rqd/rqd/compiled_proto --grpc_python_out=rqd/rqd/compiled_proto proto/*.proto

# Fix imports to work in both Python 2 and 3. See
# <https://github.com/protocolbuffers/protobuf/issues/1491> for more info.
2to3 -wn -f import pycue/opencue/compiled_proto/*_pb2*.py
2to3 -wn -f import rqd/rqd/compiled_proto/*_pb2*.py

# Build the docs and treat warnings as errors
~/.local/bin/sphinx-build -W -b html -d docs/_build/doctrees docs docs/_build/html
14 changes: 9 additions & 5 deletions ci/pylintrc_main
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,15 @@ ignored-classes=optparse.Values,thread._local,_thread._local
# and thus existing member attributes cannot be deduced by static analysis). It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=opencue.compiled_proto,
opencue.compiled_proto.filter_pb2,
opencue.compiled_proto.host_pb2,
rqd.compiled_proto.rqd_pb2,
rqd.compiled_proto.host_pb2,
rqd.compiled_proto.report_pb2
opencue.compiled_proto.filter_pb2,
opencue.compiled_proto.host_pb2,
opencue.compiled_proto.rqd_pb2,
opencue.compiled_proto.report_pb2,
rqd.compiled_proto,
rqd.compiled_proto.filter_pb2,
rqd.compiled_proto.host_pb2,
rqd.compiled_proto.rqd_pb2,
rqd.compiled_proto.report_pb2

# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
Expand Down
6 changes: 5 additions & 1 deletion ci/pylintrc_test
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,12 @@ ignored-classes=optparse.Values,thread._local,_thread._local
ignored-modules=opencue.compiled_proto,
opencue.compiled_proto.filter_pb2,
opencue.compiled_proto.host_pb2,
rqd.compiled_proto.rqd_pb2,
opencue.compiled_proto.rqd_pb2,
opencue.compiled_proto.report_pb2,
rqd.compiled_proto,
rqd.compiled_proto.filter_pb2,
rqd.compiled_proto.host_pb2,
rqd.compiled_proto.rqd_pb2,
rqd.compiled_proto.report_pb2

# Show a hint with possible names when a member name was not found. The aspect
Expand Down
4 changes: 2 additions & 2 deletions ci/run_python_lint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ cd ..

echo "Running lint for rqd/..."
cd rqd
python -m pylint --rcfile=../ci/pylintrc_main rqd --ignore=rqd/compiled_proto
python -m pylint --rcfile=../ci/pylintrc_test tests
PYTHONPATH=../pycue python -m pylint --rcfile=../ci/pylintrc_main rqd --ignore=rqd/compiled_proto
PYTHONPATH=../pycue python -m pylint --rcfile=../ci/pylintrc_test tests
cd ..
2 changes: 1 addition & 1 deletion ci/run_python_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ python pycue/setup.py test
PYTHONPATH=pycue python pyoutline/setup.py test
PYTHONPATH=pycue python cueadmin/setup.py test
PYTHONPATH=pycue:pyoutline python cuesubmit/setup.py test
python rqd/setup.py test
PYTHONPATH=pycue python rqd/setup.py test

# Xvfb no longer supports Python 2.
if [[ "$python_version" =~ "Python 3" && ${args[0]} != "--no-gui" ]]; then
Expand Down
41 changes: 2 additions & 39 deletions cuegui/cuegui/plugins/LogViewPlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

from builtins import str
from builtins import range
import os
import re
import string
import sys
Expand All @@ -33,53 +32,17 @@
from qtpy import QtCore
from qtpy import QtWidgets

import cuelogging
import cuegui.Constants
import cuegui.AbstractDockWidget


PLUGIN_NAME = 'LogView'
PLUGIN_CATEGORY = 'Other'
PLUGIN_DESCRIPTION = 'Displays Frame Log'
PLUGIN_PROVIDES = 'LogViewPlugin'
PRINTABLE = set(string.printable)


class LogReader(object):
"""
Custom class to abstract reading log files from multiple backends
"""
filepath = None
type = None

def __init__(self, filepath):
"""LogReader class initialization
@type filepath: string
@param filepath: The filepath to log to
"""
self.filepath = filepath

def size(self):
"""Return the size of the file"""
return int(os.stat(self.filepath).st_size)

def getMtime(self):
"""Return modification time of the file"""
return os.path.getmtime(self.filepath)

def exists(self):
"""Check if the file exists"""
return os.path.exists(self.filepath)

def read(self):
"""Read the data from the backend"""
content = None
if self.exists() is True:
with open(self.filepath, "r", encoding='utf-8') as fp:
content = fp.read()

return content


class LineNumberArea(QtWidgets.QWidget):
"""
Custom widget for the line numbers. This widget is designed to be attached
Expand Down Expand Up @@ -850,7 +813,7 @@ def _display_log_content(self):
@postcondition: The _update_log method is scheduled to run again
after 5 seconds
"""
log_reader = LogReader(self._log_file)
log_reader = cuelogging.CueLogReader(self._log_file)

try:
if log_reader.exists() is not True:
Expand Down
59 changes: 59 additions & 0 deletions pycue/cuelogging/CueLogReader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Copyright Contributors to the OpenCue Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Module for reading files"""

import os

class CueLogReader(object):
"""Class to abstract file log reading, this class tries to act as a file object"""

filepath = None

def __init__(self, filepath):
"""CueLogWriter class initialization
@type filepath: string
@param filepath: The filepath to log to
"""
self.filepath = filepath

def size(self):
"""Return the size of the file"""
return int(os.stat(self.filepath).st_size)

def getMtime(self):
"""Return modification time of the file"""
return os.path.getmtime(self.filepath)

def exists(self):
"""Check if the file exists"""
return os.path.exists(self.filepath)

def read(self):
"""Read the data from the backend"""

content = None
if self.exists() is True:
with open(self.filepath, "r", encoding='utf-8') as fp:
content = fp.read()
else:
raise IOError("Failed to open %s" % self.filepath)

return content

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
pass
88 changes: 42 additions & 46 deletions rqd/rqd/rqlogging.py → pycue/cuelogging/CueLogWriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,64 +12,56 @@
# See the License for the specific language governing permissions and
# limitations under the License.


"""Logging module, handles logging to files and non-files"""

"""Module for writing files"""

import logging
import time
import os
import datetime
import platform

import rqd.rqconstants
import datetime
import time

log = logging.getLogger(__name__)
log.setLevel(rqd.rqconstants.CONSOLE_LOG_LEVEL)

class CueLogWriter(object):
"""Class to abstract file log writing, this class tries to act as a file object"""

class RqdLogger(object):
"""Class to abstract file logging, this class tries to act as a file object"""
filepath = None
fd = None
type = 0

def __init__(self, filepath):
"""RQDLogger class initialization
def __init__(self, filepath, maxLogFiles=1):
"""CueLogWriter class initialization
@type filepath: string
@param filepath: The filepath to log to
@type maxLogFiles: int
@param maxLogFiles: number of files to rotate, when in write mode
"""

self.filepath = filepath
self.__log_dir = os.path.dirname(self.filepath)
self.__maxLogFiles = maxLogFiles
if not os.access(self.__log_dir, os.F_OK):
self.__makeLogDir()

log_dir = os.path.dirname(self.filepath)
if not os.access(log_dir, os.F_OK):
# Attempting mkdir for missing logdir
msg = "No Error"
try:
os.makedirs(log_dir)
os.chmod(log_dir, 0o777)
# pylint: disable=broad-except
except Exception as e:
# This is expected to fail when called in abq
# But the directory should now be visible
msg = e

if not os.access(log_dir, os.F_OK):
err = "Unable to see log directory: %s, mkdir failed with: %s" % (
log_dir, msg)
raise RuntimeError(err)

if not os.access(log_dir, os.W_OK):
err = "Unable to write to log directory %s" % log_dir
if not os.access(self.__log_dir, os.W_OK):
err = "Unable to write to log directory %s" % self.__log_dir
raise RuntimeError(err)

self.__attemptRotateLogs()
# pylint: disable=consider-using-with
self.__fd = open(self.filepath, "w+", 1, encoding='utf-8')
try:
os.chmod(self.filepath, 0o666)
# pylint: disable=broad-except
except Exception as e:
err = "Failed to chmod log file! %s due to %s" % (self.filepath, e)
log.warning(err)

def __attemptRotateLogs(self):
try:
# Rotate any old logs to a max of MAX_LOG_FILES:
if os.path.isfile(self.filepath):
rotateCount = 1
while (os.path.isfile("%s.%s" % (self.filepath, rotateCount))
and rotateCount < rqd.rqconstants.MAX_LOG_FILES):
and rotateCount < self.__maxLogFiles):
rotateCount += 1
os.rename(self.filepath,
"%s.%s" % (self.filepath, rotateCount))
Expand All @@ -83,14 +75,22 @@ def __init__(self, filepath):
log.warning(err)
else:
raise RuntimeError(err)
# pylint: disable=consider-using-with
self.fd = open(self.filepath, "w+", 1, encoding='utf-8')

def __makeLogDir(self):
# Attempting mkdir for missing logdir
msg = "No Error"
try:
os.chmod(self.filepath, 0o666)
os.makedirs(self.__log_dir)
os.chmod(self.__log_dir, 0o777)
# pylint: disable=broad-except
except Exception as e:
err = "Failed to chmod log file! %s due to %s" % (self.filepath, e)
log.warning(err)
# This is expected to fail when called in abq
# But the directory should now be visible
msg = e

if not os.access(self.__log_dir, os.F_OK):
err = "Unable to see log directory: %s, mkdir failed with: %s" % (self.__log_dir, msg)
raise RuntimeError(err)

# pylint: disable=arguments-differ
def write(self, data, prependTimestamp=False):
Expand All @@ -104,7 +104,7 @@ def write(self, data, prependTimestamp=False):
for line in lines:
print("[%s] %s" % (curr_line_timestamp, line), file=self)
else:
self.fd.write(data)
self.__fd.write(data)

def writelines(self, __lines):
"""Provides support for writing mutliple lines at a time"""
Expand All @@ -113,7 +113,7 @@ def writelines(self, __lines):

def close(self):
"""Closes the file if the backend is file based"""
self.fd.close()
self.__fd.close()

def waitForFile(self, maxTries=5):
"""Waits for the file to exist before continuing when using a file backend"""
Expand All @@ -126,8 +126,4 @@ def waitForFile(self, maxTries=5):
time.sleep(0.5 * tries)
raise IOError("Failed to create %s" % self.filepath)

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
pass
19 changes: 19 additions & 0 deletions pycue/cuelogging/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright Contributors to the OpenCue Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


"""Package for reading and writing log files"""

from .CueLogReader import CueLogReader
from .CueLogWriter import CueLogWriter
7 changes: 5 additions & 2 deletions rqd/rqd/rqcore.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import traceback
import select

import cuelogging
import rqd.compiled_proto.host_pb2
import rqd.compiled_proto.report_pb2
import rqd.rqconstants
Expand All @@ -44,7 +45,6 @@
import rqd.rqnetwork
import rqd.rqnimby
import rqd.rqutil
import rqd.rqlogging

INT32_MAX = 2147483647
INT32_MIN = -2147483648
Expand Down Expand Up @@ -490,7 +490,10 @@ def run(self):

# Setup frame logging
try:
self.rqlog = rqd.rqlogging.RqdLogger(runFrame.log_dir_file)
self.rqlog = cuelogging.CueLogWriter(
runFrame.log_dir_file,
maxLogFiles=rqd.rqconstants.MAX_LOG_FILES
)
self.rqlog.waitForFile()
# pylint: disable=broad-except
except Exception as e:
Expand Down
Loading