en-us/about_psf_message.help.txt

TOPIC
    about_psf_message
    
SHORT DESCRIPTION
    Explains the PSFrameworks message & logging component
    
LONG DESCRIPTION
    #-------------------------------------------------------------------------#
    # Component Commands #
    #-------------------------------------------------------------------------#

    - Get-PSFMessage
    - Write-PSFHostColor
    - Write-PSFMessage
    
    
    #-------------------------------------------------------------------------#
    # Table of Contents #
    #-------------------------------------------------------------------------#
    
    - Introduction
    - The message architecture
    - Messaging Configuration
    - Advanced messaging functionality
    - The logging system
    -- The logging system's configuration
    - Logging: File System
    -- Functionality
    -- Configuration
    
    #-------------------------------------------------------------------------#
    # Introduction #
    #-------------------------------------------------------------------------#
    
    We often write messages in a module. Sometimes some verbose messages for
    debugging purposes, sometimes an info for the user and sometimes even a
    warning that something seriously went wrong.
    Also often it becomes necessary or desireable to create logfiles. Logging
    helps a lot with figuring out what went wrong, but often we only enable it
    after something broke, because those logs aren't much use when everything
    works as desired and logs nobody reads are of little use, right?
    Especially when you have to take care of those logs ...
    
    The messaging system unifies the entire process into a single command:
    
      Write-PSFMessage
    
    By the simple act of using this function, not only do you write the message
    to the channels chosen, but also add them to the logging system. That system
    will not only create log files, but also take care to clean up old or too
    large files.
    Example usage:
    
      Write-PSFMessage -Level Host -Message "Writing something the user sees"
    
    There are three basic levels available:
    - Host: Visible to the user by default
    - Verbose: Written via Write-Verbose, not visible to the user by default
    - Warning: Writes a warning message.
    
    It will automatically add a timestamp and the function that was calling it.
    While details on how to configure the system are covered in subsequent
    chapters, the logging path can be read with this command:
    
    Get-PSFConfigValue "psframework.logging.filesystem.logpath"
    
    However all recently written messages can also be found still in memory, by
    running:
    
      Get-PSFMessage
    
    That command can also show any errors that were logged:
    
      Get-PSFMessage -Errors
    
    
    #-------------------------------------------------------------------------#
    # The message architecture #
    #-------------------------------------------------------------------------#
    
    The PowerShell system has multiple streams where information can go, in
    addition to straight to the host. The Verbose one is probably the best
    known one, but there are more:
    - Information
    - Verbose
    - Debug
    - Warning
    - Error
    The parameter '-Level' controls, how this message will be written. Each
    level has a numeric representation (a level). On the other hand, what level
    is to which stream is controlled by the configuration system. Each level and
    the <default> settings are shown below:
    
    Information:
      Critical (1), Important / Output / Host (2), Significant (3)
      This is what is usually shown to the end user, printed to the screen.
      Starting PowerShell v5, Write-Host is also written to the information
      stream, hence it is also available on that.
    
    Verbose:
      VeryVerbose (4), Verbose (5), SomewhatVerbose (6)
      Verbose messages are shown when a command is run with the automatic
      '-Verbose' parameter. They generally help in showing the current progress.
      
    Debug:
      Critical (1), Important / Output / Host (2), Significant (3),
      VeryVerbose (4), Verbose (5), SomewhatVerbose (6), System (7), Debug (8),
      InternalComment (9), Warning (666)
      Debugging information is only really useful to automated debugger systems.
      For example when running a powershell script from within a compiled
      application, as is common to many monitoring solutions.
    
    Warning:
      Warning (666)
      Warnings signal that something went wrong. They are a way to signal a user
      that something went wrong without turning them off with too much confusing
      information as red exceptions tend to. Warnings cannot seriously be turned
      off short of:
      - Globally disabling verbose output
      - Enabling Exception and specifying an exception.
        (More details on that in "Advanced messaging functionality")
    
    Error:
      Errors are the system's way to tell other code something went wrong. Those
      exceptions are great for debugging but tend to discourage users. There is
      no Level for exceptions. You write to the error stream by passing the
      ErrorRecord(s) you caught to the '-ErrorRecord' parameter.
    
    Once the streams to communicate with have been settled, the command will
    then pass it to the logging system. For more details on the logging system
    see below in the chapter "The logging system"
    
    
    #-------------------------------------------------------------------------#
    # Messaging Configuration #
    #-------------------------------------------------------------------------#
    
    This section assumes that general understanding of the configuration system
    has already been achieved. Run this to read up on that component:
      Get-Help about_psf_configuration
      
    The messaging system supports several settings that control its behavior:
    
    'PSFramework.message.info.minimum' (Default: 1)
    'PSFramework.message.info.maximum' (Default: 3)
    The level range at which messages are sent to host/information
    Set to 0 to disable.
    
    'PSFramework.message.verbose.minimum' (Default: 4)
    'PSFramework.message.verbose.maximum' (Default: 6)
    The level range at which messages are sent to verbose
    Set to 0 to disable.
    
    'PSFramework.message.debug.minimum' (Default: 1)
    'PSFramework.message.debug.maximum' (Default: 9)
    The level range at which messages are sent to debug
    Set to 0 to disable.
    
    'PSFramework.message.info.color' (Default: Cyan)
    The color regular messages are printed to the host.
    
    'PSFramework.message.info.color.emphasis' (Default: Green)
    The color emphasized text in messages is printed to the host.
    
    'PSFramework.message.info.color.subtle' (Default: Gray)
    The color subtle text in messages is printed to the host.
    
    'PSFramework.developer.mode.enable' (Default: False)
    The developer mode is designed to help in debugging commands that implement
    the PSFramework. All messages are shown and messages contain a lot more meta
    information than usual. Messages that are shown that would be invisible to
    regular users are highlighted in a different color.
    
    'PSFramework.message.developercolor' (Default: Gray)
    The color messages are shown in, that would not have been shown, but are
    being shown in developer mode (which shows all messages, see above).
    
    'PSFramework.message.consoleoutput.disable' (Default: False)
    This is the master switch that will disable all Information Level output,
    as well as all warnings. Basically, this enables silent mode that will
    suppress all output to screen except for uncaught exceptions.
    
    
    #-------------------------------------------------------------------------#
    # Advanced messaging functionality #
    #-------------------------------------------------------------------------#
    
    After having scratched the surface of Write-PSFMessage, there's more to be
    had. From the more advanced parameters until debugging with Get-PSFMessage
    
    # Parameters
    #--------------------------------------------------------------------------
    
    Beyond the two basic parameters '-Level' and '-Message' there are quite a
    few additional parameters, allowing access to more complex features:
    
    -FunctionName
    This parameter automatically detects the name of the function calling it, so
    in most cases it is not necessary to specify it. However, if you have an
    intermediary function and want to pass on the original function name, here
    you can explicitly choose the name.
    This name becomes part of the log and thus useful for troubleshooting.
    
    -ErrorRecord
    This allows you to attach one or several exceptions to the message written.
    When you do, pass the entire errorrecord(s), not merely the exception object
    Using this parameter has several consequences:
    - It will add an error entry in the in-memory log
    - It will add an error entry in the logging queue
    - It will automatically add the message of the first exception to the
      message written (if it isn't there yet)
    - It will write the exception to the error stream
    - It will add the error record to the $error variable
    A very simple example on how to use it:
    
      try { $null.ToString() }
      catch { Write-PSFMessage -Level Warning -ErrorRecord $_ -Message "Failed to do the impossible!" }
    
    What this will NOT do by itself is print the error to screen. In case of
    need there is the full error object still in memory and logged to xml
    
    -EnableException
    Setting this parameter to $true will cause the function to write the
    exception more publicly to the screen (just passing -ErrorRecord will not do
    so). By itself of not critical value, it conforms itself to the Flow Control
    components behavior, allowing for uniformity in handling exceptions.
    It is a boolean type, since it is designed to be passed through by the
    calling function (The calling function would implement a switch parameter
    named '-EnableException' and pass that value straight through to
    Write-PSFMessage and Stop-PSFFunction.
    
    -Target
    Adds the object that was being processed to the message. This has no effect
    on any messages shown on the screen, however will be part of the in-memory
    log as well as log file. NEVER ADD SENSITIVE DATA such as clear Passwords.
    This allows following an object in the logs as it passes through commands,
    enabling object-based tracing.
    Also handy to extract the failing input when processing many items, only
    some of which failed.
    
    -Once
    Write a specific message once only. This allows easily sending warnings such
    as deprecation warnings without spamming the user in them.
    This parameter must be passed a string in order to uniquely identify it. It
    also uses the function name, so it must only be unique per function.
    Example:
      
      Write-PSFMessage -Level Warning -Once "1" -Message "The parameter '-Example' has been deprecated and will be removed in future versions. Its functionality has become part of the baseline."
    
    
    # Level Concept
    #--------------------------------------------------------------------------
    
    The levels were introduced, in order to be able to more smoothly control
    verbosity levels. For a simple implementation, levels 2 and 5 more than
    suffice. However when it comes to user comfort, the user is able to choose
    the level at which he will be directly informed, at which point a scaling
    use of levels allows the user the level of detail he is confronted with.
    
    Example:
    A function accepts computers as input and for each does a complex procedure
    consisting of 3 major steps and lots of sub-steps. At this point the message
    distribution could be like this:
    Starting to process computer n: Level 4
    - Starting Step 1: Level 5
    -- Substep X: Level 6
    -- Substep Y: Level 6
    -- Substep Z: Level 6
    - Starting Step 2: Level 5
    -- Substep X: Level 6
    -- Substep Y: Level 6
    -- Substep Z: Level 6
    - Starting Step 2: Level 5
    -- Substep X: Level 6
    -- Substep Y: Level 6
    -- Substep Z: Level 6
    By default, the user will not see a thing while this function proceeds. If
    he increases the maximum level for information messages to 4 however:
    
      Set-PSFConfig -Name 'psframework.message.info.maximum' -Value 4
    
    He will now be shown the computer that is currently being processed. Still
    impatient, he then increases it to '5' and will suddenly see each of the
    main steps being logged to screen.
    
    The level will also be printed to the log, allowing another level of
    filtering. If the message structure as shown is respected, the log itself
    allows tracing the rough architecture if the function using Write-PSFMessage
    
    
    # Troubleshooting with Get-PSFMessage
    #--------------------------------------------------------------------------
    
    Get-PSFMessage will return the messages written straight from memory, it
    doesn't touch the logfiles itself. However, what it allows is filtering for
    information, since the logged entries contain a lot mroe meta-data than just
    the line of text.
    By filtering by the TargetObject property, it becomes possible to search for
    all messages (shown or not shown. They ALL are logged and available)
    relating to an object that was processe (Assuming the above described
    '-Target' parameter was used and properly filled).
    Of course, it is also possible to filter by function that wrote the message.
    
    Combining the two, it becomes fairly simple to retrieve all objects passed
    to the implementing function whose processing failed.
    
    Get-PSFMessage also contains a parameter '-Errors', which allows retrieving
    the logged exceptions (which will also contain information such as function,
    timestamp and targetobject). This deals with one of the steadily escalating
    issues that even with try/catch, errors get added to the $error variable,
    which has led to that variable having lost significant usefulness in
    troubleshooting non-trivial issues.
    
    
    # Bringing color to your screen
    #--------------------------------------------------------------------------
    
    Messages can provide write information for the user to see on the screen.
    However, information is easier to interpret if the essentials can be read by
    scanning, rather than detail reading. One of the bost helps with that is
    color. The human eye is drawn to these words that have a different color.
    
    All messages in the PSFramework support a html-style tag syntax in order to
    do inline color definition. Example:
    
      Write-PSFMessage -Level VeryVerbose -Message "Connecting to <c='em'>$computer</c>"
    
    This will print the specified line with color highlighting IF the user has
    his maximum information level to 4 or higher. The color tags are stripped
    from the message before being logged, so the logs or not impaired by them.
    
    The following colors are supported:
    - All legal console colors
    - em: Emphasis. The color configured under
           'PSFramework.message.info.color.emphasis'
    - sub: Subtle. The color configured under
           'PSFramework.message.info.color.subtle'
    Warning: Generally, it is recommended to restrict yourself to the specially
    configured colors 'em' and 'sub'. While static colors are supported, console
    color layouts may vary and what looks good for one user may not look good
    for the other. By using the configuration system, it becomes possible to
    give a user a choice in the color scheme.
    
    Illegal colors will be stripped without comment.
    
    For the purpose of building menues or head messages (which arguably aren't
    messages, since they do not contain information that needs to be logged),
    there is another command available:
    
      Write-PSFHostColor
    
    Which is basically the function used by Write-PSFMessage for its final
    colorful output.
    
    
    #-------------------------------------------------------------------------#
    # The logging system #
    #-------------------------------------------------------------------------#
    
    The logging system consists of the following components:
    - The in-memory queue
    - The logging queue
    - The logging script
    
    | The in-memory queue |
    #---------------------#
    All messages are kept in a queue in memory. It is self-limiting in that once
    its capacity has been exceeded, the oldest entry will be removed.
    The same hodls true for the exceptions that are logged.
    All messages and exceptions are tagged by runspace ID, when parallel
    processing, parallel runspaces log to the same queues. This allows
    troubleshooting not only the primary runspace but all of them. Keeping the
    runspace ID allows filtering by runspace.
    This is the information retrieved by the Get-PSFMessage function.
    
    | The logging queue |
    #--------------------#
    All messages and exceptions are also added to a set of queues that are
    collected by the logging script. These too have a (more generous) maximum
    capacity to prevent memory flood.
    These queues should never accumulate much data as the logging script should
    collect them frequently.
    
    | The logging script |
    #--------------------#
    The logging script gathers the info from the logging queue and logs them.
    Currently, only the filesystem logging is implemented, however additional
    logging providers will soon become available, providing a wider choice of
    logging options. Filesystem however will remain the default option.
    The script is operated by the modules own runspace component and can be
    controlled using its functions.
    
    
    # The logging system's configuration
    #--------------------------------------------------------------------------
    
    <Content Pending>
    
    
    #-------------------------------------------------------------------------#
    # Logging: File System #
    #-------------------------------------------------------------------------#
    
    <Content Pending>
    
    
    # Functionality
    #--------------------------------------------------------------------------
    
    <Content Pending>
    
    
    # Configuration
    #--------------------------------------------------------------------------
    
    <Content Pending>
    
    
KEYWORDS
    psframework message