Showing posts with label logs. Show all posts
Showing posts with label logs. Show all posts

Monday, May 9, 2022

Latest Azure PaaS Sitecore Logs using a single line of PowerShell

If you’re anything like me, you probably don’t have a passion for manually digging through the series of hundreds of randomly dated folders that look like this in search of the latest Sitecore logs:


Hello darkness, my old friend

Although several tools and approaches are available (including this nifty tool credited to fellow Sitecore MVP Kiran Patil - as well as some of my own previous posts from 2018 and 2019 covering this topic), I've recently adopted a different strategy that's proved to be successful across several Sitecore PaaS clients for quickly obtaining the latest physical Sitecore log for a given server. 

The post-worthy kicker?  It's one line of PowerShell:

$kuduHost = "https://yourazuresitename-xp2-cd.scm.azurewebsites.net"; Write-Output "`n[ LATEST SITECORE LOGS ]`n"; $array = @(); Get-ChildItem "C:\home\site\wwwroot\app_data\logs" -File -Recurse | Where-Object { $_.FullName -match "azure.*.txt" -and $_.LastWriteTime -gt (Get-Date).AddHours(-12) } | ForEach-Object { $path = $_.FullName.replace("C:\home\site\wwwroot\app_data\logs\", "$kuduHost/api/vfs/site/wwwroot/App_Data/logs/"); $array += "`n[$($_.LastWriteTime)]`n$path`n"}; $array | Sort-Object $_.LastWriteTime | Select-Object -Last 3

😬

Okay, it's...kind of a long one-liner...but one line nevertheless 

The above example outputs direct links to the latest three physical Sitecore log files, which match the pattern 'azure.*.

In practice, the desired file can be highlighted from the console and at which point you can copy the URL or open it in a new tab.



Let's break it down

The first line defines a variable for the KUDU host you're using:

$kuduHost = "https://yourazuresitename-xp2-cd.scm.azurewebsites.net"

The second line outputs a (wholly arbitrary and unnecessary) title:

Write-Output "`n`[ LATEST SITECORE LOGS ]`n"

The third line represents an array variable aptly named `$array` (because I'm clever):

$array = @();

This is where it gets exciting. This Get-ChildItem cmdlet gets all files recursively under the site's `\App_Data\logs` location:

Get-ChildItem "C:\home\site\wwwroot\app_data\logs" -File -Recurse
Neat!

We can pipe in a Where-Object cmdlet to filter only file names that match 'azure.*.txt' (or if you want all log types - Publishing, Crawling, Dianoga, SPE, etc. - *.txt) and provide a 12-hour threshold against the `LastWriteTime` property:

Get-ChildItem "C:\home\site\wwwroot\app_data\logs" -File -Recurse |
Where-Object {$_.FullName -match "azure.*.txt" -and $_.LastWriteTime -gt (Get-Date).AddHours(-12)}

We can then pipe in a ForEach-Object cmdlet to iterate through each file:

Get-ChildItem "C:\home\site\wwwroot\app_data\logs" -File -Recurse | Where-Object { $_.FullName -match "azure.*.txt" -and $_.LastWriteTime -gt (Get-Date).AddHours(-12) } | ForEach-Object { $path = $_.FullName.replace("C:\home\site\wwwroot\app_data\logs\", "$kuduHost/api/vfs/site/wwwroot/App_Data/logs/"); $array += "[$($_.LastWriteTime)]`n$path`n"}

Notice that in the ForEach-Object cmdlet, we create a variable called `$path` and set it to a string that takes the file's FullName and replaces the 'system path' portion, and replace it with our `$kuduHost` variable concatenated to `/api/vfs/site/wwwroot/App_Data/logs/`.

$path = $_.FullName.replace("C:\home\site\wwwroot\app_data\logs\", "$kuduHost/api/vfs/site/wwwroot/App_Data/logs/")

Without this string replacement, we'd only get the system path for the files in the dataset, which would still require navigating to the file manually:

Also, within the ForEach-Object cmdlet, a formatted string containing the LastWriteTime and the `$path` variable is added to the `$array` variable:

$array += "[$($_.LastWriteTime)]`n$path`n"

The `n used above allows for line breaks.

After the files have been processed, the `$array` variable is called and sorted by LastWriteTime.

A Select-Object cmdlet is piped in to limit the number of results to 3:

$array | Sort-Object $_.LastWriteTime | Select-Object -Last 3


By combining these together, eliminating spaces, and adding semi-colons to separate commands, we've got our one-liner! 🕺

Bonus: IIS HTTP Request Logs

Using the same approach with a few modifications, the application's raw IIS HTTP Request Logs can also be obtained (differences bolded below):

$kuduHost = "https://yourazuresitename-xp2-cm.scm.azurewebsites.net"; Write-Output "`n[ LATEST IIS LOGS ]`n"; $array = @(); Get-ChildItem "C:\home\LogFiles\http\RawLogs" -Recurse | Where-Object { $_.FullName -match ".log" -and $_.LastWriteTime -gt (Get-Date).AddHours(-12) } | Sort-Object $_.LastWriteTime | ForEach-Object { $path = $_.FullName.replace("C:\home\LogFiles\http\RawLogs\", "$kuduHost/api/vfs/LogFiles/http/RawLogs/"); $array += "[$($_.LastWriteTime)]`n$path`n"}; $array | Sort-Object $_.LastWriteTime | Select-Object -Last 3


Final Thoughts

You can generate variations of this one-liner by changing the various variables, which can be shared with the rest of your development/troubleshooting team and readily ready to copy from an internal Wiki:

Feel free to use and modify the script as you see fit. 🚀

Friday, April 1, 2022

'Tracker.Current.Session.Interaction should not be null' CountryCondition

Uh oh. 

The following errors are heavily present on my client's content delivery servers:

ERROR Evaluation of condition failed. Rule item ID:
Unknown, condition item ID: {9A4BEB4B-4B0F-4392-A798-124CEC8AADA4}

Exception: Sitecore.Framework.Conditions.PostconditionException

Message: Postcondition 'Tracker.Current.Session.Interaction should not be null' failed.

Source: Sitecore.Framework.Conditions
at Sitecore.Framework.Conditions.EnsuresValidator`1.ThrowExceptionCore(String condition, String additionalMessage, ConstraintViolationType type)
at Sitecore.Framework.Conditions.Throw.ValueShouldNotBeNull[T](ConditionValidator`1 validator, String conditionDescription)
at Sitecore.Framework.Conditions.ValidatorExtensions.IsNotNull[T](ConditionValidator`1 validator)
at Sitecore.ContentTesting.Rules.Conditions.CountryCondition`1.Execute(T ruleContext)
at Sitecore.Rules.Conditions.WhenCondition`1.Evaluate(T ruleContext, RuleStack stack)
at Sitecore.Rules.Conditions.OrCondition`1.Evaluate(T ruleContext, RuleStack stack)
at Sitecore.Rules.Conditions.WhenRule`1.Execute(T ruleContext)
at Sitecore.Rules.Conditions.WhenCondition`1.Evaluate(T ruleContext, RuleStack stack)
at Sitecore.Rules.RuleList`1.Run(T ruleContext, Boolean stopOnFirstMatching, Int32& executedRulesCount)

We're talking thousands upon thousands of these errors. 

The error references a GUID we can use to determine the context of this:
{9A4BEB4B-4B0F-4392-A798-124CEC8AADA4}
Moreover, the error's message hints are what ultimately causes the error to trigger: 
Tracker.Current.Session.Interaction should not be null
For context, the GUID refers to the following out-of-the-box Sitecore item:
/sitecore/system/Settings/Rules/Definitions/Elements/Predefined Rules/Predefined Rule
Nothing to see here...


After digging in, I found that the client had configured personalization on a Controller Rendering for their site's homepage component rendering so that depending on the user’s country, unique content is presented. They've implemented the following Predefined rules on the rendering:

- visitor is located in the Asia Pacific region
- visitor is located in the UK
    - or where visitor is equal to the United Kingdom
- where visitor is located in Continental Europe

These are custom rules they've added that categorize a list of countries into a region they want to target.

For example, the `visitor is located in the Asia Pacific region` looks like this:
where the country is equal to Australia
or where the country is equal to Brunei Darussalam
or where the country is equal to China
or where the country is equal to Hong Kong
or where the country is equal to Singapore
or where the country is equal to Taiwan
or where the country is equal to Thailand
or where the country is equal to New Zealand
or where the country is equal to Qatar
or where the country is equal to Turkey
or where the country is equal to Malaysia
or where the country is equal to Russian Federation
or where the country is equal to India
or where the country is equal to Indonesia
or where the country is equal to United Arab Emirates
or where the country is equal to Philippines
or where the country is equal to Israel
or where the country is equal to Pakistan
or where the country is equal to Saudi Arabia
or where the country is equal to Vietnam
or where the country is equal to Japan

Each country has been defined using the out-of-the-box `GeoIP` > `where the country compares to specific countries` condition template.

This line in the error denotes that the `CountryCondition` is the culprit in regards to the recurring error:
at Sitecore.ContentTesting.Rules.Conditions.CountryCondition`1.Execute(T ruleContext)
According to a reflection of the `Sitecore.ContentTesting.Rules.Conditions` namespace in Sitecore.ContentTesting.dll for v10.0.0, this series of checks in the first few lines of the `CountryCondition<T> : VisitCondition<T> where T : RuleContext` class's Execute() method:

[GIST_START]
[GIST_END]

My hunch was that the last check was causing the failure, and instead of failing silently, it throws an error - specifically often in cases where bot-like traffic is involved. 
Condition.Ensures<CurrentInteraction>(Tracker.Current.Session.Interaction, "Tracker.Current.Session.Interaction").IsNotNull<CurrentInteraction>();

To quell the flood of errors initially, I applied a new stand-alone rule preceding each existing visitor is rule located in {REGION_NAME} region called `visitor is human` (also out-of-the-box) to attempt to deflect bots and spam where a country code or identifiable contact/interaction is unlikely to yield a country (which would result in an error):

After applying these changes and publishing them, we see those errors disappear entirely from the error logs.  However, the introduction of the `visitor is human` rule proceeding the rest had an unintended effect: first-time visitors always failed this first condition, causing them to only see the personalized rendering after reloading the page. Removing the rule enabled users to receive the personalized rendering on the first load but reintroduced the flood of errors.

It seemed that instances where `Tracker.Current.Session.Interaction` is null may be caused by bot traffic according to: https://support.sitecore.com/kb?id=kb_article_view&sysparm_article=KB0960279

Given that this is version 10.0.0, this particular bug should have been resolved in all versions above 8.1.

Upon decompiling and comparing the GetTracker : CreateTrackerProcessor > Process() override in Sitecore.Support.424667.81.dll for v8.1+ to the 10.0.0 Sitecore.Analytics.dll's GetTracker : CreateTrackerProcessor > Process method, there's one notable difference:

v8.1+


v10.0.0

It was unclear if we need a similar patch to implement `args.set_Tracker(new DefaultTracker());` in the Process() method.

I raised the question with Sitecore Support to explore one of two resolutions:

1) A patch for suppressing errors in Sitecore.ContentTesting.Rules.Conditions.CountryCondition's Execute() method, when the `Condition.Ensures<CurrentInteraction>(Tracker.Current.Session.Interaction, "Tracker.Current.Session.Interaction").IsNotNull<CurrentInteraction>();` is not satisfied (perhaps by returning false).

or

2) An override patch for the tracker creation similar to the https://support.sitecore.com/kb?id=kb_article_view&sysparm_article=KB0960279 hotfix.

Sitecore Support was able to reproduce the reported behavior in a clean local instance of Sitecore 10.0.0 (Initial Release) without involving any of our specific customizations. They registered the issue as a bug in their bug tracking system (future reference number 456739).

Sitecore's official statement regarding the bug: 
The reported behavior occurs because Sitecore.Rules.Conditions.WhenRule class inherits CanEvaluate() method from Sitecore.Rules.Conditions.RuleCondition class which always returns true. That is why the rule is not skipped so the evaluation continues and leads to the exception. 
In order to workaround the issue, please try to avoid the usage of Conditional renderings rules.
Please assign conditions to your renderings directly without wrapping them into conditional renderings rule.
 
In this case, Sitecore will trigger CanEvaluate method related to the specific condition, so the condition will be skipped.

I ended up pursuing the following approach myself:

  1. Decompiled the `Sitecore.ContentTesting.dll` and copied the Sitecore.ContentTesting.Rules.Conditions.CountryCondition class into our solution called `CountryConditionOverride`.  I used Telerik JustDecompile for this. 

  2. Commented the offending line (48) and replaced it with a simple null check that returns false.

  3. Enabled the custom override class by updating the `Type` field on the following default Sitecore item and published it:
/sitecore/system/Settings/Rules/Definitions/Elements/GeoIP/Country
{52E42C59-7210-43E5-94A6-3EA6B98835B8}
Field: Script (section) > Type 
Old value:  `Sitecore.ContentTesting.Rules.Conditions.CountryCondition,Sitecore.ContentTesting`
New value: `Foundation.Overrides.Rules.Conditions.CountryConditionOverride, Foundation.Overrides`

The final override class:


This resolves the issue with erroneous error log entries while retaining the expected Country condition functionality when the `Tracker.Current.Session.Interaction` happens to not be null.

I've shared my resolution with Sitecore Support and will keep an eye on an official hotfix (reference 456739), which I will share once it's available. 

Hopefully, in the meantime, this helps someone out there in a similar scenario!

Thursday, September 23, 2021

Sitecore Cache Tuning: LAYOUT_DELTA_CACHE

While tuning caches for a production level Sitecore 10.0.0 site, I came across a cache name I was unfamiliar with using a cache tunerLAYOUT_DELTA_CACHE


There were also log entries specific to this cache:

4484 12:07:57 INFO Cache created: 'LAYOUT_DELTA_CACHE' (max size: 50MB, running total: 6580MB)

Oddly enough, at the time of this post, no Google Search results mentioned this cache name.


Sitecore's documentation also had no mention of the setting either. 

Reaching out to Sitecore Support helped clarify things, and I wanted to share in case anyone else happens to come across this same cache that needs tuning. 

"The cache seems to be utilized when applying layout deltas when Sitecore is retrieving the layout field. The default size of this cache is 50MB, however, you can modify it with the "Caching.LayoutFieldDeltaCacheSize" setting."

Check out the following example configuration:


Hopefully, this helps with your Sitecore cache tuning activities. Happy tuning! 😊

Thursday, September 5, 2019

Azure Application Insights: Logs & Requests Viewer using Sitecore PowerShell Extensions

Last September, I wrote about accessing Sitecore Logs from Azure PaaS instances using the (now deprecated) AzureAILogs.html file provided by Sitecore. The knowledgebase article was updated in mid-January , 2019 – and the AzureAILogs.html file had been replaced with a new /sitecore/admin page dubbed AzureTools.aspx.

This updated admin page contains all the same functionality found in the AzureAILogs.html, with the addition of being able to pull log traces and requests from Application Insights.



Installation is easy: download the AzureTools.zip files, drop in the /sitecore/admin/AzureAILogs.aspx into the you’re your site’s root.

Admittedly, this admin page is great - but I could also see several aspects SPE being particularly useful (like the OOB SPE ListView - which would easily allow us to filter/sort/search through a series of log entries). An additional option to see raw color-coded logs would also be cool. 😊

Using the existing AzureTools.aspx as a general guide, we can re-create the GUI with general ease.

We’ll need:
1) Option to get Requests or Logs
2) Option to selected a Role (values pulled from API)
3) Option to control recency.
4) Option to control the severity.


The end result will consume the Application Insights REST API endpoints and allow a user to pull logs from Application Insights inside the CMS.


API Access

To start, we'll need to make sure we can work with the API by obtaining an Application Insights App ID and a corresponding App Insights API key  Sitecore's documentation already lists the.

Sitecore's documentation covers this but it's as simple as logging into Azure Portal and navigating to your Application Insights service. 

Under Configure, select 'API Access':


The Application Insights App ID will be displayed the following screen:

Copy this value and store it temporarily.

Click the 'Create API Key' button.
Give it a name and check the 'Read telemetry' checkbox.

After clicking 'Generate key', you'll have one opportunity to copy the 'App Insights API key'.  Copy and store this value temporarily.


Initial Communication with the API

Our script will utilize the two values to interact with the API.

Before building our UI in SPE, we'll need to confirm API communication by obtaining the server roles from Application Insights.  We can set a variable to call a function that will grab an ArrayList of roles:

Our function will build the URL, include the property URL authorization header containing the API key, and return an array list.



User Interface

Now that we have confirmed communication to the API and obtained our list of roles, we can pass the variable into a new function that will be responsible for building and displaying the UI:

The dialog should contain a series of radio buttons and checkbox lists, all of which will be used to provide options to build out another API call to obtain the traces or requests from AppInsights.

The output displays as follows:

Notice line 51 in the above snippet calls a Get-LogsOrRequests function which accepts a series of parameters from the dialog options upon selecting the OK button.

This function builds out the proper API URL and query parameters based on the passed the selected values passed in. Invoke-WebRequest is used to make the call to the API, which will return a JSON object of log entries from AppInsights based on those parameters.

Line 119 contains a final call to a function called 'Set-PostDialog' which provides options for displaying the results.

The output here is a ModalDialog with three buttons:


Selecting 'Script View' will display the results of the API in a color-coded Show-Result window:


Selecting 'List View' will process the results to an acceptable format for a standard SPE ListView result window (filtering, exporting, etc is obviously all included here):


Finally, selecting the 'Download' button will download a .txt file of the contents retrieved from the API.


Final Script





Installation

Manual

  1. Create a new Sitecore item based on the SPE PowerShell Script template and copy the final script above into the Script Body field.
  2. Replace the default "XXXXXXXXXXXXXXXXXXXXXXXXX" placeholder values in the $aiAppID and $apiKey variables with your own.  

Sitecore Package

  1. Download the Sitecore package and install from GitHub.
  2. Navigate to the PowerShell script located here:
    /sitecore/system/Modules/PowerShell/Script Library/Azure Application Insights Logs/Toolbox/Azure Application Insights Logs
  3. Replace the default "XXXXXXXXXXXXXXXXXXXXXXXXX" placeholder values in the $aiAppID and $apiKey variables with your own.  
The script will be available to run from the PowerShell Toolbox in the Start Menu.


Source Code

The full script can also be found on GitHub.
Feel free to grab a copy and modify it how you see fit.  



Monday, April 29, 2019

Sitecore Azure Kudu Tools PowerShell Module



I've managed to start several blog post drafts with the intention of sharing a few of my PowerShell scripts - but haven't got around to finishing/posting any of them.

This actually led to an epiphany: the scripts I wanted to share all had an underlying theme: obtaining files using the Kudu Rest API using PowerShell.


Huh? Kudu?

Aw, a baby Kudu!

If you don't already know, Kudu is the "engine behind git deployments" in Azure App Service - but can also be used as a built-in diagnostics tool within Azure.   Any time you have an Azure website, you automatically get a 'companion' Kudu (aka SCM) site accessible via the following URL format:  https://{ResourceName}.scm.azurewebsites.net.  

For example, if your CM App Service name is
'mysitecoresite-xp2-small-prd1-cm',

the corresponding Kudu site would be:
https://mysitecoresite-xp2-small-prd1-cm.scm.azurewebsites.net/ 

If you've ever had to Rebuild the xDB index in Azure Search, Sitecore's documentation walks you through how to do so using the Kudu Debug console.

Kudu REST API

One of my favorite feature of Kudu is the Kudu REST API since any files you can access via FTP are also accessible via the Kudu REST API.   You can download files, upload new ones, etc.

Typically, all you need are:
  1. Subscription ID
  2. Resource Group Name
  3. Resource Name
In Azure Portal - you can copy these values from a resource in the overview panel:


Those values are the key to interact with the API using PowerShell's Invoke-RestMethod.
There are a couple prerequisites:
  1. Azure RM module installed and ConnectAccount has been executed.
  2. Valid Azure credentials (same ones used to log into Azure Portal) to invoke Login-AzureRmAccount (converted to Base64)



Sitecore Azure Kudu Tools

I'd never written a PowerShell Module, but I figured this would be a great segway to learning how. I got to reading -- and tinkering -- and refactoring.  

Before long I had written my first PowerShell Module: Sitecore Azure Kudu Tools.

Sitecore Azure Kudu Tools is a collection of functions (three at the time of this post) built to help you get information/files from Sitecore instances on hosted on Azure PaaS using the Kudu Rest API.

It's available on the PowerShell Gallery or check out the GitHub repository.


Get-SitecoreSupportPackage

Allows you to remotely generate a Sitecore Support Package.  The function will download files defined for Sitecore Support Packages into a specified path, obfuscate sensitive data from ConnectionStrings.config, and compress the contents:

\App_Config\* Global.asax
\Logs\* license.xml
eventlog.xml sitecore.version.xml
Web.config


Why?

While there's a built-in way to obtain Sitecore Support Packages in Sitecore's admin page, being able to remotely obtain this information is a nice alternative.  This is useful not only for providing the required information for Sitecore Support tickets - but also for your own diagnostics.

Usage

Invoke this function using the following syntax:


Output


Alternatively, if you just run Get-SitecoreSupportPackage without any parameters, you'll be prompted to provide each required parameter.



Invoke-SitecoreThumbprintValidation

Provides a way to verify that certificate thumbprints match across Sitecore Azure PaaS Resource Group.  The function will download ConnectionStrings.config and AppSettings.config files from all App Services in a given Resource Group, then display any certificate thumbprints discrepancies.

Why?

If you've ever had to replace thumbprint values across an Azure PaaS Sitecore topology, you know that it can be a bit of a pain identifying all the configs where the old thumbprint needs to be replaced.

Bram Stoop wrote a great post identifying all the places you'll need to modify those thumbprints.  If you're looking to semi-automate this process, you can utilize the Kudu REST API to get all the configurations, then identify any mismatched thumbprint values using PowerShell.

Usage

Invoke this function using the following syntax:


Output




Get-SitecoreFileBackup

Allows you to a full copy of an App Service's website file contents.  This function will download all files from in a given ResourceName.

The following folders are excluded:
_DEV sitecore modules
App_Data sitecore_files
App_Browsers temp
sitecore upload
xsl

Why?

Sometimes I just want everything. If I need to determine discrepancies between environments for any reason, this helps.

Usage

Invoke this function using the following syntax:

Output




What's Next?

Now that the module is established, I've created a few GitHub Issues which I hope to get through quickly.  I also plan to add more functions in the future and am 100% open to contributions. 

Is it perfect? Far from it! It's a work in progress. Thrilled to share anyway.

If you're interested in contributing, please check out the contribute section on the Github repo.

via GIPHY

😊


Thursday, September 6, 2018

Azure PaaS Sitecore Logs using AzureAILogs.html

When hosting Sitecore XP solutions on Azure PaaS – you’ll quickly find out that accessing and viewing Sitecore logs is different than you may be used to.

Sitecore has a great Knowledgebase article available (Access logs and diagnostics data in Sitecore XP on Azure Web Apps) which describes a couple approaches for obtaining the Sitecore logs on a PaaS environment using both Azure Application Insights or FTP.

Grabbing recent log files is pretty straightforward once you’ve configured FTP credentials to access your Sitecore instance.  Simply FTP into the instance (Filezilla is my favorite), navigate to /LogFiles/Application, sort by date, and download the relevant logs.



My preferred approach, however, is utilizing the AzureAILogs.html file that Sitecore provides within the “Using Azure Application Insights REST API” section of the KB article:


Enabling the API Key also requires a few clicks in the Azure portal, but the instructions for enabling this feature are outlined well – and it only takes a couple of minutes to complete.

If you download and open the HTML file locally, the output is pretty sweet:


Once you input the Sitecore app's App Insights App ID and API key, clicking the 'Update Roles' button retrieves the relevant roles for the application (CM, CD, Reporting, and Processing).

Having obtained the roles, you can select one or multiple roles, configure any specific options (recency // checkbox to only show errors // number of entries), and click the 'Get logs from AI' button to make the call.

You’ll end up with filtered and descending log entries you’d typically get from Sitecore logs:

The bonus here is the 'Download logs' button will download the log files – which are also compatible with Sitecore Log Analyzer.

This is super handy as-is, but I also wanted to make it a little easier to access online.  Specifically:

  1. I don’t want to input in the App ID and API key every time I want to use this tool.
  2. I want to access this from our CM environment, similar to any other admin page.
By adding a few old-fashioned lines of Javascript to my copy of the AzureAILogs.html file (just before the requestHandler function), the page was able to accept two URL query parameters (‘appid’ and ‘apikey’) to prefill the two input values.


For example:
AzureAILogs.html?appid=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&apikey=0000000000000000000000000000000000000000

In order to access this from our CM Authoring environment, I simply added the HTML page to the /sitecore/admin directory.

Once I was able to hit the page from the server, I tacked on our App ID and API Key to the URL and bookmarked the page.   Voila - simple yet effective.

Of course, this is just one of many ways to view Sitecore logs on a PaaS environment - but I found it to be one of the most useful.

Thursday, February 22, 2018

Real-time, Filterable Trailing/Rolling Sitecore Logs with PowerShell

Sitecore troubleshooting usually goes something like this:

1) Do something on the site
2) Navigate to the /logs directory
3) Sort the files by date
4) Open the latest log file
5) Scroll to the bottom to find the most recent entries
6) Repeat as needed

Sometimes seeing what's being written to the logs in real-time makes a lot more sense during development and troubleshooting sessions.

While there are plenty of note editors out there that support log tailing (Notepad++, SnakeTail, or even just the Command Prompt) there are always caveats (lack of filtering, finding the latest log file) - I wanted a simpler experience, with slightly more advanced options that can be used across any of my local Sitecore instances - without it being too complicated to use.  More specifically, you may not always need all the INFO or WARN messages during a real-time monitoring session.

And since I've become a PowerShell addict throughout the last couple of years...

I ended up with a couple of pretty handy PowerShell script I've been using in my day-to-day development that'd I'd love to share with you.

Actually, there are two scripts!

RollingSitecoreLogs.ps1

The first script can be placed anywhere on your machine.  When you run it, you'll be prompted with a Directory Selection dialog.  Simply navigate to the /logs folder for any Sitecore instance.


Once you've selected the directory, the script prompts you with a second dialog form which allows you to filter in/out INFO, WARN, ERROR entries.


Hit OK, and the log starts rolling in!


RollingSitecoreLogs-RelativeDirectory.ps1

The second script is far less involved and runs from your /logs directory (just drop it right in).


It determines the current directory (based on where the script itself is located), finds the latest log.* file, gives you the option to choose which messages should filter in, and begins a rolling session.

The idea is - since you're probably navigating to your logs directory to pick up on the latest log anyway - once you have this script added to our /logs directory you can simply run the script and have it start a real-time log monitoring session.  Simple as that.

Please note - this only considers the primary log.* files - so it's not built for Crawling.log, Search.log, etc. Perhaps additional options can be added at some point in the future to chose or maybe even merge them somehow.

Feel free to grab whichever script suites your needs here:
https://github.com/strezag/sitecore-rolling-logs-powershell

As always, let me know what you think in the comments.

Happy log-sifting