Wednesday, April 8, 2015

AX32 Tip - Redirecting infolog output to the console

For automation purposes, you may need to execute startup commands or jobs which write their output to the Infolog. By default, this information is not saved anywhere, but there is a way to access it.


Part 1 - Set up a trace listener in Ax32.exe.config

Add the following to the app config file if not already present, before the </configuration> closing tag:

  <system.diagnostics>
    <trace autoflush="true"/>
    <sources>
      <source name="Microsoft.Dynamics.Kernel.Client.DiagnosticLog-Infolog"
              switchValue="Information">
        <listeners>
          <add name="configConsoleListener"
               type="System.Diagnostics.ConsoleTraceListener"/>
        </listeners>
      </source>
    </sources>
  </system.diagnostics>

Now the Infolog will write its output to STDOUT and STDERR.

Info Class Gotcha

Adding a global handler to the info class proved to be troublesome. It worked in most situations, but code executed on the server wasn't outputting to the client IO handles. That was just one obstacle I ran into.

Part 2 - Capturing the output of Ax32.exe in the console - DOS

Here's a DOS command which will start the Ax32.exe client and pipe the STDOUT and STDERR streams to findstr, which in turn prints to the console. If called without the pipe operator, the command returns immediately and the output is lost.

"C:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin\Ax32.exe" -startupcmd=<your startup command> -aol=<your layer, ie. CUS or USR> -LazyClassLoading -LazyTableLoading -internal=NoModalBoxes 2>&1 | findstr /x .*


This is the only non-intrusive method I have discovered for receiving data from the infolog. The trace listener header text can be stripped off. This is a small price to pay for utilizing the built in functionality.

Part 3 - Capturing the output of Ax32.exe in the console - PowerShell

I have written a separate entry which explains how to capture output in Powershell 3.0.

http://daxgotchas.blogspot.com/2015/02/powershell-tip-reading-output-from-the-infolog.html


See this post: http://daxgotchas.blogspot.com/2015/02/powershell-tip-reading-output-from-the-infolog.html

STDIO Gotcha

If the STDERR or STDOUT buffers get full, the next call to infolog will block until the buffer can receive more output. For example, piping to the "more" command will cause the application to hang until the user presses spacebar after each screen of information. This can potentially slow down the process being executed if it writes a lot of output (thousands of lines) to the infolog.



Sunday, March 29, 2015

Database Sync - The transaction log for database 'MicrosoftDynamicsAX' is full due to 'ACTIVE_TRANSACTION'.

During database sync, the following statement resulted in an error.

CREATE INDEX I_587PROJID_IDX ON "DBO".PROJEMPLTRANS (PROJID,PARTITION,DATAAREAID) INCLUDE (TRANSDATE)
Synchronize database - Cannot execute a data definition language command on ().
The SQL database has issued an error. SQL error description: The transaction log for database 'MicrosoftDynamicsAX' is full due to 'ACTIVE_TRANSACTION'.

Post Mortem - What happened?

Basically, the SQL server was unable to service the request for space during the creation of the new or modified index. This failed the DB sync process. This could be due to several factors. Here are a couple of methods for managing disk space when working in an over-subscribed environment, where disk space is limited.

Modelstore space utilization

During deployments, the Modelstore database will see heavy writes. This requires 40 GB space for log file growth. This space can be reclaimed after the Modelstore import is finished. Set the database to simple recovery mode and shrink the database log file. In test environments, I do this before taking a backup so that developers will have enough disk space to restore it. This saves each developer 40 GB of space.

Transactional space utilization

The transactional database will see some heavy traffic during database sync and table operations. This will vary depending on the scope of database changes, and how long since last deployed. For deploying to test environments, I set the transactional database to simple recovery model before performing database sync. Afterward I set it back to full recovery and then take a full backup.

Take away

Don't shrink things in production. However it may be useful to manage space differently during the deployment process. This will help avoid issues such as running out of disk space during Modelstore import or database sync, and it will save disk space downstream for environments used in development. Multiply this by the number of branches being tested in parallel and the number of test environments, and it may add up to significant savings.

Also, monitor the space used when staging a deployment during the database sync step. Always stage deployments against recent production data -- this will give a much better idea of the space and time required. Every deployment is different depending on the changes made and how large the affected tables are.

