diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..95fcfa3
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,16 @@
+ARG IMAGE=store/intersystems/iris-community:2021.1.0.205.0
+FROM $IMAGE
+
+USER root
+
+WORKDIR /opt/irisapp
+RUN chown ${ISC_PACKAGE_MGRUSER}:${ISC_PACKAGE_IRISGROUP} /opt/irisapp
+USER ${ISC_PACKAGE_MGRUSER}
+
+COPY src src
+COPY module.xml module.xml
+COPY iris.script /tmp/iris.script
+
+RUN iris start IRIS \
+ && iris session IRIS < /tmp/iris.script \
+ && iris stop IRIS quietly
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..01362e1
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,14 @@
+version: '3.6'
+services:
+ iris:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ restart: always
+ ports:
+ - 51553:51773
+ - 52553:52773
+ - 53773
+ volumes:
+ - ~/iris.key:/usr/irissys/mgr/iris.key
+ - ./:/irisdev/app
\ No newline at end of file
diff --git a/iris.script b/iris.script
new file mode 100644
index 0000000..475e480
--- /dev/null
+++ b/iris.script
@@ -0,0 +1,9 @@
+;do $System.OBJ.LoadDir("/opt/irisapp/src","ck",,1)
+
+zn "%SYS"
+Do ##class(Security.Users).UnExpireUserPasswords("*")
+set $namespace="%SYS", name="DefaultSSL" do:'##class(Security.SSLConfigs).Exists(name) ##class(Security.SSLConfigs).Create(name) set url="https://pm.community.intersystems.com/packages/zpm/latest/installer" Do ##class(%Net.URLParser).Parse(url,.comp) set ht = ##class(%Net.HttpRequest).%New(), ht.Server = comp("host"), ht.Port = 443, ht.Https=1, ht.SSLConfiguration=name, st=ht.Get(comp("path")) quit:'st $System.Status.GetErrorText(st) set xml=##class(%File).TempFilename("xml"), tFile = ##class(%Stream.FileBinary).%New(), tFile.Filename = xml do tFile.CopyFromAndSave(ht.HttpResponse.Data) do ht.%Close(), $system.OBJ.Load(xml,"ck") do ##class(%File).Delete(xml)
+;zpm "install zpm"
+zn "USER"
+zpm "load /opt/irisapp/ -v":1:1
+halt
diff --git a/module.xml b/module.xml
new file mode 100644
index 0000000..f4990cc
--- /dev/null
+++ b/module.xml
@@ -0,0 +1,14 @@
+
+
+
+
+ DeepSeeButtons
+ 1.0.0
+ Script used by the DeepSee support group at InterSystems to gather system information.
+ DeepSee Buttons
+ module
+ src
+
+
+
+
diff --git a/src/mac/DeepSeeButtons.mac b/src/mac/DeepSeeButtons.mac
new file mode 100644
index 0000000..6c93762
--- /dev/null
+++ b/src/mac/DeepSeeButtons.mac
@@ -0,0 +1,3756 @@
+ROUTINE DeepSeeButtons
+DeepSeeButtons(namespace="ask", cubeString="ask", getLogs="", LogFile="", tracking="")
+#include %occConstant
+
+ ;DeepSeeButtons: routine to log system and DeepSee information
+ ;Install it in the %SYS namespace and launch it as:
+ ;%SYS> Do ^DeepSeeButtons
+ ;
+ ;You can use the following optional arguments:
+ ;namespace: namespace where this routine will run, e.g. "SAMPLES". If "" the current namespace will be chosen
+ ;cubeString: comma separated list of cubes, e.g. "patients,holefoods", "ALL", or "" for no cubes at all
+ ;getLogs: boolean flag to control inclusion of the cconsole.log, Query Log, and DeepSee logs.
+ ; A value of getLogs="" will prompt the user to make this choice from the interactive dialog
+ ;LogFile: output file. By default the output file will be stored in the /mgr directory
+ ;tracking: Used to log progress into ^IRIS.Temp.DeepSeeButtonsTrack and track this routine
+ ;
+ ;Example using arguments:
+ ;Do ^DeepSeeButtons("SAMPLES","PATIENTS",1,"/home/amarin/Desktop/DSbuttons.html",0)
+ ;
+ ;
+ ;DeepSee Buttons includes the following general information
+ ; 1) DeepSee Setup
+ ; -Agent Count and cores
+ ; -DeepSee.AuditCode, DeepSee.AuditQueryCode
+ ; -Most recent activity in Cube manager
+ ; -Config section of cpf file
+ ; -Important mappings
+ ; -Server Initialization Code
+ ; -Deepsee enabled webapps
+ ; 2) Server Details
+ ; -Configuration
+ ; -Customer name
+ ; -License
+ ; -Fully Qualified Host Name
+ ; -User and date
+ ; -Cache startup
+ ; -$ZV
+ ; -Locale
+ ; -Operating system
+ ; -Disk space
+ ; -RAM
+ ; 3) Cubes in namespace
+ ; -Cubes table with Cube Name, Display name, Source Class, Cube Class, Related Cubes
+ ; -Versioned cubes
+ ; -Abstract cubes
+ ; -Cubes with Source Classes Based on SQL Storage
+ ; -Cubes Based on Data Connectors
+ ; -Build Order for Related Cubes
+ ; 4) Build/Synch
+ ; -DSTIME
+ ; -BuildSynchTable Table with Cube Name, Fact Count, Build Time, Build Rate, Build Errors, DSTIME,
+ ; Last Compile, Last Build/Synch, Related Cubes
+ ; -Build Errors
+ ; 5) Cube Registry Map
+ ; 6) Cube Info: Optional Extra data on a particular cube
+ ; 6A) Cube Info: display name, cube type, subject area class, inherits from, resource, source class,
+ ; fact class, caption, fact count,
+ ; build restrictions (maxfacts, buildrestriction/filterspec property, %OnProcessFact, and %OnGetFilterSpec),
+ ; last modified, DSTIME & DSINTERVAL, cube registry, build errors
+ ; 6B) Dimensions: dimension list, ^DeepSee.CalcMbrs, %Analyze, FieldNameToSpec, %AnalyzeMissing
+ ; 6C) Other Elements: Pivot variables, listing fields, listings, resources
+ ; 7) Query Log
+ ; -Number of users runnign queries
+ ; -User and Queries run
+ ; -^DeepSee.LastQuery
+ ; -Last 5 queries run by each user
+ ; 8) DeepSee Logs
+ ; 9) CPF file (includes mappings)
+ ; 10) cconsole.log
+ ; 11) Mappings - Show global mappings in the namespace
+ ; 12) Local Databases
+ ; 13) Task schedule
+ ; 14) Journaling
+ ; 15) Alerts
+
+StartDialog
+ New (namespace,cubeString,getLogs,LogFile,tracking)
+ Set origNS=$Namespace
+ Try {
+ If '$system.Security.Check("%DeepSee_Admin","USE") {
+ // Require %DeepSee_Admin in order to run this utility
+ Write !,"This tool requires the %DeepSee_Admin resource to run"
+ Quit
+ }
+
+ Do:tracking WriteTrack("setup","Starting DeepSeeButtons","")
+ Set PDev=$Principal
+ Use PDev
+ Write !,"DeepSee Diagnostic Report Evidence Logging Tool"
+ Write !,"This reporting tool provides the information required for"
+ Write !,"InterSystems Technical Support to analyze DeepSee issues. "
+ Set namespace=$$GetNamespace(namespace)
+ Quit:namespace=""
+ Set cubeList=$$GetCubesToLog(cubeString,namespace,tracking)
+ //Later do not ask to confirm to proceed if anything was passed to getLogs argument
+ Set proceed=(getLogs'="")
+ Do:getLogs="" GetLogsConfirm
+ Do:'proceed ReadLogTypeConfirm
+ Quit:'proceed
+ Kill:tracking ^IRIS.Temp.DeepSeeButtonsTrack
+ Do LaunchLogs(namespace,cubeList,getLogs)
+ } Catch(ex) {
+ Set tSC = ex.AsStatus()
+ Set msg = $System.Status.GetErrorText(tSC)
+ Do:tracking WriteTrack("error","","",msg)
+ Use $Principal
+ Write !,msg
+ }
+ zn origNS
+ Quit
+
+GetNamespace(namespace) {
+ //If namespace is "" choose the current namespace
+ If namespace="" {
+ Set namespace = $Namespace
+ Write !,"Running in namespace: "_namespace
+ }
+
+ //Ask user if the namespace variable is not given
+ Set:namespace="ask" namespace=""
+ Set namespace=$$ValidateNamespace(namespace) //Make sure input namespace exists
+ While namespace="" { //User didn't enter a namespace when calling routine
+ Write !!,"Type namespace ["_$Namespace_"]"
+ Read namespace
+ Set:namespace="" namespace = $Namespace
+ Set namespace=$$ValidateNamespace(namespace)
+ }
+ Quit namespace
+}
+
+GetCubesToLog(cubeString,namespace,tracking=0) {
+ If cubeString="ask" {
+ Set allcubeList=$$DialogCubes(namespace)
+ } ElseIf cubeString="" {
+ Set allcubeList=""
+ } ElseIf $LISTVALID(cubeString) {
+ Set allcubeList=cubeString
+ } ElseIf cubeString="ALL"{
+ Set cubeString=$$GetAllCubes(namespace)
+ Set allcubeList=$LFS(cubeString,",")
+ } Else {
+ Set allcubeList=$LFS(cubeString,",")
+ }
+ Set cubeList=$$VerifyInputCubes(allcubeList,namespace,tracking)
+ Quit cubeList
+}
+
+GetLogsConfirm
+ ZN "%SYS"
+ Write !, "Include cconsole.log, Query Log, and DeepSee Logs? [Y] "
+ Read getLogs
+ Set getLogs=$ZCONVERT(getLogs,"U")
+ If (getLogs="") {
+ Set getLogs=1 //If the user did not make a selection, add console and query logs
+ } ElseIf (getLogs="N")||(getLogs="NO") {
+ Set getLogs=0
+ } ElseIf (getLogs="Y")||(getLogs="YES") {
+ Set getLogs=1
+ } ElseIf (getLogs=+getLogs) {
+ //secret option: if getLogs is a number it controls the number of queries by user shown
+ //Just pass getLogs on
+ } Else {
+ Write !,"Please enter Y or N"
+ Set getLogs=""
+ Goto GetLogsConfirm
+ }
+ Quit
+
+ReadLogTypeConfirm
+ Write !,"Continue? [Y] " Read LogType
+ Set LogType=$ZCONVERT(LogType,"U")
+ If ((LogType="NO")!(LogType="N")!(LogType="Q")!(LogType="QUIT")) {
+ Set proceed=0 }
+ ElseIf ((LogType="YES")!(LogType="Y")!(LogType="")) {
+ Set proceed=1
+ } Else {
+ Write !,"Please enter Y or N" Goto ReadLogTypeConfirm
+ }
+ Quit proceed
+
+LaunchLogs(namespace,cubeList,getLogs)
+ Try {
+ Set CacheVerNumber=$System.Version.GetNumber()
+ If +CacheVerNumber<5 { //Do Quit Return
+ Set Message="*** Wrong version of Diagnostic Report utility ! ***"_$Char(13,10)_$Char(13,10)_"You are running on Cache "_
+ CacheVerNumber_" and this is the code for Cache 5.0 and later"
+ Use PDev Write:$X ! Write !,Message
+ Set Return="0|"_Message
+ Quit
+ }
+ Use PDev Write:$X !
+ Write "Collecting information, please do not interrupt this process.",!,"Do not close terminal until the process has completed"
+ Break 0
+ Set EOF=$ZUtil(68,40)
+ //Start logging with the DeepSee Setup section
+ Set output=$$LogSections(cubeList,getLogs,LogFile)
+ If $E(output,1,5)="Error" {
+ Do:tracking WriteTrack("error","","",output_". Check your output path and permissions")
+ W !,output," Abort",!
+ Return
+ } Else {
+ Set LogFile = output
+ }
+ Set rc=$$$OK
+ If $ZUtil(68,40,EOF) //Reset $ZEOF to the original setting
+ Break 1
+ If LogFile="" { //Do Quit Return
+ Set Message="*** Log file could not be created in "_LogDirectory_". Check directory permissions. ***"
+ Use PDev Write:$X ! Write !,Message
+ Set Return="0|"_Message
+ Quit
+ }
+ Use PDev
+ Write:$X ! Write !,"DeepSeeButtons report saved to: ",!,LogFile
+ Write !,"Please send the html file above to InterSystems Support."
+ } Catch(ex) {
+ Set tSC = ex.AsStatus()
+ Do $System.Status.DisplayError(tSC)
+ Do:tracking WriteTrack("error","","",$System.Status.GetErrorText(tSC))
+ }
+ Quit
+
+
+OpenLogFile(LogFile,FileOpenTimeOut) {
+ //Compared to ^Buttons the file is opened here, not in NewFile
+ Open LogFile:"RWNSK\UTF8\":FileOpenTimeOut
+ If '$Test Quit "Error opening file "_LogFile
+ Quit LogFile
+}
+
+LogSections(cubeList,getLogs,LogFile)
+ New (LogDirectory,namespace,cubeList,getLogs,LogFile,MgrDir,tracking)
+ Do Init
+ Set LogFile = $$InitLogFile
+ Set out = $$OpenLogFile(LogFile,FileOpenTimeOut)
+ If $E(out,1,5)="Error" Quit out
+ If OS?1"***".e Quit ""
+ Do LogHead(cubeList,getLogs)
+ Do LogOpenMainDiv
+ Do LogDeepSeeSetupSection //Note Ale: here rs.%Execute("") messes up my ZW in DumpToFile
+ Do LogServerSetup
+ Do LogCubeSection
+ Do LogBuildSynchSection
+ Do LogCubeRegistry
+ Do:(($D(cubeList)'=0) && (cubeList'="")) LogDetailedCubeInfo
+ Do:getLogs>0 LogQuerylog
+ Do:getLogs>0 LogDeepSeelog
+ Do LogCPF
+ Do:getLogs>0 LogCConsole
+ Do LogMappings
+ Do LogDataBases
+ Do LogTasks
+ Do LogJournal
+ Do LogAlerts
+ Do LogTrailer
+ Do LogSidePanel(cubeList,getLogs,$G(alerts,0))
+ Do LogCloseBody
+ ZN "%SYS"
+ Close LogFile
+ Quit LogFile
+
+
+///Log* Helper functions that log the section of a DeepSeeButtons report
+LogHead(cubeList,getLogs)
+ //Writes the Header record
+ Try {
+ New %DAT,%TIM,x //,Build
+ //Set x=$Text(+1),Build=$Piece(x,";",5),Build=$Piece(Build," ",2)
+ Set colspan=12 If OS="UNIX" Set colspan=13
+ Use LogFile
+ Do WriteLog("")
+ Do WriteLog("")
+ Do WriteLog("
")
+ Do WriteLog("")
+ Do LogCubeInfo
+ Do LogCubeDimensions
+ Do LogOtherCubeElements
+ Do WriteLog("
")
+ Do:tracking WriteTrack("cube","Detailed information collected",cube)
+ }
+ }
+ Quit
+
+LogCubeInfo
+ //New (namespace,LogFile,PDev,cube)
+ Do WriteUpdate("Getting detailed cube information for "_cube)
+ Do:tracking WriteTrack("cube","Build/Synch",cube)
+ Use LogFile
+ ZN namespace
+ Try {
+ Do WriteLog("")
+ } Else {
+ Do WriteLog("
")
+ }
+ Do WriteLog("
",10)
+ Set totCount = ^DeepSee.BuildErrors(cube)
+ Set tCount = 0
+ Set k = $O(^DeepSee.BuildErrors(cube,""))
+ While (k'="") {
+ Set tCount = tCount + 1
+ Set tSC = $G(^DeepSee.BuildErrors(cube,k))
+ Write $J($FNUMBER(tCount,"O,"),5),$J("",3),"Source ID: ",k
+ Write !,?8,$System.Status.GetErrorText(tSC),!!
+ If (tCount>1000) {
+ Write !,?0,"... skipping build errors ..."
+ Write !
+ Write !
+ Quit
+ }
+ Set k = $O(^DeepSee.BuildErrors(cube,k))
+ }
+ Write $FNUMBER(totCount,"O,")," build error(s) for '",cube,"'"
+ Do WriteLog("
",10)
+ Do WriteLog("
")
+ } Else {
+ Do WriteLog("
",6)
+ Do WriteLog("",8)
+ Do WriteLog("Build Errors",4)
+ Do WriteLog("",10)
+ Do ##class(%DeepSee.Utils).%PrintBuildErrors(cube)
+ Write ?10," "
+ Do WriteLog(" | ",8)
+ Do WriteLog("
",6)
+ Do WriteLog("",4)
+ Do WriteLog("",2)
+ }
+ } Catch(ex) {
+ Set tSC = ex.AsStatus()
+ Do $System.Status.DisplayError(tSC)
+ Do:tracking WriteTrack("warning","","LogCubeInfo",$System.Status.GetErrorText(tSC))
+ }
+ ZN "%SYS"
+ Quit
+
+LogCubeDimensions
+ Do WriteUpdate("Getting detailed cube information for "_cube_": get dimension list")
+ Do:tracking WriteTrack("cube","Dimension list",cube)
+ ZN namespace
+ Do WriteLog("
",2)
+ Do WriteLog("
",2)
+ Do WriteLog("
Dimensions for "_cube_"
",2)
+ If ##class(%DeepSee.Utils).%IsCubeAbstract(cube) {
+ Do WriteLog("
No dimensions because the cube is abstract
",2)
+ Quit
+ }
+ Do WriteLog("
Dimension List
",2)
+ Set st=##class(%DeepSee.Utils).%GetDimensionList(cube,.dimensionlist,1)
+ Do WriteLog("
",2)
+ Do WriteLog("",4)
+ Do WriteLog("",6)
+ Do WriteLog("Dimension | ",8)
+ Do WriteLog("Hierarchy | ",8)
+ Do WriteLog("Level | ",8)
+ Do WriteLog("Type | ",6)
+ Do WriteLog("
",6)
+ Set DimNo=$O(dimensionlist(-1)) //skip Calculated Dimensions
+ Set oldHierNo=0
+ Kill timeLevels
+ For {
+ Quit:DimNo=""
+ Set HierNo=$O(dimensionlist(DimNo,""))
+ For {
+ If HierNo="" {
+ Set oldHierNo=0
+ Quit
+ }
+ Set LevelNo=$O(dimensionlist(DimNo,HierNo,""))
+ For {
+ Quit:LevelNo=""
+ Set type=$LG(dimensionlist(DimNo,HierNo,LevelNo),1)
+ If (HierNo=0) { //Dimension.
+ //In this case 4th item "type" is actually the caption for all level
+ Do WriteLog("",6)
+ Do WriteLog(""_$LG(dimensionlist(DimNo,HierNo,LevelNo),2)_" | ",8) //DimName
+ If ($LG(dimensionlist(DimNo,HierNo,LevelNo),1)="r") { //relationships
+ Do WriteLog(" | ",8)
+ Do WriteLog(" | ",8)
+ Do WriteLog(" | ",8)
+ }
+
+ If ((type="d") && ($LG(dimensionlist(DimNo,HierNo,LevelNo),4)'="")) {
+ Do WriteLog(" | ",8)
+ Do WriteLog(""_$LG(dimensionlist(DimNo,HierNo,LevelNo),4)_" | ",8)
+ Do WriteLog("[All level] | ",8)
+ Do WriteLog("
",6)
+ Do WriteLog("",6)
+ Do WriteLog(" | ",8) //Skip DimName column
+ }
+ }
+ If (HierNo'=0){
+ If type="all" {
+ //Skip the all level because it was already shown next to the dimension
+ } ElseIf ((LevelNo=0) && (DimNo'=0)) {
+ Set newHier=0
+ If (oldHierNo && (HierNo'=oldHierNo)) { //Maybe the logic could be simpler but this works
+ Do WriteLog("
",6)
+ Do WriteLog("",6)
+ Do WriteLog(" | ",8)
+ }
+ Do WriteLog(""_$LG(dimensionlist(DimNo,HierNo,LevelNo),3)_" | ",8) //HierName
+ } ElseIf ((LevelNo=0) && (DimNo=0)){ //Measures section
+ If HierNo>1 {
+ Do WriteLog("
",6)
+ Do WriteLog("",6)
+ Do WriteLog(" | ",8)
+ }
+ Do WriteLog(""_$LG(dimensionlist(DimNo,HierNo,LevelNo),3)_" | ",8) //MeasName
+ Do WriteLog(" | ",8)
+ Do WriteLog(" | ",8)
+ } ElseIf (DimNo'=0) {
+ If $E($LG(^DeepSee.Cubes("cubes",cube,"mbr#",DimNo,HierNo,LevelNo),6),0,14)="%DeepSee.Time." {
+ Set temp=^DeepSee.Cubes("cubes",cube,"mbr#",DimNo,HierNo,LevelNo)
+ Set timeLevels(DimNo,HierNo,LevelNo)=$LB($LG(temp,6),cube,$LG(temp,2),$LG(temp,3),$LG(temp,4))
+ }
+ If newHier {
+ Do WriteLog("
",6)
+ Do WriteLog("",6)
+ Do WriteLog(" | ",8)
+ Do WriteLog(" | ",8)
+ }
+ Do WriteLog(""_$LG(dimensionlist(DimNo,HierNo,LevelNo),4)_" | ",8) //LevelName
+ Set type=$S(type="all":"[All level a]",1:"")
+ Do WriteLog(""_type_" | ",8) //type
+ Set newHier=1
+ }
+ }
+ Set LevelNo=$O(dimensionlist(DimNo,HierNo,LevelNo))
+ }
+ Set oldHierNo=HierNo
+ Set HierNo=$O(dimensionlist(DimNo,HierNo))
+ }
+ Set DimNo=$O(dimensionlist(DimNo))
+ Do WriteLog("
",6)
+ }
+ Do WriteLog("",4)
+ Do WriteLog("
",2)
+ //Alert if incompatible time levels are found
+ Do alertTimeLevels(.timeLevels,.alerts)
+ //Show calculated members in ^DeepSee.CalcMbrs
+ Do WriteLog("
Calculated Members
",2)
+ If $D(^DeepSee.CalcMbrs(cube)) {
+ Do WriteLog("
",2)
+ Do WriteLog("",4)
+ Do WriteLog("",6)
+ Do PrintGlobal(namespace,"^DeepSee.CalcMbrs("""_cube_""")",10)
+ Do WriteLog("
",6)
+ Do WriteLog("",4)
+ Do WriteLog("
",2)
+ } Else {
+ Do WriteLog("
No calculated members found for "_cube_"
",2)
+ }
+ //Detailed cube information
+ Do WriteUpdate("Getting detailed cube information for "_cube_": %Analyze")
+ Do:tracking WriteTrack("cube","%Analyze",cube)
+ Do WriteLog("
Analyze
",2)
+ Do WriteLog("
",2)
+ Do WriteLog("",4)
+ Do WriteLog("",6)
+ Do WriteLog("",8)
+ Do WriteLog("",10)
+ //Execute %Analyze but skip it if indices take too long
+ Try {
+ Set dirindices=##class(%SYS.Namespace).GetGlobalDest(namespace,"DeepSee.Index")
+ Do ##class(%Library.GlobalEdit).GetGlobalSizeBySubscript($P(dirindices,"^",2),"DeepSee.Index("""_cube_""")","",.sizeindex)
+ Set dirfacts=##class(%SYS.Namespace).GetGlobalDest(namespace,"DeepSee.Fact")
+ Do ##class(%Library.GlobalEdit).GetGlobalSizeBySubscript($P(dirfacts,"^",2),"DeepSee.Fact("""_$zu(28,factclass,5)_""")","",.sizefacts)
+ Set flag="c"
+ Set:(sizeindex<500) flag="i"_flag
+ If (flag'="c") {
+ //See if analyzing facts is quick
+ Set:(sizefacts<300) flag="f"_flag
+ Do WriteLog("Do ##class(%DeepSee.Utils).%Analyze("""_cube_""","""_flag_""",0)")
+ Do ##class(%DeepSee.Utils).%Analyze(cube,flag,0)
+ } Else {
+ Set msg="%Analyze was skipped because of the sizes of ^DeepSee.Fact or ^DeepSee.Index global ("_
+ sizefacts_" and "_sizeindex_", respectively). Consider to run the following command: "
+ Set msg2="Do ##class(%DeepSee.Utils).%Analyze("""_cube_""",""fci"",0)"
+ Do WriteLog(msg)
+ Do WriteLog(msg2)
+ Do:tracking WriteTrack("warning","",cube,msg_msg2)
+ }
+ Do WriteLog("")
+ Do WriteLog("")
+ Do WriteLog("")
+ } Catch(ex) {
+ Set tSC = ex.AsStatus()
+ Do WriteLog(tSC)
+ }
+ // Translate the filed names in %Analyze to actual specs
+ Do WriteUpdate("Getting detailed cube information for "_cube_": FieldNameToSpec")
+ Do:tracking WriteTrack("cube","FieldNameToSpec",cube)
+ Write "FieldNameToSpec("""_cube_""")",!
+ Do FieldNameToSpec(cube)
+ Do WriteLog("")
+ Do WriteLog("")
+ Do WriteLog("")
+ Do WriteUpdate("Getting detailed cube information for "_cube_": %AnalyzeMissing")
+ Do:tracking WriteTrack("cube","%AnalyzeMissing",cube)
+ Write "Do ##class(%DeepSee.Utils).%AnalyzeMissing(""",cube,""")",!
+ Do ##class(%DeepSee.Utils).%AnalyzeMissing(cube)
+ Do WriteLog(" ",10)
+ Do WriteLog(" | ",8)
+ Do WriteLog("
",6)
+ Do WriteLog("",4)
+ Do WriteLog("
",2)
+ Do WriteLog("")
+ ZN "%SYS"
+ Quit
+
+LogOtherCubeElements
+ Do WriteUpdate("Getting detailed cube information for "_cube_": other cube elements")
+ Do:tracking WriteTrack("cube","Other cube elements",cube)
+ ZN namespace
+ Do WriteLog("
",2)
+ Do WriteLog("
",2)
+ Do WriteLog("
Other Elements for "_cube_"
",2)
+ If ##class(%DeepSee.Utils).%IsCubeAbstract(cube) {
+ Do WriteLog("
Not available because the cube is abstract
",0)
+ ZN "%SYS"
+ Quit
+ }
+ Do ##class(%DeepSee.Utils).%GetPivotVariables(cube,.pivotvars)
+ Do ##class(%DeepSee.Utils).%GetCubeListingFields(cube,.listingfields)
+ Do ##class(%DeepSee.Utils).%GetCubeListings(cube,.listings)
+ Set model = ##class(%DeepSee.Utils).%GetModel(cube)
+ If model="" {
+ Set defaultListingName = ""
+ } Else {
+ Set defaultListingName = model.defaultListing
+ }
+ /// Pivot Variables
+ Do WriteLog("
Pivot Variables
",2)
+ If $D(pivotvars){
+ Do WriteLog("
",2)
+ Do WriteLog("",4)
+ Do WriteLog("",6)
+ Do WriteLog("Name | Description | Default Value | Type | ",8)
+ Do WriteLog("
",6)
+ For ii=1:1:pivotvars{
+ Do WriteLog("",6)
+ Do WriteLog(""_$LG(pivotvars(ii),1)_" | ",8)
+ Do WriteLog(""_$LG(pivotvars(ii),2)_" | ",8) //Description
+ Do WriteLog(""_$LG(pivotvars(ii),3)_" | ",8) //Default Value
+ Do WriteLog(""_$LG(pivotvars(ii),4)_" | ",8) //Type
+ Do WriteLog("
",6)
+ }
+ Do WriteLog("",4)
+ Do WriteLog("
",2)
+ }
+ /// Named sets
+ Do WriteLog("
Named Sets
",2)
+ Do WriteLog("")
+ Merge namedsets = ^DeepSee.Cubes("cubes",cube,"namedSets")
+ If $D(namedsets){
+ Do WriteLog("
",2)
+ Do WriteLog("",4)
+ Do WriteLog("",6)
+ Do WriteLog("Name | Set Expression | ",8)
+ Do WriteLog("
",6)
+ Set ii = $O(namedsets(""))
+ While ii'="" {
+ Do WriteLog("",6)
+ Do WriteLog(""_$LG(namedsets(ii),1)_" | ",8)
+ Do WriteLog(""_$LG(namedsets(ii),2)_" | ",8) //Set Expression
+ Do WriteLog("
",6)
+ Set ii = $O(namedsets(ii))
+ }
+ Do WriteLog("",4)
+ Do WriteLog("
",2)
+ }
+ //Listing fields
+ Do WriteLog("
Listing Fields
",2)
+ If $D(listingfields){
+ Do WriteLog("
")
+ Do WriteLog("",2)
+ Do WriteLog("",4)
+ Do WriteLog("Name | Field Expression | Resource | Description | ",6)
+ Do WriteLog("
",4)
+ Set tIndex = $O(listingfields(""))
+ While tIndex'="" {
+ Do WriteLog("",4)
+ Do WriteLog(""_$LG(listingfields(tIndex),1)_" | ",6)
+ Do WriteLog(""_$LG(listingfields(tIndex),2)_" | ",6)
+ Do WriteLog(""_$G(^DeepSee.Cubes("cubes",cube,"listingFields",$LG(listingfields(tIndex),1),"resource"))_" | ",6)
+ Do WriteLog(""_$LG(listingfields(tIndex),3)_" | ",6)
+ Do WriteLog("
",4)
+ Set tIndex = $O(listingfields(tIndex))
+ }
+ Do WriteLog("",2)
+ Do WriteLog("
")
+ Do WriteLog("")
+ }
+ //Listings
+ Do WriteLog("
Listings
",2)
+ If $D(listings){
+ Do WriteLog("
",2)
+ Do WriteLog("",4)
+ Do WriteLog("",6)
+ Do WriteLog("Listing Name | ",8)
+ Do WriteLog("Fields | ",8)
+ Do WriteLog("Source | ",8)
+ Do WriteLog("Resource | ",8)
+ Do WriteLog("
",6)
+ //Write fields of listing nicely
+ Set listing=$O(listings(""))
+ While listing'="" {
+ //$$$CUSTOM just marks there are listing fields
+ If listing="$$$CUSTOM" {
+ Set listing=$O(listings(listing))
+ Continue
+ }
+ Do WriteLog("",6)
+ Do WriteLog(""_listing_$S((listing=defaultListingName):" (default)",1:"")_" | ",8)
+ Set fieldString=$LG(listings(listing),2)
+ Set listingSource=$LG(listings(listing),5) //Listing source
+ //Resource
+ Set resource = ""
+ Set:(listingSource="cube") resource = $G(^DeepSee.Cubes("cubes",cube,"listing",listing,"resource"))
+ Set:(listingSource="listingGroup") resource = $G(^DeepSee.ListingGroups("cubes",cube,"listing",listing,"resource"))
+ Set listingSource=$S(listingSource="listingGroup":"Listing Group",listingSource="cube":"Cube",1:listingSource)
+ //Custom SQL listing vs normal listing with fields
+ If (fieldString="") {
+ Do WriteLog("*No Fields - Custom SQL Listing* | ",8) //FieldName
+ Do WriteLog(""_listingSource_" | ",8)
+ Do WriteLog(""_resource_" | ",8)
+ Do WriteLog("
",6)
+ //Split listing expression on multiple lines on SQL keywords: FROM, WHERE
+ //Split an write FROM part
+ Set listingExpr = $G(^DeepSee.Cubes("cubes",cube,"listing",listing,"sql"))
+ Set tInd = $FIND($ZCONVERT(listingExpr,"U")," FROM ")
+ Set stub = $E(listingExpr,0,tInd-6)
+ Set listingExpr = $E(listingExpr,tInd-5,*)
+ If tInd {
+ Do WriteLog("",6)
+ Do WriteLog(" | ",8) //Skip Listing Name columns
+ Do WriteLog(""_stub_" | ",8)
+ Do WriteLog(" | ",8) //Skip Listing Name column
+ Do WriteLog(" | ",8) //Skip Listing Name column
+ Do WriteLog("
",6)
+ }
+ //Split an write WHERE part
+ Set tInd = $FIND($ZCONVERT(listingExpr,"U")," WHERE ")
+ Set stub = $E(listingExpr,0,tInd-7)
+ Set listingExpr = $E(listingExpr,tInd-6,*)
+ If tInd {
+ Do WriteLog("",6)
+ Do WriteLog(" | ",8) //Skip Listing Name column
+ Do WriteLog(""_stub_" | ",8)
+ Do WriteLog(" | ",8) //Skip Listing Name column
+ Do WriteLog(" | ",8) //Skip Listing Name column
+ Do WriteLog("
",6)
+ }
+ //Write all that is left
+ Do WriteLog("",6)
+ Do WriteLog(" | ",8)
+ Do WriteLog(""_listingExpr_" | ",8)
+ Do WriteLog(" | ",8) //Skip Listing Name column
+ Do WriteLog(" | ",8) //Skip Listing Name column
+ Do WriteLog("
",6)
+ } Else { //Normal listings
+ //Print the list fields (the source properties) separately in the second column
+ Set fieldList=$LFS(fieldString,",")
+ //Place the first fieldList in the same line
+ Set tInd=0
+ Do WriteLog(" | ",8) //Skip first field column
+ Do WriteLog(""_listingSource_" | ",8)
+ Do WriteLog(""_resource_" | ",8)
+ Do WriteLog("",6)
+ //Do WriteLog("",6)
+ //Write one field per row
+ Set field=$LG(fieldList,$I(tInd))
+ While field'="" {
+ //Try to parse $$$TEXT[] in listings correctly
+ If ($FIND($ZCONVERT(field,"U"),"$$$TEXT[") && '$FIND(field,"]")) { //Typical of Health Insight
+ Set field=field_","_$LG(fieldList,$I(tInd))
+ }
+ //Health Insight has often NVL() || NVL() in listings
+ If ($E($ZCONVERT(field,"U"),1,5)["NVL(") {
+ Set field=field_","_$LG(fieldList,$I(tInd))
+ While ($L(field)<1000) { //Stop in case things go wrong
+ Set fieldafter=$LG(fieldList,tInd+1)
+ If (($E(fieldafter)="'") || ($E(fieldafter)=")")) {
+ Set field=field_","_fieldafter
+ Set tInd=tInd+1
+ } Else {
+ Quit
+ }
+ }
+ }
+ /*//I don't think field can start with single quote but that happens when using eg NVL()
+ If (($E(field)="'") || ($E(field,2)="'")) {
+ Set field=field_$LG(fieldList,$I(tInd))
+ }*/
+ Do WriteLog("
",6)
+ Do WriteLog(" | ",8) //Nothing in the first column
+ Do WriteLog(""_field_" | ",8)
+ Do WriteLog(" | ",8) //Nothing in the 3rd column (Source)
+ Do WriteLog(" | ",8) //Nothing in the 4th column (Resource)
+ Do WriteLog("
",6)
+ Set field=$LG(fieldList,$I(tInd))
+ }
+ }
+ Set listing=$O(listings(listing))
+ }
+ Do WriteLog("",4)
+ Do WriteLog("
",2)
+ } Else{
+ Do WriteLog("No detail listings defined in this cube")
+ }
+ ZN "%SYS"
+ Quit
+
+LogQuerylog
+ //Get last N queries run by each user, where N can be secretly chosen from the prompt instead of Y/N
+
+ Do WriteUpdate("Getting Query Log, DeepSee logs, and cconsole.log")
+ Do:tracking WriteTrack("getlogs","Getting Query Log, DeepSee logs, and cconsole.log","")
+ Do WriteLog("
")
+ Do WriteParagraph("querylog","Query Log")
+ Do WriteLog("
▸ Expand
",2)
+ Do WriteLog("
",2)
+ ZN namespace
+ Do:($D(^DeepSee.QueryLog)<10) WriteLog("
Query log global not found
",2)
+ Quit:($D(^DeepSee.QueryLog)<10)
+ //Get usercount in ^DeepSee.QueryLog
+ Set user=$O(^DeepSee.QueryLog(""))
+ Set usercount=0
+ While (user'="") {
+ Set userqueries(user)=$G(^DeepSee.QueryLog(user))
+ Set usercount=$I(usercount)
+ Set user=$O(^DeepSee.QueryLog(user))
+ }
+ //Show table with number of queries run by users
+ Do WriteHeader4("Users running MDX queries",2)
+ //Do WriteLog("
Number of users = "_usercount_"
")
+ If $D(userqueries) {
+ Do WriteLog("
",2)
+ Do WriteLog("",4)
+ Do WriteLog("",6)
+ Do WriteLog("User ("_usercount_" total) | ",8)
+ Do WriteLog("Queries run | ",8)
+ Do WriteLog("
",6)
+ Set u = $O(userqueries(""))
+ While (u'="") {
+ Do WriteLog("",6)
+ Do WriteLog(""_u_" | ",8)
+ Do WriteLog(""_userqueries(u)_" | ",8)
+ Do WriteLog("
",6)
+ Set u = $O(userqueries(u))
+ }
+ Do WriteLog("",4)
+ Do WriteLog("
",2)
+ }
+ //Show table with the most run queries, 5 by default unless the user used the secret option on prompt
+ Set numqueries = 5
+ Set:(getLogs>1) numqueries = getLogs
+ Do WriteHeader4("Most run queries",2)
+ Do MostRunQueries(numqueries)
+ //Last Query subsection
+ Do WriteHeader4("Last query",2)
+ Do WriteLog("
",2)
+ Set lastquery=$g(^[namespace]DeepSee.LastQuery) //Display last query
+ If lastquery'=""{
+ Do WriteLog(lastquery,0)
+ Use PDev
+ }
+ Do WriteLog("
",2)
+ //Subsection with 5 last queries for each user
+ Do WriteHeader4("MDX queries by user",2)
+ //Show the last 5 queries by default unless the user used the secret option on prompt
+ Do lastNQueries(numqueries)
+ Do WriteLog("
",2) //Close Expand/Collapse div
+ Do WriteLog("")
+ Use PDev
+ Quit
+
+LogDeepSeelog
+ //Processes DeepSee Log file
+ Try {
+ New x
+ Set DSFile=$zu(12)_"DeepSeeTasks_"_namespace_".log"
+ Do WriteLog("
+ Use PDev
+ Quit
+
+LogSidePanel(cubeList,getLogs,numalerts)
+ Do WriteLog("
")
+ Do WriteLog("
×",2)
+ Do WriteLog("
DeepSee Setup",2)
+ If (isInsight || isTrak) {
+ //Set nOverrides=$$CountNodes(namespace,"^DeepSee.Overrides")
+ Do:(nOverrides>=10) WriteLog("
DeepSee Overrides",2)
+ }
+ Do WriteLog("
Server Details",2)
+ Do WriteLog("
Cubes",2)
+ Do WriteLog("
Build/Synch",2)
+ Do WriteLog("
Cube Registry",2)
+ If (($D(cubeList)'=0) && (cubeList'="")) {
+ Do WriteLog("
Cube Info",2)
+ Set cubeListLength=$ll(cubeList)
+ For i=1:1:cubeListLength{
+ Set cube=$LG(cubeList,i)
+ Do:cube'="" WriteLog("
"_cube_"",2)
+ }
+ }
+ If getLogs{
+ Do WriteLog("
Query Log",2)
+ Do WriteLog("
DeepSee Logs",2)
+ }
+ Do WriteLog("
cache.cpf",2)
+ Do:getLogs WriteLog("
cconsole.log",2)
+ Do WriteLog("
Mappings",2)
+ Do WriteLog("
Local Databases",2)
+ Do WriteLog("
Task Schedule",2)
+ Do WriteLog("
Journaling",2)
+ Set colorclass=$S(numalerts: "red",1:"")
+ Do WriteLog("
Alerts ("_numalerts_")",2)
+ Do WriteLog("
")
+ Quit
+
+LogCloseBody
+ Do WriteLog("")
+ Do WriteLog("")
+ Do WriteUpdate("DeepSeeButtons report saved to "_LogFile)
+ Do:tracking WriteTrack("save","DeepSeeButtons report saved to ",LogFile)
+ Do WriteUpdate("Done")
+ Do:tracking WriteTrack("complete","Complete","")
+ Quit
+
+
+/// More helper functions for the Log* functions above
+ValidateNamespace(namespace) [namespace]{
+ Set namespace=$ZCONVERT(namespace, "U")
+ Try {
+ ZN namespace
+ return namespace
+ } Catch ex {
+ Write !,namespace," is invalid. Please enter a valid namespace."
+ Set namespace=""
+ Return namespace
+ }
+}
+
+Init()
+ //Sets routine-wide variables
+ New i,LogFilePrefix,v,x
+ Set PDev=$Principal
+ Set CRLF=$Char(13,10)
+ Set CmdOpenTimeOut=60
+ Set CmdReadTimeOut=30
+ Set FileOpenTimeOut=5
+ Set FileReadTimeOut=30
+ Set CacheVerStr=$ZVersion
+ Set CacheVerNumber=$System.Version.GetNumber()
+ Set HostName=$ZUtil(54,0)
+ Set CacheDir=""
+
+ Set IPAddr="unknown"
+ Set FullHostName="unknown"
+ Try {
+ //$zversion(0) is a bit string that informs what features are enabled in cache'.
+ //It can fail behind a firewalls
+ #define USEIPV6 $zbitget($zversion(0)_$c(0,0,0,0),42)
+ #define HostNameToIPText(%h,%f) $s($$$USEIPV6:$SYSTEM.INetInfo.HostNameToAddr(%h,%f),1:$p($ZU(54,13,%h),",",1))
+ #define IPTextToBinary(%ip) $s($$$USEIPV6:$SYSTEM.INetInfo.TextAddrToBinary(%ip),1:$ZU(54,1,%ip))
+ #define IPBinaryToHostName(%ip) $s($$$USEIPV6:$SYSTEM.INetInfo.AddrToHostName(%ip),1:$p($ZU(54,14,%ip),",",2))
+ #define IPTextToHostName(%ip) $$$IPBinaryToHostName($$$IPTextToBinary(%ip))
+ Set IPAddr=$$$HostNameToIPText(HostName,0)
+ Set FullHostName=$$$IPTextToHostName(IPAddr)
+ } Catch(ex) {
+ Set tSC = ex.AsStatus()
+ Set FullHostName="Unknown"
+ Set IPAddr="unknown (due to "_$System.Status.GetErrorText(tSC)_")"
+ }
+ Set MgrDir=$ZUtil(12)
+ Set MgrNsp=$$ST()
+ Set CurDir=$ZUtil(12,"")
+ Set CurNsp=$ZUtil(5)
+ Set x=$ZUtil(86),ConfigFile=$Piece(x,"*",1),ConfigName=$Piece(x,"*",2)
+ Set CurUser=$ZUtil(67,11,$Job)
+ Set CustomerName=$System.License.KeyCustomerName()
+ Set OrderNumber=$System.License.KeyOrderNumber()
+ //Equivalent to $System.Version.GetCompBuildOS()
+ //Get if Trak or HealthInsight
+ Set isInsight=$$isHealthInsight(namespace) //Determine if this is a Health Insight namespace (1 if yes)
+ Set isTrak=$$isTrak(namespace) //Determine if this is a Health Insight namespace (1 if yes)
+ Set nOverrides = ""
+ Set:(isInsight || isTrak) nOverrides=$$CountNodes(namespace,"^DeepSee.Overrides")
+ Set v=$ZVersion,v=$ZConvert(v,"l")
+ If v["windows" Set OS="WinNT" //Windows NT, 2000, XP or 2003 Server
+ Else If v["unix" Set OS="UNIX"
+ Else If v["openvms" Set OS="VMS"
+ Else Set OS="*** Unrecognized OS ***"
+ If OS?1"***".e Quit
+ If (OS?1"Win".e) {
+ Set DirDelim="\"
+ Set NullDev="//./nul"
+ Do SetDirs
+ Set KeyFile=MgrDir_DirDelim_"Cache.key"
+ Set BinDir=CacheDir_DirDelim_"Bin"
+ } ElseIf (OS="UNIX") {
+ Set DirDelim="/"
+ Set NullDev="/dev/null/"
+ Do SetDirs
+ Set KeyFile=MgrDir_DirDelim_"cache.key"
+ Set BinDir=CacheDir_DirDelim_"bin"
+ } ElseIf (OS="VMS") {
+ Set DirDelim="."
+ Set NullDev="NL:"
+ Do SetDirs
+ Set KeyFile=MgrDir_"CACHE.KEY"
+ Set i=$Find(MgrDir,".MGR")
+ Set BinDir=$Extract(MgrDir,1,i-$Length(".MGR")-1)_".BIN"_$Extract(MgrDir,i,*)
+ }
+ Quit
+
+InitLogFile()
+ Set LogFilePrefix=""
+ Set FileOpenTimeOut=5
+ Set CustomerName=$System.License.KeyCustomerName()
+ If CustomerName'="" Set LogFilePrefix="DeepSeeButtons_"_$Piece(CustomerName," ",1)_"_"
+ If LogFilePrefix'="",LogFilePrefix?1a.an,$Length(LogFilePrefix)<20
+ Set:LogFile="" LogFile=$$NewFile(LogFilePrefix,"html")
+ Quit LogFile
+
+ST()
+ //Sets the Manager's Namespace (also hardcoded in %ST)
+ ZN "%SYS"
+ New
+ Do ^ST
+ Set MgrNsp=%ST("MGRNSP")
+ Quit MgrNsp
+
+DialogCubes(namespace) {
+ Set cubeString=""
+ ZN namespace
+ Do ##class(%DeepSee.Utils).%GetCubeList(.cubeList,,1)
+ If '$D(cubeList){
+ Write !,"There are no cubes in this namespace!"
+ Set cubeList=""
+ Quit cubeList
+ }
+ Do {
+ Set cube=""
+ Write !,"Give cube name for detailed cube info or press enter to continue: "
+ Read cube
+ Set:cube="?" cube=$$ListCubes()
+ If (cube="")||(cube="QUIT")||(cube="Q") {
+ Quit
+ } ElseIf (cube'="") {
+ If ($LISTFIND($LISTFROMSTRING(cubeString),$ZCONVERT(cube,"t"))'=0) {
+ Write !,"Cube already selected"
+ Set cube=""
+ } ElseIf (cube="ALL") { //problem: it asks again
+ Set cubeString=$$GetAllCubes(namespace)
+ Set cube="QUIT" //prob useless
+ Quit
+ } ElseIf ##class(%DeepSee.Utils).%CubeExists(cube,.status)'=1 {
+ Write !,cube," is an invalid cube selection: "
+ Write !,"Enter '?' to see list of cubes in the "_namespace_" namespace",!
+ //Set cube=""
+ } Else {
+ Set cube=$ZCONVERT(cube,"t") //Make cube name uppercase to normalize names
+ Set cubeString=cubeString_","_cube
+ }
+ }
+ } While (cube'="")&&(cube'="QUIT")&&(cube'="Q")
+ Set:$E(cubeString,0,1)="," cubeString=$p(cubeString,",",2,*) //Eliminate leading comma
+ Set cubeSelection=$LFS(cubeString,",") //Create list
+ ZN "%SYS"
+ Quit cubeSelection
+}
+
+GetAllCubes(namespace)
+ Set cubeString=""
+ ZN namespace
+ Do ##class(%DeepSee.Utils).%GetCubeList(.cubeList,,1)
+ Set cubeString=""
+
+ Set cubetmp=$Order(cubeList(""))
+ While (cubetmp'="") {
+ Set cubeString=cubeString_","_cubetmp
+ Set cubetmp=$Order(cubeList(cubetmp))
+ }
+
+ Set cubeString=$P(cubeString,",",2,*)
+ ZN "%SYS"
+ Quit cubeString
+
+VerifyInputCubes(cubeList,namespace,tracking=0){
+ Set len=$LISTLENGTH(cubeList)
+ For i=1:1:len{
+ Set cube=$LG(cubeList,i)
+ Set cube=$ZCONVERT(cube, "U")
+ ZN namespace
+ If ##class(%DeepSee.Utils).%CubeExists(cube,.status)'=1 {
+ Write !!, cube_": invalid cube selection. It will not be included in the report"
+ //Do $system.OBJ.DisplayError(status)
+ Do:tracking WriteTrack("warning","",cube,"invalid cube selection. It was not included in the report")
+ Set cube=""
+ }
+ Set $LIST(cubeList,i)=cube //Change element in list to uppercase version (or null if it didn't exist)
+ }
+ ZN "%SYS"
+ Quit cubeList
+}
+
+SetDirs
+ //Sets Cache Installation Directory
+ New i,Dev,Dir
+ If OS?1"Win".e!(OS="UNIX") Do
+ . If $Extract(MgrDir,$Length(MgrDir))=DirDelim Set MgrDir=$Extract(MgrDir,1,$Length(MgrDir)-1) //Remove trailing \ or /
+ . If $Extract(CurDir,$Length(CurDir))=DirDelim Set CurDir=$Extract(CurDir,1,$Length(CurDir)-1) //Remove trailing \ or /
+ . Quit
+ Else If OS="VMS" Do
+ . Set MgrDir=$$VMSCanonize(MgrDir)
+ . Set CurDir=$$VMSCanonize(CurDir)
+ . Quit
+ If OS?1"Win".e!(OS="UNIX") Set i=$Length(MgrDir,DirDelim)-1,CacheDir=$Piece(MgrDir,DirDelim,1,i)
+ Else If OS="VMS" Do
+ . Set Dev=$Piece(MgrDir,":",1),Dir=$Piece(MgrDir,":",2,$$$MaxPieceNum)
+ . If $Extract(Dir,1)="[" Set Dir=$Extract(Dir,2,*)
+ . If $Extract(Dir,$Length(Dir))="]" Set Dir=$Extract(Dir,1,$Length(Dir)-1)
+ . Set Dir=$Piece(Dir,".",1,$Length(Dir,".")-1)
+ . Set Dir="["_Dir_"]"
+ . Set CacheDir=Dev_":"_Dir
+ . Quit
+ Quit
+
+ListCubes(){
+ Do ##class(%DeepSee.Utils).%GetCubeList(.cubeList,,1)
+ Write !, "Cubes in this namespace: ",!!
+ Set cubetmp=""
+
+ Set cubetmp=$order(cubeList(""))
+ While (cubetmp'="") {
+ Write cubetmp,!
+ Set cubetmp=$order(cubeList(cubetmp))
+ }
+ Write "ALL",!
+ Write !, "Give cube name for detailed cube info or press enter to continue: "
+ Read cube
+
+ Quit cube //returns "" if no cube number entered
+}
+
+LongName(x)
+ New (OS,x)
+ Set x=$Get(x,"")
+ If OS="VMS" Quit x
+ Set Space=$Char(32),Quote=$Char(34)
+ If x[Space Set x=Quote_x_Quote
+ Quit x
+
+VMSCanonize(Dir)
+ New (Dir)
+ Set Dev=$Piece(Dir,":",1),Dir=$Piece(Dir,":",2,$$$MaxPieceNum)
+ Set Dir=$Translate(Dir,"<","[") //Replace < by [
+ Set Dir=$Translate(Dir,">","]") //Replace > by ]
+ Set i=$Length(Dir,"[")-1
+ If i>1 Do //Directory format is [DIR.][SUBDIR]...
+ . If $Extract(Dir,1)="[" Set Dir=$Extract(Dir,2,*)
+ . If $Extract(Dir,$Length(Dir))="]" Set Dir=$Extract(Dir,1,$Length(Dir)-1)
+ . For Quit:$Piece(Dir,"[",2)="" Set Dir=$Piece(Dir,"[",1)_$Piece(Dir,"[",2,$$$MaxPieceNum)
+ . For Quit:$Piece(Dir,"]",2)="" Set Dir=$Piece(Dir,"]",1)_$Piece(Dir,"]",2,$$$MaxPieceNum)
+ . Set Dir="["_Dir_"]"
+ . Quit
+ Set Dir=Dev_":"_Dir
+ Quit Dir
+
+WriteLastStartup
+ Try {
+ Set timein=$ZHorolog\1, now=$Horolog
+ Set timeup=timein
+ Set days=timeup\86400
+ Set timeup=timeup-(days*86400)
+ Set hours=timeup\3600
+ Set timeup=timeup-(hours*3600)
+ Set minutes=timeup\60
+ Set timeup=timeup-(minutes*60)
+ Set seconds=timeup
+ Set today=+now
+ Set secs=$Piece(now,",",2)
+ Set now=(today*86400)+secs
+ Set then=now-timein
+ Set odays=then\86400
+ Set osecs=then-(odays*86400)
+ Set oh=odays_","_osecs
+ Do WriteLog("
"_$ZDATETIME(oh,3)_". As of this report Caché has been up for "_days_" days "_hours_" hours "_minutes_" minutes "_seconds_" seconds"_"
",8)
+ } Catch(ex) {
+ Set tSC = ex.AsStatus()
+ Do WriteLog($System.Status.GetErrorText(tSC),10)
+ Do:tracking WriteTrack("warning","","WriteLastStartup",$System.Status.GetErrorText(tSC))
+ }
+ Quit
+
+isHealthInsight(namespace){
+ Try{
+ ZN namespace
+ Set HealthShare=##class(%SYSTEM.License).GetFeature(12) //Look in license for HealthShare Foundation
+ ZN "%SYS"
+ Return HealthShare
+ } Catch {
+ ZN "%SYS"
+ Return 0 //Method did not work so return 0
+ }
+}
+
+isTrak(namespace){
+ Try{
+ ZN namespace
+ Set BitTrakCare = ##class(%SYSTEM.License).GetFeature(6) //BitTrakCare
+ ZN "%SYS"
+ Return BitTrakCare
+ } Catch {
+ ZN "%SYS"
+ Return 0 //Method did not work so return 0
+ }
+}
+
+NLS
+ Try {
+ New LocCur,LocDesc,LocSrc,oLoc
+ Do WriteHeader4("Current Locale",8)
+ ZN "%SYS"
+ Set oLoc=##class(Config.NLS.Locales).OpenCurrent()
+ If oLoc="" Set LocCur="Unknown",LocDesc="Unknown"
+ Else Set LocCur=oLoc.Name,LocDesc=oLoc.Description
+ Set LocSrc=$$ComputeFullDBDir^%SYS.API("Locale")
+ Do WriteLog("
"_LocCur_" ("_LocDesc_")
",8)
+ } Catch(ex) {
+ Set tSC = ex.AsStatus()
+ Do WriteLog($System.Status.GetErrorText(tSC),10)
+ Do:tracking WriteTrack("warning","","NLS",$System.Status.GetErrorText(tSC))
+ }
+ Quit
+
+OSVer
+ //This is almost the same as the OSVer function in ^Buttons
+ Try {
+ //Add the OS version to LogFile
+ New Cmd,uname
+ Do WriteHeader4("Operating System Version",8)
+ Do WriteLog("
",8)
+ If OS?1"Win".e Set Cmd="Ver"
+ If OS="UNIX" Set Cmd="uname -a"
+ If OS="VMS" Set Cmd="WRITE SYS$OUTPUT ""OpenVMS "",F$GETSYI(""VERSION"")"
+ Do ExternalCmd(Cmd)
+ //Do ExternalCmd^Buttons(Cmd)
+ If OS="UNIX" Set uname=$$uname()
+ If ($D(uname) && (uname?1"AIX".e)) {
+ Do WriteLog(" -- ",8)
+ Do ExternalCmd("lsattr -El proc0")
+ //Do ExternalCmd^Buttons("lsattr -El proc0")
+ }
+ } Catch(ex) {
+ Set tSC = ex.AsStatus()
+ Do WriteLog($System.Status.GetErrorText(tSC),10)
+ Do:tracking WriteTrack("warning","","OSVer",$System.Status.GetErrorText(tSC))
+ }
+ Do WriteLog("
",8)
+ Quit
+
+uname()
+ New (CmdOpenTimeOut,CmdReadTimeOut,PDev)
+ Set Cmd="uname -s"
+ Open Cmd:"RQ":CmdOpenTimeOut
+ If '$Test Quit ""
+ Try {
+ Use Cmd Read uname:CmdReadTimeOut Use PDev
+ } Catch(ex) {
+ Set tSC = ex.AsStatus()
+ }
+ Close Cmd
+ Quit uname
+
+RAM
+ Do WriteHeader4("RAM",8)
+ //First refresh CPU info
+ Do $ZU(204,0)
+ Do WriteLog("
Model: "_$ZU(204,2)_"
",8)
+ Do WriteLog("
Chips: "_$ZU(204,6)_"
",8)
+ Do WriteLog("
Cores: "_$ZU(204,5)_"
",8)
+ Do WriteLog("
Threads: "_$ZU(204,4)_"
",8)
+ Do WriteLog("
Frequency: "_$ZU(204,11)_" MHz
",8)
+ Set temp = $ZU(190,18)
+ Do WriteLog("
Total physical memory: "_$FNUMBER($P(temp,",",1)/1024,",",0)_" MB
",8)
+ Do WriteLog("
Free physical memory: "_$FNUMBER($P(temp,",",2)/1024,",",0)_" MB
",8)
+ Do WriteLog("
Total paging/swap space: "_$FNUMBER($P(temp,",",3)/1024,",",0)_" MB
",8)
+ Do WriteLog("
Free paging/swap space: "_$FNUMBER($P(temp,",",4)/1024,",",0)_" MB
",8)
+ Do WriteLog("",8)
+ Quit
+
+DiskSpace
+ Do WriteHeader4("Disk space",8)
+ Do ##class(%File).DriveListExecute(.drivelist)
+ For {
+ Set st=##class(%File).DriveListFetch(.drivelist,.drive,.AtEnd)
+ Set drive = $LG(drive)
+ Do ##class(%Library.File).GetDirectorySpace(drive,.free,.total,1)
+ Do WriteLog("
Total space in """_drive_""" drive: "_$FNUMBER(total,",",0)_" MB
",8)
+ Do WriteLog("
Free space in """_drive_""" drive: "_$FNUMBER(free,",",0)_" MB
",8)
+ Quit:AtEnd
+ }
+ Quit
+
+CountNodes(namespace,g){
+ ZN namespace
+ Return:'$D(@g) 0
+ For count=$D(@g)#10:1 Set g=$Query(@g) Quit:g=""
+ Return count
+}
+
+GetLastBuild(CubeEvent,cubename) [cubename,CubeEvent,cubekey,cubeevent,totaltime,cubesize,finishtime,factsupdated,SQLCODE] {
+ new cubekey,totaltime,cubesize,finishtime,factsupdated,SQLCODE
+
+ Set sql ="SELECT TOP 1 CubeKey,TotalTime,CubeSize,FinishTime,FactsUpdated " _
+ "FROM %DeepSee_CubeManager.CubeEvent " _
+ "WHERE CubeEvent='"_CubeEvent_"' "_
+ $S($D(cubename):"AND CubeKey='"_cubename_"' ",1:"") _
+ "ORDER BY FinishTime DESC"
+ Set rs = ##class(%SQL.Statement).%ExecDirect(.S,sql)
+
+ Set SQLCODE=""
+ If rs.%Next() {
+ Set cubekey = rs.%Get("CubeKey")
+ Set totaltime = rs.%Get("TotalTime")
+ Set cubesize = rs.%Get("CubeSize")
+ Set finishtime = rs.%Get("FinishTime")
+ Set factsupdated = rs.%Get("FactsUpdated")
+ Set SQLCODE = rs.%SQLCODE
+ }
+
+ IF SQLCODE=0 {
+ If CubeEvent="Synch"{
+ Set string=$FNUMBER(factsupdated,"O,")_" facts synched on "_finishtime_" in "_totaltime_" seconds"
+ } ElseIf CubeEvent="Build"{
+ Set string=$FNUMBER(cubesize,"O,")_" facts built on "_finishtime_" in "_totaltime_" seconds"
+ } ElseIf CubeEvent="Update"{
+ Set string="on "_finishtime
+ } ElseIf CubeEvent="Repair"{
+ Set string=$FNUMBER(cubesize,"O,")_" facts built on "_finishtime_" in "_totaltime_" seconds"
+ } Else {
+ Set string=CubeEvent_" event on "_finishtime_" in "_totaltime
+ }
+ Set:'$D(cubename) string = string_" for the "_cubekey_" cube"
+ } ElseIf SQLCODE=100 {
+ Set string = "Not found"
+ } Else {
+ Set string = "SQL Error code: "_SQLCODE
+ }
+ Quit string
+}
+
+GetRelationships(cube){
+ Quit:##class(%DeepSee.Utils).%IsCubeCompound(cube) //Can't have a related, compound cube
+ Set status=##class(%DeepSee.Utils).%GetDimensionList(cube,.dimlist)
+ Set nodenum=$O(dimlist(""),-1) //Get last node in dimlist
+ Set count=0
+ If status=1 {
+ For {
+ If $LG(dimlist(nodenum,0,0),1)="r"{ //If dimension is a relationship...
+ Set count=count+1 //increment count
+ Set dimname=$LG(dimlist(nodenum,0,0),2) //Get name of relationship
+ Set relationships(count)=##class(%DeepSee.Utils).%GetRelatedCube(cube,dimname) //Related cube name
+ }
+ Quit:nodenum=0 //If no dimensions defined, first node will be 0
+ Set nodenum=$O(dimlist(nodenum),-1)
+ Quit:$LG(dimlist(nodenum,0,0),1)'="r"
+ }
+ If count=0 {
+ Write " "
+ } Else {
+ For i=1:1:count {
+ If $g(relationships(i),"null")'="null" {
+ Write relationships(i)
+ Write:(i'=count) ", "
+ }
+ }
+ }
+ }
+ Quit
+}
+
+GetSourceClass(cube,type)[storageList, dataConnectorList]{
+ Try {
+ Set sourceClass=""
+ If type="cube" {
+ Set cubeObj=##class(%DeepSee.Utils).%GetModel(cube)
+ If cubeObj=""{
+ Set sourceClass = "Subject area class not compiled"
+ Quit
+ }
+ Set sourceClass=cubeObj.sourceClass //Source Class name
+ If sourceClass=""&&isInsight{
+ Set sourceClass=^DeepSee.Overrides(cube,"SOURCECLASS") //Source class isn't part of cube object
+ }
+ Set classObj=##class(%Dictionary.CompiledClass).%OpenId(sourceClass)
+ Set storage=classObj.StorageStrategy
+
+ Set super=classObj.Super
+
+ If storage["SQLStorage"{
+ Set $LIST(storageList,*+1)=cube
+ }
+ If super["%DeepSee.DataConnector"{
+ Set $LIST(dataConnectorList,*+1)=cube
+ }
+ } ElseIf type="subjectArea" {
+ Set basecube=##class(%DeepSee.Utils).%GetBaseCube(cube)
+ Do ##class(%DeepSee.Utils).%GetCubeList(.plist)
+ Set typebasecube = $LG(plist(basecube),4)
+ Set sourceClass = $$GetSourceClass(basecube,typebasecube)
+ } Else {
+ Set sourceClass="Not available"
+ }
+ } catch {
+ Set sourceClass = "Not available"
+ }
+ Quit sourceClass
+}
+
+GetCountStar(sqlclass){
+ Try {
+ Set FactCount=""
+ Set SQLQuery="SELECT COUNT(*) As FactCount FROM "_sqlclass
+ Set tStatement = ##class(%SQL.Statement).%New()
+ Set st = tStatement.%Prepare(SQLQuery)
+ If 'st {
+ Set FactCount = $System.Status.DisplayError(st)
+ Quit
+ }
+ Set rset = tStatement.%Execute()
+ If (rset.%SQLCODE < 0) {
+ Set FactCount = rset.%Message
+ Quit
+ }
+ Do rset.%Next()
+ Set FactCount = rset.FactCount
+ } Catch(ex) {
+ Set FactCount = ex.AsStatus()
+ Do $System.Status.DisplayError(tSC)
+ }
+ Quit FactCount
+}
+
+GetDeepSeeAuditCode
+ Kill auditcode,querycode
+ Do WriteHeader4("Audit",8)
+ Try {
+ If $D(^[namespace]DeepSee.AuditCode){
+ Set auditcode=$g(^[namespace]DeepSee.AuditCode)
+ Do WriteLog("
DeepSee.AuditCode: "_auditcode_"
",8)
+ } Else{
+ Do WriteLog("
^DeepSee.AuditCode is undefined
",8)
+ }
+ If $D(^[namespace]DeepSee.AuditQueryCode){
+ Set querycode=$g(^[namespace]DeepSee.AuditQueryCode)
+ Do WriteLog("
DeepSee.AuditQueryCode: "_querycode_"
",8)
+ } Else{
+ Do WriteLog("
^DeepSee.AuditQueryCode is undefined
",8)
+ }
+ } Catch {
+ Write "Not Available"
+ }
+ Quit
+
+GetBuildTime(cube)
+ [time,cube] PUBLIC{
+ new time
+ Set cube=$zconvert(cube,"u")
+
+ Set sql ="SELECT TotalTime FROM %DeepSee_CubeManager.CubeEvent where cubekey='" _
+ cube _ "' and cubeevent='Build' order by finishtime desc"
+ Set rs = ##class(%SQL.Statement).%ExecDirect(.S,sql)
+
+ If rs.%Next() {
+ Quit rs.%Get("TotalTime")
+ } Else{
+ Quit ""
+ }
+}
+
+FieldNameToSpec(pCubeName) {
+ Set tSC = $$$OK
+ Q:pCubeName=""
+ Try {
+ Set tCube = $G(^DeepSee.Cubes("cubes",$zu(28,pCubeName,5),"indexName"),$zu(28,pCubeName,5))
+ //Loop over indD,indH,indL in ^DeepSee.Cubes("cubes",tCube,"mbr#",indD,indH,indL)
+ Set indD = $O(^DeepSee.Cubes("cubes",tCube,"mbr#",""))
+ While (indD '= "") {
+ Set indH = $O(^DeepSee.Cubes("cubes",tCube,"mbr#",indD,""))
+ While (indH '= "") {
+ Set indL = $O(^DeepSee.Cubes("cubes",tCube,"mbr#",indD,indH,""))
+ While (indL '= "") {
+ Set list = ^DeepSee.Cubes("cubes",tCube,"mbr#",indD,indH,indL)
+ Set type = $LG(list,1)
+ Set tIndex = $LG(list,5)
+ If ((tIndex'="") && ((type="l") || (type="m") || (type="r"))) {
+ Set tIndexName = $S($E(tIndex)="M":$G(^DeepSee.Cubes("cubes",tCube,"msr#",tIndex),tIndex),
+ 1:$G(^DeepSee.Cubes("cubes",tCube,"fact#",tIndex),tIndex))
+ If ($D(^DeepSee.Cubes("cubes",tCube,"fact","prop",tIndexName,"alias"))) {
+ Set tIndexName = ^DeepSee.Cubes("cubes",tCube,"fact","prop",tIndexName,"alias")
+ }
+ If ((type="l") && (tIndexName'="") && (tIndex>1)) { //Also skipping %Search with tIndex=1
+ Set dimname = $LG(list,2)
+ Set hiername = $LG(list,3)
+ Set levelname = $LG(list,4)
+ Set fieldname2spec(tIndexName) = "["_dimname_"].["_hiername_"].["_levelname_"]"
+ Write !,?4,tIndexName,?41," ",fieldname2spec(tIndexName)
+ } ElseIf ((type="m") && (tIndex'="")) { //e.g. COUNT has no tIndex
+ Set dimname = $LG(list,2) //this is always "Measures"
+ Set measname = $LG(list,3)
+ If '$D(fieldname2spec(tIndexName)) {
+ Set fieldname2spec(tIndexName) = "["_dimname_"].["_measname_"]"
+ } Else {
+ Set fieldname2spec(tIndexName) = fieldname2spec(tIndexName)_", ["_dimname_"].["_measname_"]"
+ }
+ Set fieldname2spec(tIndexName) = "["_dimname_"].["_measname_"]"
+ Write !,?4,tIndexName,?41," ",fieldname2spec(tIndexName)
+ } ElseIf (type="r") {
+ Set dimname = $LG(list,2)
+ Set fieldname2spec(tIndexName) = "["_dimname_"]"
+ Write !,?4,tIndexName,?41," ",fieldname2spec(tIndexName)
+ }
+ }
+ Set indL = $O(^DeepSee.Cubes("cubes",tCube,"mbr#",indD,indH,indL))
+ }
+ Set indH = $O(^DeepSee.Cubes("cubes",tCube,"mbr#",indD,indH))
+ }
+ Set indD = $O(^DeepSee.Cubes("cubes",tCube,"mbr#",indD))
+ }
+ Set tSC = $$$OK
+ }
+ Catch(ex) {
+ Set tSC = ex.AsStatus()
+ }
+}
+
+MostRunQueries(numqueries)
+ //Show table with the most run queries
+ //Use $ZCRC(,7) to hash an MDX query, then create two arrays:
+ // queryarr(hashed MDX query) = frequency
+ // crcarr(hashed MDX query) = MDX query
+ Set u = ""
+ Set i = ""
+ For {
+ Set u = $O(^DeepSee.QueryLog(u))
+ Quit:u=""
+ For {
+ Set i = $O(^DeepSee.QueryLog(u,i))
+ Quit:i=""
+ //Strip some patterns from MDX queries
+ Set strippedquery = $ZSTRIP(^DeepSee.QueryLog(u,i),"*C") //strip control characters
+ Set strippedquery = $REPLACE(strippedquery,", ",",") //replace ", "
+ Set strippedquery = $ZSTRIP(strippedquery,"<=>W") //strip leading, trailing, and repeating white spaces
+ Set crc = $ZCRC(strippedquery,7)
+ If $D(queryarr(crc)) {
+ Set queryarr(crc) = $I(queryarr(crc))
+ } Else {
+ Set queryarr(crc) = 1
+ Set crcarr(crc) = strippedquery
+ }
+ }
+ }
+ //Reverse the queryarr array to get frequencies handy:
+ // freqarr(frequency, hashed MDX query) = MDX query
+ Set c = ""
+ For {
+ Set c = $O(queryarr(c))
+ Quit:c=""
+ Set f = queryarr(c)
+ Set freqarr(f,c) = crcarr(c)
+ }
+ //Print
+ Do WriteLog("
",2)
+ Do WriteLog("",4)
+ Do WriteLog("",6)
+ Do WriteLog("# | ",8)
+ Do WriteLog("Frequency | ",8)
+ Do WriteLog("Query | ",8)
+ Do WriteLog("
",6)
+ Set freq = ""
+ For n = 1:1:numqueries {
+ Set freq = $O(freqarr(freq),-1)
+ Quit:freq=""
+ Do WriteLog("",6)
+ Do WriteLog(""_n_" | ",8)
+ Do WriteLog(""_freq_" | ",8)
+ Do WriteLog("",8)
+ Set hashed=""
+ Set counter = 0
+ For {
+ Set hashed=$O(freqarr(freq,hashed))
+ Quit:hashed=""
+ Do:counter=7 WriteLog(" ... ",10) //Show up to 6 queries per frequency
+ Quit:counter=7
+ Set query = freqarr(freq,hashed)
+ Do WriteLog(""_$$encode(query)_" ",10)
+ Set counter= $I(counter)
+ }
+ Do WriteLog(" | ",8)
+ Do WriteLog("
",6)
+ }
+ Do WriteLog("",4)
+ Do WriteLog("
",2)
+ Quit
+
+lastNQueries(numqueries)
+ Do WriteLog("
",4)
+ Set username=""
+ For k=1:1 {
+ Set numqueriesuser = numqueries
+ Set username=$O(^DeepSee.QueryLog(username),1)
+ If username="" Quit
+ Set totqueries=$O(^DeepSee.QueryLog(username,""),-1)
+ Set:totqueriestotqueries //User has fewer than 5 queries
+ Set counter=$O(^DeepSee.QueryLog(username,counter),-1)
+ Set query=$Get(^DeepSee.QueryLog(username,counter))
+ If query'=""{
+ Do WriteLog( i_") "_$$encode(query),0)
+ }
+ }
+ }
+ Do WriteLog("
",2)
+ Quit
+
+encode(string) {
+ Quit $ZCVT(string,"O","HTML")
+}
+
+/// Alerts
+alertRoutineSize(RoutineSize,alerts) {
+ Try {
+ If (RoutineSize=0) {
+ Set pre="title=""Routine buffers have the default ''0'' value and might need customization"">"
+ Set alert = "Alert: Routine buffers have not been customized"
+ Set alerts($I(alerts)) = pre_alert
+ Do WriteLog("
",8)
+ }
+ Set tSC = 1
+ } Catch (ex) {
+ Set tSC = ex.AsStatus()
+ Do $System.Status.DisplayError(tSC)
+ }
+ Quit tSC
+}
+
+alertGlobalKSize(GlobalKSize,alerts) {
+ Try {
+ If (GlobalKSize="0,0,0,0,0,0") {
+ Set pre="title=""Global buffers have the default ''0,0,0,0,0,0'' values and might need customization"">"
+ Set alert = "Alert: Global buffers have not been customized"
+ Set alerts($I(alerts)) = pre_alert
+ Do WriteLog("
",8)
+ }
+ Set tSC = 1
+ } Catch (ex) {
+ Set tSC = ex.AsStatus()
+ Do $System.Status.DisplayError(tSC)
+ }
+ Quit tSC
+}
+
+alertDStimeRW(DSTimeMapFrom,alerts) {
+ Try {
+ ZN "%SYS"
+ //Check if DB is Read-Write
+ Set sc = ##class(Config.Databases).Get(DSTimeMapFrom, .prop)
+ //If a remote DB is used we do not know
+ If prop("Server")'="" {
+ Set db=##Class(SYS.Database).%OpenId(prop("Directory"))
+ Set readonly = db.ReadOnly
+ If readonly {
+ Set pre="title=""In Caché versions including DevChange DTB422 ^OBJ.DSTIME and ^DeepSee.Update should be mapped to a Read-Write database"">"
+ Set alert = "Alert: ^OBJ.DSTIME and/or ^DeepSee.Update are stored in the "_DSTimeMapFrom_" database, which should be Read-Write"
+ Set alerts($I(alerts)) = pre_alert
+ Do WriteLog("
",8)
+ }
+ }
+ Set tSC = 1
+ } Catch (ex) {
+ Set tSC = ex.AsStatus()
+ Do $System.Status.DisplayError(tSC)
+ }
+ Quit tSC
+}
+
+alertCacheMappings(ns,alerts) {
+ Try {
+ //Check if ^DeepSee.Cache.Results, .Axis, .Cells end up in a journaled DB
+ ZN "%SYS"
+ Set tSC = $$$OK
+ Set DSCacheGlobals = $LB("DeepSee.Cache.Results","DeepSee.Cache.Axis","DeepSee.Cache.Cells")
+ While 1 {
+ Set cacheGlob=$LG(DSCacheGlobals,$I(i))
+ Quit:(cacheGlob="")
+ Set sysdir=##class(%SYS.Namespace).GetGlobalDest(ns,cacheGlob)
+ //sysdir is system^directory, but only the directory is needed for the following call
+ Set DB=##class(SYS.Database).%OpenId($P(sysdir,"^",2))
+ If (DB.GlobalJournalState = 3) {
+ Do ##Class(Config.Databases).DatabasesByDirectory($P(sysdir,"^",1),$P(sysdir,"^",2),.listDB)
+ Set DBname=$LISTTOSTRING(listDB,",") //In general I would expect one DB but there could be more
+ Set pre="title=""Journaling the DeepSee cache leads to problems with disk size and query performance"">"
+ Set alert = "Alert: The DeepSee cache stored in the "_DBname_" database is journaled"
+ Set alerts($I(alerts)) = pre_alert
+ Do WriteLog("
",8)
+ Quit
+ }
+ }
+ } Catch (ex) {
+ Set tSC = ex.AsStatus()
+ Do WriteLog("
",8)
+ }
+ Quit tSC
+}
+
+alertJoinIndexMappings(ns,alerts) {
+ Try {
+ //Check if ^DeepSee.JoinIndex ends up in a journaled DB.
+ //It should go with the cache but it is less bad than journaling ^DeepSee.Cache* globals.
+ //For this reason I keep this alert separate from alertCacheMappings
+ ZN "%SYS"
+ Set tSC = $$$OK
+ Set cacheGlob = "DeepSee.JoinIndex"
+ Set sysdir=##class(%SYS.Namespace).GetGlobalDest(ns,cacheGlob)
+ //sysdir is system^directory, but only the directory is needed for the following call
+ Set DB=##class(SYS.Database).%OpenId($P(sysdir,"^",2))
+ If (DB.GlobalJournalState = 3) {
+ Do ##Class(Config.Databases).DatabasesByDirectory($P(sysdir,"^",1),$P(sysdir,"^",2),.listDB)
+ Set DBname=$LISTTOSTRING(listDB,",") //In general I would expect one DB but there could be more
+ Set pre="title=""We suggest mapping the ^DeepSee.JoinIndex global together with the DeepSee cache to an unjournaled database"">"
+ Set alert = "Alert: The ^DeepSee.JoinIndex global stored in the "_DBname_" database is journaled"
+ Set alerts($I(alerts)) = pre_alert
+ Do WriteLog("
",8)
+ }
+ } Catch (ex) {
+ Set tSC = ex.AsStatus()
+ Do WriteLog("
",8)
+ }
+ Quit tSC
+}
+
+alertInitialBuildCubeManager(cube,msgrepair,msgbuild,alerts) {
+ Try {
+ Set alert=""
+ Set pre="title=""Before you synchronize cubes from the Cube Manager, it is necessary to build the cubes at least once from the Cube Manager."">"
+ If ((msgrepair="Not found") && (msgbuild="Not found")) {
+ Set alert = "Alert: there is no record for the initial build of "_cube_" from Cube Manager. Check if the cube is updating"
+ Set alerts($I(alerts)) = pre_alert
+ }
+ Set tSC = 1
+ } Catch(ex) {
+ Set tSC = ex.AsStatus()
+ Set alert = tSC
+ Set alerts($I(alerts)) = alert
+ }
+ Do WriteLog("
",8)
+}
+
+alertTimeLevels(timeLevels,alerts) {
+ Try {
+ Set throwalert=0
+ Set DimNo=$O(timeLevels(""))
+ For {
+ Quit:DimNo=""
+ Set HierNo=$O(timeLevels(DimNo,""))
+ For {
+ Quit:HierNo=""
+
+ Set typeparent = ""
+ Set levelparent = ""
+
+ Set LevelNo=$O(timeLevels(DimNo,HierNo,""))
+ For {
+ Quit:LevelNo=""
+ Set levelType = $LG(timeLevels(DimNo,HierNo,LevelNo),1)
+
+ Set type = $S(levelType="%DeepSee.Time.Decade":"normal",
+ levelType="%DeepSee.Time.Year":"normal",
+ levelType="%DeepSee.Time.QuarterYear":"normal",
+ levelType="%DeepSee.Time.MonthYear":"normal",
+ levelType="%DeepSee.Time.DayMonthYear":"normal",
+ levelType="%DeepSee.Time.WeekYear":"normal",
+ levelType="%DeepSee.Time.WeekNumber":"week",
+ levelType="%DeepSee.Time.QuarterNumber":"normal",
+ levelType="%DeepSee.Time.MonthNumber":"normal",
+ levelType="%DeepSee.Time.DayNumber":"normal",
+ levelType="%DeepSee.Time.DayOfWeek":"normal",
+ levelType="%DeepSee.Time.HourNumber":"time",
+ levelType="%DeepSee.Time.MinuteNumber":"time",
+ 1:"custom")
+ Set level = $S(levelType="%DeepSee.Time.Decade":9,
+ levelType="%DeepSee.Time.Year":8,
+ levelType="%DeepSee.Time.QuarterYear":7,
+ levelType="%DeepSee.Time.MonthYear":6,
+ levelType="%DeepSee.Time.DayMonthYear":3,
+ levelType="%DeepSee.Time.WeekYear":5,
+ levelType="%DeepSee.Time.WeekNumber":4,
+ levelType="%DeepSee.Time.QuarterNumber":7,
+ levelType="%DeepSee.Time.MonthNumber":6,
+ levelType="%DeepSee.Time.DayNumber":3,
+ levelType="%DeepSee.Time.DayOfWeek":3,
+ levelType="%DeepSee.Time.HourNumber":2,
+ levelType="%DeepSee.Time.MinuteNumber":1,
+ 1:"custom")
+
+ //Start by excluding the custom time dimensions.
+ If (type="custom") || (typeparent="custom") {
+ //Custom time levels. Good to go
+ } ElseIf (typeparent = "") || (levelparent="") {
+ //Top level. Good to go
+ } ElseIf (level>levelparent) {
+ Set throwalert = 1
+ } ElseIf (type'=typeparent) {
+ //Check when mixing different types. The previous check took care of several wrong cases
+ //Hours and Minutes are incompatible with anything else
+ If (type="time") || (typeparent="time") {
+ Set throwalert = 1
+ } ElseIf (typeparent="normal") && (type="week") {
+ //WeekNumber is under a "normal" level such as Year. WeekYear is ok
+ If (level'=4) {
+ Set throwalert = 1
+ }
+ } ElseIf (typeparent="week") {
+ //This is fine because type="time" bigger level numbers were caught before. Days are fine
+ } ElseIf (typeparent="other") {
+ //I assume abstract/custom time functions are ok
+ }
+ }
+ If throwalert=1 {
+ Set tl = timeLevels(DimNo,HierNo,LevelNo)
+ Set pre="title=""Placing certain time levels such as Year of Month in the same hierarchy as a week level will lead to unexpected results"">"
+ Set alert = "The "_$LG(tl,3)_"."_$LG(tl,4)_"."_$LG(tl,5)_" level in the "_$LG(tl,2)_
+ " cube using the "_$LG(tl,1)_" time function is incompatible with other time levels in the same hierarchy"
+ Set alerts($I(alerts)) = pre_alert
+ Do WriteLog("
",0)
+ Set throwalert=0
+ //Advance to next hierarchy, right?
+ Quit
+ }
+
+ Set typeparent = type
+ Set levelparent = level
+ Set LevelNo=$O(timeLevels(DimNo,HierNo,LevelNo))
+ }
+ Set HierNo=$O(timeLevels(DimNo,HierNo))
+ }
+ Set DimNo=$O(timeLevels(DimNo))
+ }
+ Set tSC = 1
+ } Catch (ex) {
+ Set tSC = ex.AsStatus()
+ }
+ Quit tSC
+}
+
+
+/// Write, I/O, etc helper functions
+WriteLog(string,spaces)
+ //Adds a record to LogFile
+ If string?1"***".e Quit
+ Use LogFile
+ If '$D(spaces) Set spaces=0
+ Write !,?spaces,string
+ Quit
+
+WriteParagraph(name,title,flag)
+ If '$D(flag) Set flag = 1
+ Do:flag WriteLog("
",2)
+ Do WriteLog("
",2)
+ Do WriteLog("
"_title_"
",2)
+ Quit
+
+WriteHeader4(header,spaces,title)
+ Use LogFile
+ If '$D(spaces) Set spaces=0
+ If '$D(title) Set title=""
+ Do WriteLog("
"_header_"
",spaces)
+ Quit
+
+WriteUpdate(msg)
+ New (msg, PDev, LogFile, tracking)
+ Use PDev
+ Write $C(13,27)_"[0J"_msg
+ Use LogFile
+ Quit
+
+WriteTrack(phase,mgs="",details="",errors="")
+ ZN namespace
+ Set tStep = $Case(phase,"setup":1,"cubelog":2,"buildsynch":3,"cube":4,"getlogs":5,"databases":6,"tasks":7,"journal":8,"save":9,"warning":10,"complete":12,"error":13,:11)
+ Set ^IRIS.Temp.DeepSeeButtonsTrack(+$J,tStep)=$LB(phase,mgs,details,errors)
+ //If logging detail info on cubes or a warning, create a third node in the global
+ Set:phase="cube" ^IRIS.Temp.DeepSeeButtonsTrack(+$J,tStep,details)=$LB(phase,mgs,details,errors)
+ Set:phase="warning" ^IRIS.Temp.DeepSeeButtonsTrack(+$J,tStep,details)=$LB(phase,mgs,details,errors)
+
+WriteAdhocPatch
+ Try {
+ Set patchvar=$Order(^%qPatch(""))
+ While (patchvar'=""){
+ Set data=^%qPatch(patchvar)
+ Set patchvar2=$Order(^%qPatch(patchvar))
+ Do WriteLog("
Adhoc: "_$list(data)_"
",8)
+ Do WriteLog("
Description: "_$list(data,2)_"
",8)
+ Do WriteLog("
Created at: "_$list(data,5)_"
",8)
+ Do WriteLog("
Created on $zv: "_$piece($list(data,6),")",1,2)_")"_"
",8)
+ Do WriteLog("
Applied on: "_$list(data,7)_"
",8)
+ Do WriteLog("
Applied by: "_$list(data,8)_"
",8)
+ Do WriteLog("")
+ Set patchvar=$Order(^%qPatch(patchvar))
+ }
+ } Catch(ex) {
+ //Set tSC = ex.AsStatus()
+ Do WriteLog("
An error occurred
",8)
+ }
+ Quit
+
+PrintGlobal(namespace,glob,spaces){
+ ZN namespace
+ Quit:'$D(@glob)
+ Quit:glob=""
+ Set:$D(spaces) spaces = 0
+ Set queryary=$QUERY(@glob@(""))
+ Set res=@queryary
+ Set quote=""
+ Set:'(res=+res) quote=""""
+ If $ListValid(res) {
+ //This seems to provide good formatting for ^DeepSee.CalcMbrs
+ Set res = "$lb("""_$REPLACE($LISTTOSTRING(res,"@"),"""","""""")_""")"
+ Set res = $REPLACE(res,"@",""",""")
+ Set quote=""
+ }
+ Do WriteLog("
"_queryary_" = "_quote_res_quote_"
",spaces)
+ For {
+ Set queryary=$QUERY(@queryary)
+ Quit:queryary=""
+ Set res=@queryary
+ Set quote=""
+ Set:'(res=+res) quote=""""
+ Do WriteLog("
"_queryary_" = "_quote_res_quote_"
",spaces)
+ }
+}
+
+NewFile(LogFilePrefix,LogFileSuffix)
+ //Creates a new file with Date and Time added to the filename and opens it for Reading and Writing
+ //File Name can be either "Cache" or "cstat"
+ New Date,Dir,NewFile,Time
+ Set:LogFileSuffix="" LogFileSuffix="html"
+ Set Date=$TRANSLATE($ZD($H,3),"-","")
+ Set Time=$TRANSLATE($ZT($H,2),":","")
+ If (OS?1"Win".e) {
+ Set LogFileSuffix=$ZConvert(LogFileSuffix,"l")
+ } ElseIf (OS="UNIX") {
+ Set LogFileSuffix=$ZConvert(LogFileSuffix,"l")
+ } ElseIf (OS="VMS") {
+ Set LogFileSuffix=$ZConvert(LogFileSuffix,"U")
+ }
+ Set Dir=MgrDir
+ Set LogDirectory=$Get(LogDirectory,"")
+ Set:LogDirectory'="" Dir=LogDirectory
+ If (OS?1"Win".e) {
+ Set NewFile=Dir_DirDelim_LogFilePrefix_Date_"_"_Time_"."_LogFileSuffix
+ } ElseIf (OS="UNIX") {
+ Set NewFile=Dir_DirDelim_LogFilePrefix_Date_"_"_Time_"."_LogFileSuffix
+ } ElseIf (OS="VMS") {
+ Set NewFile=Dir_$ZConvert(LogFilePrefix,"U")_Date_Time_"."_LogFileSuffix_";"
+ }
+ // Open NewFile:"RWNSK\UTF8\":FileOpenTimeOut
+ // If '$Test Quit ""
+ Quit NewFile
+
+ExternalCmd(Command)
+ //Executes an external program and adds its output to LogFile
+ //Requires the full specification of the Exe file
+ New PDev,x
+ Set PDev=$Principal
+ If OS="UNIX" Do ExtCmdPipe
+ If OS?1"Win".e!(OS="VMS") Do ExtCmdFile
+ Use PDev
+ Quit
+
+ExtCmdPipe
+ //Executing an OS command through a pipe works on UNIX
+ //It should also work on 32-bit Windows (NT, 2000 and XP), but I found inconsistent behavior on these platforms
+ Open Command:"RQ":CmdOpenTimeOut
+ If '$Test Quit
+ Try {
+ //Read timeout added to prevent the case where neither
error nor $ZEOF terminate the loop
+ For Use Command Read x:CmdReadTimeOut Set ZEOF=$ZEof Use PDev Quit:'$Test!(ZEOF) If x'="" Do WriteLog($ZConvert(x,"O","HTML"))
+ Close Command
+ } Catch(ex) {
+ Set tSC = ex.AsStatus()
+ Close Command
+ }
+ Quit
+
+ExtCmdFile
+ //Only to be executed when OS is Windows or VMS, when either pipes don't work or behave inconsistently
+ New Date,File,Time
+ Set Date=$TRANSLATE($ZD($H,3),"-","")
+ Set Time=$TRANSLATE($ZT($H,2),":","")
+ If OS?1"Win".e Do
+ . Set File=MgrDir_DirDelim_Date_Time_".$$$"
+ . Set Command=$Char(34)_Command_" > "_$$LongName(File)_$Char(34) //Cache will call "Cmd /c", which requires quotes surrounding the command
+ . Quit
+ Else If OS="VMS" Set File=MgrDir_Date_Time_".$$$"
+ If OS?1"Win".e Set x=$ZF(-1,Command)
+ Else If OS="VMS" Set x=$ZF(-1,Command,File)
+ Set $ZTrap="ExitCmdNoFile"
+ Open File:"R":FileOpenTimeOut
+ If '$Test Do WriteLog("Error: could not open file "_File) Quit
+ Set $ZTrap="ExitCmdFileEOF"
+ //Read timeout added to prevent the case where neither error nor $ZEOF terminate the loop
+ For {
+ Use File
+ Read x:FileReadTimeOut
+ Set ZEOF=$ZEof
+ Use PDev
+ Quit:'$Test!(ZEOF)
+ If x'="" Do WriteLog($ZConvert(x,"O","HTML"))
+ }
+ Set $ZTrap=""
+ Set $ZError=""
+ Close File
+ If OS="VMS" Do
+ . If $Extract(File,$Length(File))'=";" Set File=File_";"
+ . Set File=File_"*"
+ . Quit
+ Set x=$ZUtil(140,5,File) //Delete temporary scratch file
+ Quit
+ExitCmdFileEOF
+ Set $ZTrap=""
+ Set $ZError=""
+ Close File
+ If OS="VMS" Do
+ . If $Extract(File,$Length(File))'=";" Set File=File_";"
+ . Set File=File_"*"
+ . Quit
+ Set x=$ZUtil(140,5,File) //Delete temporary scratch file
+ Quit
+
+ExitCmdNoFile
+ Set $ZTrap=""
+ Set $ZError=""
+ Quit
+
+CopyToLog(InputFile,Caption,SkipSize=0)
+ //Appends a file to LogFile. Used for cconsole.log
+ //InputFile can be cconsole.log, the generated cstat output file, inuse.dmp or dumpkeys.txt
+ //SkipSize - Skip the first x number of bytes in the file to reduce size. Used by cconsole.log
+ //to keep it a reasonable size
+ New %DAT,%TIM,x
+ Do INT^%D,INT^%T
+ Do WriteLog(Caption_" on "_%DAT_" at "_%TIM_":"),WriteLog("")
+ Try {
+ Open InputFile:"R":FileOpenTimeOut
+ If '$Test Do WriteLog("File "_InputFile_" does not exist") Do WriteLog("") Use PDev Quit
+ //Read timeout added to prevent the case where neither error nor $ZEOF terminate the loop
+ If SkipSize>0 Do WriteLog("File "_InputFile_" is too large, skipping first "_SkipSize_" bytes"),WriteLog("")
+ Set Size=0
+ For {
+ Use InputFile
+ Read x:FileReadTimeOut
+ Set ZEOF=$ZEof
+ Use PDev
+ Quit:'$Test!(ZEOF)
+ Set Size=Size+$l(x)
+ Continue:SkipSize>Size
+ Use LogFile
+ Write $zconvert(x,"O","HTML"),CRLF
+ Use PDev
+ }
+ } Catch(ex) {
+ Set tSC = ex.AsStatus()
+ }
+ Close InputFile
+ Quit
+