-
Notifications
You must be signed in to change notification settings - Fork 27
Description
Output in USE 7.0
Before a new Shell can be integrated (see #5), it needs to be defined how output to the shell and to different logs should be done.
Currently (USE 7.0.1), there are different technqiues used to output information. These techniques are:
1. org.tzi.use.util.USEWriter
classDiagram-v2
class USEWriter {
-out:PrintStream
-noProtocolOut:PrintStream
-err:PrintStream
-log:ByteArrayOutputStream
-logWriter:PrintStream
-quietMode:boolean
+getOut():PrintStream
+getErr():PrintStream
+getProtocolOut():PrintStream
+protocol(line:String)
+writeProtocolFile(out:OutputStream)
+isQuietMode():boolean
+setQuietMode(quietMode:boolean)
+clearLog()
}
class LoggingOutputStreamDecorator {
-out:OutputStream
+write(b:int)
}
class OutputStream
OutputStream <|-- LoggingOutputStreamDecorator
USEWriter ..> LoggingOutputStreamDecorator: use
Description
The class USEWriter represents a singleton that logs output to an additional logWriter. This behaviour can be changed by setting the quiteModeflag. Further, the logWriter can be bypassed by using the original stream getNoProtocolOut().
It represents some kind of manager for the decorated streams and a data sink for all output of USE.
Functionality
- Log output to additional log-buffer
- Suppress output to default stream, but write to log-buffer by using
setQuietMode - Bypass log-buffer by using
getNoProtocolOut
Usage
The USEWriter itself is used for the default outputs System.out and System.err at the very beginning of main, to be able to record all outputs of USE.
The addtional functionality of USEWriter is used as follows:
- Log output to additional log-buffer: Used by
MainWindowto write a protocol to a file. - Suppress output: No usage found in USE or USE plugins
- Bypass log-buffer: No usage found in USE or USE plugins
2. org.tzi.use.util.Log
classDiagram-v2
class Log {
-fOut:PrintStream
-fErr:PrintStream
-fDbg:PrintStream
-fDateFormat:DateFormat
-fPrintTime:boolean
-showWarnings:boolean
-fDebug:boolean
-fVerbose:boolean
-fTrace:boolean
-fPrintStackTraces:boolean
-fDidOutput:boolean
+setShowWarnings(showWarnings:boolean)$
+isShowWarnings()$ boolean
+setDebug(onOff:boolean)$
+isDebug()$ boolean
+setVerbose(onOff:boolean)$
+isVerbose()$ boolean
+setTrace(onOff:boolean)$
+isTracing()$ boolean
+setPrintStackTrace(onOff:boolean)$
+isPrintStackTrace()$ boolean
+setPrintTime(onOff:boolean)$
+isPrintingTime()$ boolean
+resetOutputFlag()$
+out()$ PrintStream
+error(s:String)$
+error(location:Object, msg:String)$
+error(e:Exception)$
+error(s:String, e:Exception)$
+warn(string:String)$
+println(s:String)$
+print(s:String)$
+println()$
+debug(s:String)$
+verbose(s:String)$
+trace(msg:String)$
+trace(location:Object, msg:String)$
+trace(location:Object, msg:String, flush:boolean)$
}
Description
The class Log allows to separate between normal output, warning, errors and debug information. It is a static utility class.
Functionality
- Print errors
- Print warnings
- Print normal output
- Print debug information
- Print traces
- Print verbose information
- Output/suppress of exception stacktrace
- Can be queried if output was made (with reset functionality)
- Can print time information at beginning of normal output line
Inconsistencies
- Time information is only printed for normal output, not for other levels like warnings, errors, ...
- Normal output has
print,println(String),println(), all other levels not - Error output has location object, i. e, prints the classname of the object to "locate" the error. Other levels have not.
- Not all levels set
fDidOutput - Order of output is unclear. If debug messages are turned of, traces could still be printed out.
Usage
The class Log is used for different intensions:
- Providing output to the user supporting different levels of verbosity set by the user [OUT]
- Easing error handling (instead of throwing an exception, an error is logged) [ERR]
- Providing logging capabilities for USE developers [DEV]
While 1 and 3 are in my opinion valid usages, 2 isn't.
Log.println(String) is called from:
- org.tzi.use.config.Options OUT
Here, also the commanline optionsquietandcompileOnlyare queried. Should be considered in new version. - org.tzi.use.parser.shell.ShellCommandCompiler DEV
- org.tzi.use.main.shell.Shell OUT, ERR
- org.tzi.use.main.shell.ShellCoverageCommandProcessor OUT
Log.error(String) is called from 104 places in the following classes:
org.tzi.use.analysis.metrics.AbstractShellCommandProcessor (unused class?)deletedorg.tzi.use.analysis.metrics.GSMetricConfigurationdeleted- org.tzi.use.gen.tool.GGenerator OUT
Suppresses warnings globally by switching them ofLog.setShowWarnings(false);and restoring them afterwards.
This is a strong argument for passing an output object around instead of using a static logger class. - org.tzi.use.gen.tool.GGeneratorArguments OUT
- org.tzi.use.uml.ocl.extension.ExtensionManager OUT
- org.tzi.use.uml.ocl.extension.ExtensionOperation OUT
Uses a also a StringWriter to capture errors from Ruby execution. Is this really needed?ScriptContextof Ruby just uses aWriter. - org.tzi.use.uml.sys.DerivedLinkControllerDerivedEnd OUT
- org.tzi.use.uml.sys.MSystemState OUT
- org.tzi.use.main.Main OUT
- org.tzi.use.main.shell.HelpForCmd OUT
- org.tzi.use.main.shell.ReadlineStack ERR
- org.tzi.use.main.shell.Shell OUT, DEV, ERR
Uses also the functionality to reset the output flag:Log.resetOutputFlag();
However,Log.didOutput()is never called from USE. Maybe from plugins? - org.tzi.use.main.shell.ShellCoverageCommandProcessor OUT
- org.tzi.use.runtime.MainPluginRuntime
- org.tzi.use.runtime.gui.impl.PluginAction
- org.tzi.use.runtime.gui.impl.PluginActionDescriptor
- org.tzi.use.runtime.gui.impl.PluginActionProxy
- org.tzi.use.runtime.impl.Plugin
- org.tzi.use.runtime.impl.PluginDescriptor
- org.tzi.use.runtime.impl.PluginRuntime
- org.tzi.use.runtime.service.impl.PluginServiceDescriptor
- org.tzi.use.runtime.shell.impl.PluginShellCmd
- org.tzi.use.runtime.shell.impl.PluginShellCmdDescriptor
- org.tzi.use.runtime.util.ActionRegistry
- org.tzi.use.runtime.util.PluginParser
- org.tzi.use.runtime.util.PluginRegistry
- org.tzi.use.runtime.util.ServiceRegistry
- org.tzi.use.runtime.util.ShellCmdRegistry
Log.error(Object location, String msg) is called from 0 places
Log.error(Exception) is called from 3 places in the following classes:
- org.tzi.use.uml.ocl.expr.operations.Op_collection_max
- org.tzi.use.uml.ocl.expr.operations.Op_collection_min
- org.tzi.use.main.shell.ReadlineStack
Log.error(String s, Exception e) is called from 23 places in the following classes:
- org.tzi.use.runtime.gui.impl.PluginActionDescriptor
- org.tzi.use.runtime.impl.PluginDescriptor
- org.tzi.use.runtime.service.impl.PluginServiceDescriptor
- org.tzi.use.runtime.shell.impl.PluginShellCmdDescriptor
- org.tzi.use.runtime.util.PluginRegistry
Log.warn(String string) is called from 17 places in the following classes:
- org.tzi.use.uml.ocl.expr.ExpStdOp
- org.tzi.use.uml.ocl.extension.ExtensionManager
- org.tzi.use.uml.ocl.extension.ExtensionOperation
- org.tzi.use.uml.sys.MSystem
- org.tzi.use.uml.sys.MSystemState
- org.tzi.use.util.input.LineInput
- org.tzi.use.util.rubyintegration.RubyHelper
- org.tzi.use.main.shell.Shell
Log.debug(String) is called from 130 places in the following classes:
- org.tzi.use.uml.ocl.expr.ThreadedEvaluator.Controller
- org.tzi.use.uml.ocl.expr.ThreadedEvaluator.Worker
- org.tzi.use.uml.ocl.extension.ExtensionManager
- org.tzi.use.uml.sys.MSystemState
- org.tzi.use.gui.main.MainWindow
- org.tzi.use.main.Main
- org.tzi.use.runtime.MainPluginRuntime
- org.tzi.use.runtime.gui.impl.PluginAction
- org.tzi.use.runtime.gui.impl.PluginActionDescriptor
- org.tzi.use.runtime.gui.impl.PluginActionProxy
- org.tzi.use.runtime.gui.impl.PluginMMHTMLPrintVisitor
- org.tzi.use.runtime.gui.impl.PluginMMPrintVisitor
- org.tzi.use.runtime.impl.PluginDescriptor
- org.tzi.use.runtime.impl.PluginRuntime
- org.tzi.use.runtime.service.impl.PluginServiceDescriptor
- org.tzi.use.runtime.shell.impl.PluginShellCmd
- org.tzi.use.runtime.shell.impl.PluginShellCmdDescriptor
- org.tzi.use.runtime.shell.impl.ShellExtensionPoint
- org.tzi.use.runtime.util.ActionRegistry
- org.tzi.use.runtime.util.PluginParser
- org.tzi.use.runtime.util.PluginRegistry
- org.tzi.use.runtime.util.ServiceRegistry
- org.tzi.use.runtime.util.ShellCmdRegistry
Log.verbose(String) is called from 17 places in the following classes::
- org.tzi.use.gen.tool.GGenerator
- org.tzi.use.gui.main.MainWindow.ActionFileSaveScript
- org.tzi.use.main.Main
- org.tzi.use.main.shell.Shell
- org.tzi.use.runtime.MainPluginRuntime
Log.trace(String) is called from 1 place in the following class:
- org.tzi.use.uml.ocl.expr.Evaluator
Log.trace(Object location, String msg) is called from 11 places in the following classes:
- org.tzi.use.uml.ocl.expr.EvalContext
- org.tzi.use.uml.sys.MSystem
- org.tzi.use.uml.sys.MSystemState
- org.tzi.use.main.shell.Shell
Log.trace(Object location, String msg, boolean flush) is called from 1 place in the following classes:
- org.tzi.use.util.Log
3. Direct output to System.out and System.err
Many places access System.out or System.err. A detailed list can be generated using ArchUnit with the following test:
@ArchTest
public static final ArchRule noSystemOut = GeneralCodingRules.NO_CLASSES_SHOULD_ACCESS_STANDARD_STREAMS;Shell
The class Shell outputs to System.err if there is an exception "on a lower level". This is done to be as less dependent as possible.
Sometimes output to the shell is done by System.out, without any reason. This should be replaced by some explicit handling of the shell output.
Options
Prints help on System.out
4. Usage of PrintWriter on execution
Some areas of USE pass loggers as arguments. For example, the USECompiler takes an argument PrintWriter err to report compilation errors. However, there is just one kind of output with no differentiation between errors, warnings, debug, ... on the USE application level. For this, sometimes awkward solutions are implemented. For example, the BaseParser uses System.err to provide a warning writer.
Proposed Solution
The new approach to output information should
- separate output for users and output for developers
- allow for multiple output targets, i.g., shell and logwindow
- allow for decorated output, i.g., output warnings in yellow, etc.
To achieve 1., a class UserOutput is proposed. This class is used instead of the currently used PrintWriter. To output information to developers, a well accepted logging framework should be used. This clearly separates user output from development information.
The proposed UserOutput class provides methods for different output levels for USE:
- Normal
- Error
- Warn
- Info
- Trace
Originally posted by @h-man2 in #5 (comment)