Friday, March 13, 2015

Generating cross reference data during the build process

This post applies to AX2012 R2. Cross reference data can be generated as part of the Full AOT compile process or via batch process. However the Full AOT compile with cross reference takes much longer than a normal R2 compile (which is already much slower than R3 axbuild), so I prefer to do this step after the nightly integration build has completed.

Method 1 - Full AOT compile

Set options as below, or use the following SQL to accomplish the same. Next perform a Full AOT compile, and the cross reference data will be updated.


Here's the SQL for setting the option above
Only bit 5 of column DebugInfo needs to be set for cross reference to work. The other bits are assigned to other settings:

use MicrosoftDynamicsAX

-- Substitute the ID of your build service account here
DECLARE @UserId VARCHAR(255) = 'admin'

-- VIEW STATUS OF CROSS REFERENCE
SELECT
 Debuginfo as CurrentDebugValue,
 (Debuginfo & 65519) AS DebugValue_CrossReferenceOff,
 (Debuginfo | 16) AS DebugValue_CrossReferenceOn,
 CASE WHEN (Debuginfo & 16) > 0 THEN 1 ELSE 0 END AS CrossReferenceStatus,
 * 
FROM USERINFO 
WHERE id = @UserId

-- TURN OFF CROSS REFERENCE
UPDATE USERINFO 
 SET Debuginfo = (Debuginfo & 65519)
 WHERE id = @UserId

-- TURN ON CROSS REFERENCE
UPDATE USERINFO 
 SET Debuginfo = (Debuginfo | 16)
 WHERE id = @UserId


Method 2 - Batch cross reference update

A small but important detail to consider: there must be a batch AOS running. It will suffice for the AOS performing Full AOT compile to be added to the default batch group. Otherwise, the cross reference window will spin eternally without making any progress.

Here's code which will do that via job:
// Run cross reference from AOT job
Args xrefArgs = new Args("SysCompileAll");
xRefUpdate::startxRef(xrefArgs.pack());


Exporting and importing with BCP

Note that cross reference data does NOT travel with the Modelstore database. Instead this data lives in the transactional side. You will need to export the cross reference data if you want to be able to import it to development environments or elsewhere. Here's one way to do that with the BCP utility provided with SQL:

bcp MicrosoftDynamicsAx.dbo.XREFTABLERELATION out "$TargetFolder\$($FilePrefix)XREFTABLERELATION.DAT" 
bcp MicrosoftDynamicsAx.dbo.XREFREFERENCES out "$TargetFolder\$($FilePrefix)XREFREFERENCES.DAT"    
bcp MicrosoftDynamicsAx.dbo.XREFNAMES out "$TargetFolder\$($FilePrefix)XREFNAMES.DAT"        
bcp MicrosoftDynamicsAx.dbo.XREFPATHS out "$TargetFolder\$($FilePrefix)XREFPATHS.DAT"        

Saturday, February 28, 2015

AX32 Tip - Opening the AxCompileAll.html log file

Tip: AxCompileAll.html can be opened with MorphX.

This file contains the results of the full AOT compile if you run unattended compilations with AXBuild or MorphX client. It houses any compiler output in a format which can be reloaded in the MorphX client at a later time.


AxCompileAll.html is overwritten each time the compilation completes. Loading it back into MorphX is simple. Click Import and look in one of the paths below:

Default location for AXBuild logs:
C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\Log

Default location for MorphX Client logs:
%UserProfile%\Microsoft\Dynamics Ax\Log




Likewise, you can Export the compiler output for transferring to another workstation or reviewing later, should you need to move on with your work. Now the compile errors will be displayed in the output window, and you can jump right to them:


AOTComp Log


You can search in AOTComp.log for "* Err" and you will find any compilation issues. There should be no errors, or your Full CIL will fail, and you cannot deploy this build to a production system.


Default location for AOTComp.log:
%UserProfile%\Microsoft\Dynamics Ax\Log

Full CIL Log

Note that you should also be examining the Full CIL log regularly if you perform automated builds.

Default location for XPPIL Log:
C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\bin\XppIL\Dynamics.Ax.Application.dll.log

I have found that performing the Full CIL routinely as part of deployment is helpful. Checking the number of warnings will give you an early indication if your deployment environment has been provisioned with the correct run-time DLLs. There should never be errors.

