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

Unify user and developer output in USE #60

Open
h-man2 opened this issue Dec 22, 2022 · 0 comments
Open

Unify user and developer output in USE #60

h-man2 opened this issue Dec 22, 2022 · 0 comments

Comments

@h-man2
Copy link
Contributor

h-man2 commented Dec 22, 2022

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
Loading

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

  1. Log output to additional log-buffer
  2. Suppress output to default stream, but write to log-buffer by using setQuietMode
  3. 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:

  1. Log output to additional log-buffer: Used by MainWindow to write a protocol to a file.
  2. Suppress output: No usage found in USE or USE plugins
  3. 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)$
    }
Loading

Description

The class Log allows to separate between normal output, warning, errors and debug information. It is a static utility class.

Functionality

  1. Print errors
  2. Print warnings
  3. Print normal output
  4. Print debug information
  5. Print traces
  6. Print verbose information
  7. Output/suppress of exception stacktrace
  8. Can be queried if output was made (with reset functionality)
  9. 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:

  1. Providing output to the user supporting different levels of verbosity set by the user [OUT]
  2. Easing error handling (instead of throwing an exception, an error is logged) [ERR]
  3. 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 options quiet and compileOnly are 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?) deleted
  • org.tzi.use.analysis.metrics.GSMetricConfiguration deleted
  • org.tzi.use.gen.tool.GGenerator OUT
    Suppresses warnings globally by switching them of Log.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? ScriptContext of Ruby just uses a Writer.
  • 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

  1. separate output for users and output for developers
  2. allow for multiple output targets, i.g., shell and logwindow
  3. 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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

When branches are created from issues, their pull requests are automatically linked.

1 participant