Intro

Just a blog listing some weird issues and their solutions with regards to the Oracle Hyperion applications I manage.
Hopefully it will help someone else resolving these -often cryptic- incidents.

Applications involved are:

Hyperion Financial Planning
Hyperion Business Rules
Hyperion Calculation Manager
Hyperion Financial Management
Hyperion Analytic Services (Essbase)
Hyperion Reporting and Analysis
Hyperion Financial Data Quality Management (FDM)
Hyperion Workspace

All running version 11.1.2.1.0

Thursday, January 16, 2014

PowerShell script to rotate HFM logfiles

Hyperion Financial Management 11.1.2.1 writes it's messages to two logfiles:

HsvEventLog.log
Hfm.odl.log.

These files are located on the HFM application server in the directory:

<EPM_ORACLE_INSTANCE>\diagnostics\logs\hfm

Over time, these files grow and viewing the system messages from within HFM may become slow. They also can become too large for external editors. That's why they need to be rotated occasionally.
Since HFM opens and writes these files continuously and downtime is sparse, any action to rotate these logfiles (renaming, clearing) is blocked. Multiple HFM processes will lock the files:

one or more HsvDatasource.exe
HsxServer.exe
CASSecurity.exe

This is This is why I wrote a PowerShell script (so Windows only), that will close the open file handles on the logfiles and rename them with a yyyymmdd extension. The script needs the SysInternal's handle.exe utility, which can be found here. The PowerShell functions to find the handles and close them were borrowed from Sean Kearney and can be found here.


# Name   : Rotate_HFM_Logfiles.ps1
# Purpose: Renames HFM logfiles HsvEventlog.log and Hfm.odl.log with a date extension
# Author : P. da Graça
# Remark : Edited with Notepad++, layout maybe off in other editors
#
# When            Who                What
# 13-01-2014    PdaGraca        New setup in PowerShell

# script variables

# first determine the EPM instance
$epmroot='D:\Oracle\Middleware'                                                # installation directory of EPM, change if installed elsewhere!
$epm=(Get-Item $epmroot\User_Projects\* -Include Epmsystem* -ErrorAction SilentlyContinue) # check if an EPM instance exists on the server
If ( $epm.Exists )                                                            # if yes
 {
  If ( $epm.Attributes.toString() -eq 'Directory' )                            # check if it's a directory
   {
    $epm_oracle_instance=$epm.FullName                                        # if yes, assign the full pathname to variable
   }
  Else                                                                        # if not
   {
    Write-Host '$epm is not a directory!'                                    # report back
    Exit                                                                    # and exit script
   }
 }
 Else                                                                        # if no instance is found
 {
  Write-Host 'No EPM instance found on server!'                                # report back
  Exit                                                                        # and exit script
 }                    

$hfm_log_dir="$epm_oracle_instance\diagnostics\logs\hfm"                    # location of HFM logfiles
$hfm_event_log="HsvEventLog.log"                                            # name of logfile 1
$hfm_odl_log="Hfm.odl.log"                                                    # name of logfile 2
$curdate=Get-Date -Format "yyyyMMdd"                                        # get current date in double digit format string
$curyear=$curdate.SubString(0,4)                                            # extract current year
$curmonth=$curdate.SubString(4,2)                                            # extract current month
$curday=$curdate.SubString(6,2)                                                # extract current day
$curmmdd="$curyear$curmonth$curday"                                            # generate a yyyymmdd extension

# These functions are borrowed from Sean Kearney (http://gallery.technet.microsoft.com/scriptcenter/79e3a8d3-fe68-4e6a-b41e-1fd22539e264),
# and used to make sure the logfiles are closed

Function global:GET-OpenFilePID()
    {
      param (
             [parameter(ValueFromPipeline=$true, Mandatory=$true)]
             [String[]]$HandleData
            )

      Process
            {
              $OpenFile=New-Object PSObject -Property @{FILENAME='';ProcessPID='';FILEID=''}

              $StartPid=($HandleData[0] | SELECT-STRING 'pid:').matches[0].Index
              $OpenFile.Processpid=$HandleData[0].substring($StartPid+5,7).trim()

              $StartFileID=($HandleData[0] | SELECT-STRING 'type: File').matches[0].Index
              $OpenFile.fileid=$HandleData[0].substring($StartFileID+10,14).trim()

              $OpenFile.Filename=$HandleData[0].substring($StartFileID+26).trim()
              Return $OpenFile
            }
    }
                
Function global:GET-Openfile()
    {
      [Cmdletbinding()]
      param ( 
             [parameter(Mandatory=$True, ValueFromPipeline=$True)]
             [String[]]$Filename
            )

      Process
            {
              If ( ! (TEST-LocalAdmin) ) { Write-Host 'Need to RUN AS ADMINISTRATOR first'; Return 1 }
              If ( ! ($Filename) ) { Write-Host 'No Filename or Search Parameter supplied.' }
              $HANDLEAPP="& 'D:\VionICT\Tools\handle.exe'"
              $Expression=$HANDLEAPP+' '+$Filename

              $OPENFILES=(INVOKE-EXPRESSION $Expression) -like '*pid:*'

              $Results=($OPENFILES | GET-openfilepid)

              Return $results
            }
    }

Function global:Close-Openfile()
    {
      [CmdletBinding(SupportsShouldProcess=$true)]
      param (
             [parameter(Mandatory=$True, ValueFromPipelineByPropertyName=$True)]
             [string[]]$ProcessPID,
             [parameter(Mandatory=$True, ValueFromPipelinebyPropertyName=$True)]
             [string[]]$FileID,
             [parameter(Mandatory=$false, ValueFromPipelinebyPropertyName=$True)]
             [String[]]$Filename
            )

      Process
            {
             $HANDLEAPP="& 'D:\VionICT\Tools\handle.exe'"                
             $Expression=$HANDLEAPP+' -p '+$ProcessPID[0]+' -c '+$FileID[0]+' -y'
             If ( $PSCmdlet.ShouldProcess($Filename) ) 
                    {
                      INVOKE-EXPRESSION $Expression | OUT-NULL
                      If ( ! $LastexitCode ) { Write-host 'Successfully closed'}
                    }
            }
    }

Function global:TEST-LocalAdmin()
    {
      Return ([security.principal.windowsprincipal] [security.principal.windowsidentity]::GetCurrent()).isinrole([Security.Principal.WindowsBuiltInRole] "Administrator")
    }

# End of borrowed functions   
   
Function Close-HFMLogFile()
    {
      param (
              [parameter(Mandatory=$True)]$FileName
             )

      Process
             {
               If (Get-Item .\$FileName -ErrorAction SilentlyContinue)            # if the logfile exists
                {
                  Get-OpenFile $FileName | Close-OpenFile -ErrorAction SilentlyContinue    # close any open file handles
                  $newname=$FileName.Replace(".log",".$curmmdd.log")            # generate a new filename with date extension
                  If (-not (Get-Item .\$newname -ErrorAction SilentlyContinue)) {Rename-Item .\$FileName -Newname .\$newname} # if the new name does not exist yet, rename the file
                }
             }
    }
   
Set-Location $hfm_log_dir

Close-HFMLogFile $hfm_event_log
Close-HFMLogFile $hfm_odl_log