For example, when third party models have been updated, they often require accompanying DLL files. If one of these DLL files is missing on the AOS, it will sometimes generate an XPPIL warning.

Also, specific features must be selected during the install of AX. While there may be unavoidable XPPIL warnings depending on your choice of third party vendors, the same warnings should be applicable to all environments for which the Modelstore applies, or there is certainly a noteworthy difference between the environments.


Tuesday, February 17, 2015

AX2012 TFS Tip - Setting default startup model

If you use version control then it can be helpful to set the default startup model for development workstations. At first glance, this can be easily accomplished through the AX Configuration options.

Startup Model Gotcha

If the development environment is refreshed from production, the configuration options are overwritten. Therefore the default startup model may be set incorrectly.

AX32.exe -model argument

To ensure your developers have the correct startup model after an environment refresh, simply add the following to the MorphX shortcut: 

"-model=(YourModel, YourVendor)"
Important: Include the quotation marks.



Setting the Startup Layer

The default layer can be set in the AX Configuration Utility, and will survive an environment refresh. Alternatively, supply the following argument (CUS layer shown as example): 
Ax32.exe -aol=CUS -aolcode=YOURKEY
The development code can be omitted from the parameter set if specified in the client configuration utility.




A more complete list of client configuration commands is available here:
https://technet.microsoft.com/en-us/library/aa569653.aspx


Monday, February 16, 2015

AXBuild included with AX2012 R2 CU7 - but does it work for base R2?

AXBuild.exe for Dynamics is a high performance build engine released with AX2012 R2 CU7 Kernel. There are a few ways it speeds up the build, namely through parallelism and by cutting out the overhead of MorphX. This compile tool can make full use of all available CPU cores and it benefits from enterprise class storage systems.

By contrast, builds performed in the MorphX client would benefit most from systems optimized for single threaded operations, ie. no virtualization, solid state disks and high clock speed.

It is theoretically possible to use AXBuild.exe without first upgrading to CU7. I tried it. Even though it works, I can find no documentation stating that it is acceptable to use AXBuild on installations prior to CU7. Therefore, if you do not have CU7, your results may be unsupported if you use the following method.

There are a couple of mentions where AXBuild was used successfully without taking on CU7, after updating the Kernel only:

AXBuild Gotchas:

  • AXBuild takes the place of the AOS service. Therefore, the AOS service should be turned off for the duration of the compile, and MorphX should be closed.
  • Using the altbin parameter will correctly locate the client\bin binaries and avoid runtime errors.
  • If your server\bin folder has not been well maintained, you may uncover third party components which are out of date, previously unmentioned by MorphX. These should be corrected anyway.
  • Hot-swapping must be turned off in the AOS configuration.
  • The compile log files are not stored in the user profile by default. Instead, they are are stored in: C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\Log\
  • AXBuild should be executed with administrative credentials.
  • .NET Objects Cannot be Instantiated while the compile is running. This matters if you have customized a few key foundation classes to perform .NET calls, namely Application, Infolog, and ClassFactory. See section F: https://msdn.microsoft.com/en-us/library/dn528954.aspx
  • AXBuild does not support chained COM calls. See below.
  • The documentation for AXBuild alludes to differences in the Modelstore schema. In my experience, the compile completed successfully on AX2012 R2 without updating the schema, so I am not sure that this applies. For CU7 where the tool was introduced, it certainly applies. In that case, care must be taken to also update the schema on deployment environments, or the new Modelstore will fail to import.
  • Full CIL generation remains as a separate step which is not covered by AXBuild.

 

Fix for AX2012 R2 base install - errors in foundation class SysInetHTMLEditor


For the AX2012 R2 base install, I encountered two errors:
Description    Path    Line    Method/Property name    Diagnostic ID   
1. The variable is not of the type CLASS.    \Forms\SysInetHTMLEditor\Methods\saveChanges    21    \Forms    Err:74   
2. The variable is not of the type CLASS.    \Forms\SysInetHTMLEditor\Methods\saveDocument    25    \Forms    Err:74   

For an explanation, see Section F, constraints:
https://msdn.microsoft.com/en-us/library/dn528954.aspx


Here are the errors after loading AxCompileAll.html into MorphX:


This was easily solvable by first declaring a variable of type COM to avoid the chaining call: