Negative Lookahead with Regular expression in Kusto Log Analytics

%3CLINGO-SUB%20id%3D%22lingo-sub-1183988%22%20slang%3D%22en-US%22%3ENegative%20Lookahead%20with%20Regular%20expression%20in%20Kusto%20Log%20Analytics%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1183988%22%20slang%3D%22en-US%22%3E%3CP%3EHello%20everyone%2C%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EI'm%20trying%20to%20extract%20exceptions%20within%20our%20logs%20using%20regular%20expression.%20And%20it%20happens%20that%20I%20need%20to%20perform%20a%20negative%20lookahead%20to%20ignore%20a%20specific%20string.%20The%20query%20looks%20like%20below%3A%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CDIV%3E%3CDIV%3E%3CDIV%3E%26nbsp%3B%3C%2FDIV%3E%3C%2FDIV%3E%3C%2FDIV%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-javascript%22%3E%3CCODE%3Elet%20pattern%20%3D%20%40'(%3F!Exception%3A%20System.Web.HttpUnhandledException)Exception%3A%20(.%2B)%5Cs%2BMessage%3A%20(%5B%5CS%5Cs%5D%2B)%5Cs%2BSource%3A%20(%5B%5CS%5Cs%5D%2B)'%3B%0Alet%20standardize%20%3D%20(msg%3Astring)%20%7B%0A%20%20%20%20let%20msg2%20%3D%20replace(%40'%22(%5CS%2B)%22'%2C%20'%22xxx%22'%2C%20msg)%3B%0A%20%20%20%20replace(%40%22'(%5CS%2B)'%22%2C%20'%22xxx%22'%2C%20msg2)%0A%7D%3B%0AWebsiteLogs%0A%7C%20where%20ExceptionMessage%20contains%20%22System.Web.HttpUnhandledException%22%20or%20ExceptionMessage%20contains%20%22%5BExtra%20Exception%20from%20config%5D%22%0A%7C%20where%20%20TimeGenerated%20%26gt%3B%20ago(7d)%20%0A%7C%20project%20%20%20URL%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20Exception%3Dextract(pattern%2C%201%2C%20ExceptionMessage%20)%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20Message%20%3D%20standardize(extract(pattern%2C%202%2C%20ExceptionMessage%20))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20StackTrace%20%3D%20substring(extract(pattern%2C%203%2C%20ExceptionMessage%20)%2C%200%2C%20500)%0A%7C%20summarize%20Errors_Count%20%3D%20count()%20by%20Message%2C%20URL%2C%20StackTrace%0A%7C%20sort%20by%20Errors_Count%20desc%20%20nulls%20last%20%0A%7C%20limit%201000%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CDIV%3E%26nbsp%3B%3C%2FDIV%3E%3CDIV%3EA%20sample%20of%20exception%20below%20is%20like%20below%3A%3C%2FDIV%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-markup%22%3E%3CCODE%3EException%3A%20System.Web.HttpUnhandledException%0AMessage%3A%20An%20unhandled%20exception%20occurred.%0ASource%3A%20Sitecore.Mvc%0Aat%20Sitecore.Mvc.Pipelines.MvcEvents.Exception.ShowAspNetErrorMessage.ShowErrorMessage(ExceptionContext%20exceptionContext%2C%20ExceptionArgs%20args)%0Aat%20Sitecore.Mvc.Pipelines.MvcEvents.Exception.ShowAspNetErrorMessage.Process(ExceptionArgs%20args)%0Aat%20(Object%20%2C%20Object%5B%5D%20)%0Aat%20Sitecore.Pipelines.CorePipeline.Run(PipelineArgs%20args)%0Aat%20Sitecore.Pipelines.DefaultCorePipelineManager.Run(String%20pipelineName%2C%20PipelineArgs%20args%2C%20String%20pipelineDomain)%0Aat%20Sitecore.Mvc.Pipelines.PipelineService.RunPipeline%5BTArgs%5D(String%20pipelineName%2C%20TArgs%20args)%0Aat%20Sitecore.Mvc.Filters.PipelineBasedRequestFilter.OnException(ExceptionContext%20exceptionContext)%0Aat%20System.Web.Mvc.ControllerActionInvoker.InvokeExceptionFilters(ControllerContext%20controllerContext%2C%20IList%601%20filters%2C%20Exception%20exception)%0Aat%20System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext%20controllerContext%2C%20String%20actionName)%0Aat%20System.Web.Mvc.Controller.ExecuteCore()%0Aat%20System.Web.Mvc.ControllerBase.Execute(RequestContext%20requestContext)%0Aat%20Sitecore.Mvc.Controllers.ControllerRunner.ExecuteController(Controller%20controller)%0Aat%20Sitecore.Mvc.Controllers.ControllerRunner.Execute()%0Aat%20Sitecore.Mvc.Presentation.ControllerRenderer.Render(TextWriter%20writer)%0Aat%20Sitecore.Mvc.Pipelines.Response.RenderRendering.ExecuteRenderer.Render(Renderer%20renderer%2C%20TextWriter%20writer%2C%20RenderRenderingArgs%20args)%0A%0ANested%20Exception%0A%0AException%3A%20System.ArgumentNullException%0AMessage%3A%20Value%20cannot%20be%20null.%0AParameter%20name%3A%20item%0ASource%3A%20Website.Module.Product%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CDIV%3E%3CSPAN%3E%3CSPAN%3E%3CSPAN%3EAs%20you%20can%20see%2C%20I%20want%20to%20ignore%20the%26nbsp%3B%3C%2FSPAN%3E%3C%2FSPAN%3E%3C%2FSPAN%3ES%3CEM%3Eystem.Web.HttpUnhandledException%3C%2FEM%3E%20as%20it%20Is%20not%20very%20informative%20for%20my%20case.%20The%20information%20that%20I%20want%20to%20extract%20is%20found%20below%20the%20%3CEM%3ENested%20Exception%3C%2FEM%3E.%20As%20such%2C%20I'm%20using%20regex%20negative%20lookahead%20for%20this%2C%20and%20it%20match%20very%20well%20when%20tested%20on%20a%20regex%20tester.%20But%20the%20thing%20is%20it%20seems%20that%20Log%20Analytics%20doesn't%20support%20this%20feature.%20Is%20it%20the%20case%20or%20I%20missed%20something%20in%20the%20Kusto%20syntax%20for%20regular%20expressions%3F%3C%2FDIV%3E%3CDIV%3E%26nbsp%3B%3C%2FDIV%3E%3CDIV%3EThank%20you%20in%20advance%20for%20your%20precious%20help%26nbsp%3B%3CIMG%20class%3D%22lia-deferred-image%20lia-image-emoji%22%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Fhtml%2Fimages%2Femoticons%2Fsmile_40x40.gif%22%20alt%3D%22%3Asmile%3A%22%20title%3D%22%3Asmile%3A%22%20%2F%3E%3C%2FDIV%3E%3C%2FLINGO-BODY%3E%3CLINGO-LABS%20id%3D%22lingo-labs-1183988%22%20slang%3D%22en-US%22%3E%3CLINGO-LABEL%3EAzure%20Log%20Analytics%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EQuery%20Language%3C%2FLINGO-LABEL%3E%3C%2FLINGO-LABS%3E%3CLINGO-SUB%20id%3D%22lingo-sub-1184321%22%20slang%3D%22en-US%22%3ERe%3A%20Negative%20Lookahead%20with%20Regular%20expression%20in%20Kusto%20Log%20Analytics%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1184321%22%20slang%3D%22en-US%22%3E%3CP%3EWell%2C%20I%20managed%20to%20get%20over%20it%20without%20using%20regex%20negative%20lookhead%20by%20using%20another%20custom%20function%20to%20skip%20the%20non-relevant%20information.%20My%20solution%20looks%20like%20below%20in%20case%20someone%20else%20is%20facing%20similar%20case%20%3CIMG%20class%3D%22lia-deferred-image%20lia-image-emoji%22%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Fhtml%2Fimages%2Femoticons%2Fsmile_40x40.gif%22%20alt%3D%22%3Asmile%3A%22%20title%3D%22%3Asmile%3A%22%20%2F%3E%3C%2FP%3E%3CPRE%20class%3D%22lia-code-sample%20language-javascript%22%3E%3CCODE%3Elet%20pattern%20%3D%20%40'Exception%3A%20(.%2B)%5Cs%2BMessage%3A%20(%5B%5CS%5Cs%5D%2B)%5Cs%2BSource%3A%20(%5B%5CS%5Cs%5D%2B)'%3B%0Alet%20standardize%20%3D%20(msg%3Astring)%20%7B%0A%20%20%20%20let%20msg2%20%3D%20replace(%40'%22(%5CS%2B)%22'%2C%20'%22xxx%22'%2C%20msg)%3B%0A%20%20%20%20replace(%40%22'(%5CS%2B)'%22%2C%20'%22xxx%22'%2C%20msg2)%0A%7D%3B%0Alet%20getException%20%3D%20(msg%3A%20string)%20%7B%0A%20%20%20%20case(msg%20contains%20%22System.Web.HttpUnhandledException%22%2C%20substring(msg%2C%20indexof(msg%2C%20%22Nested%20Exception%22)%20%2B%2017)%2C%20msg)%0A%7D%3B%0AWebsiteLogs%0A%7C%20where%20ExceptionMessage%20contains%20%22System.Web.HttpUnhandledException%22%20or%20ExceptionMessage%20contains%20%22%5BExtra%20Exception%20from%20config%5D%22%0A%7C%20where%20%20TimeGenerated%20%26gt%3B%20ago(7d)%20%0A%7C%20project%20%20%20URL%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20Exception%3Dextract(pattern%2C%201%2C%20ExceptionMessage%20)%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20Message%20%3D%20standardize(extract(pattern%2C%202%2C%20getException(ExceptionMessage)%20))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20StackTrace%20%3D%20substring(extract(pattern%2C%203%2C%20getException(ExceptionMessage%20))%2C%200%2C%20500)%0A%7C%20summarize%20Errors_Count%20%3D%20count()%20by%20Message%2C%20URL%2C%20StackTrace%0A%7C%20sort%20by%20Errors_Count%20desc%20%20nulls%20last%20%0A%7C%20limit%201000%3C%2FCODE%3E%3C%2FPRE%3E%3CP%3EHere%2C%20the%20getException()%20function%20just%20skip%20the%20%3CEM%3EExceptionMessage%3C%2FEM%3E%20till%20the%20first%20%3CEM%3ENested%20Exception%20%3C%2FEM%3Efor%20logs%20containing%20the%20S%3CEM%3Eystem.Web.HttpUnhandledException.%3C%2FEM%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3ENevertheless%2C%20I'm%20still%20wondering%20if%20regex%20lookahead%20is%20supported%20or%20not%20%3CIMG%20class%3D%22lia-deferred-image%20lia-image-emoji%22%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Fhtml%2Fimages%2Femoticons%2Fsmile_40x40.gif%22%20alt%3D%22%3Asmile%3A%22%20title%3D%22%3Asmile%3A%22%20%2F%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-1190922%22%20slang%3D%22en-US%22%3ERE%3A%20Negative%20Lookahead%20with%20Regular%20expression%20in%20Kusto%20Log%20Analytics%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1190922%22%20slang%3D%22en-US%22%3EThanks%20for%20sharing%20Sami.%20Meanwhile%20I%20checked%20with%20the%20Kusto%20group%20and%20that's%20indeed%20not%20supported.%3C%2FLINGO-BODY%3E
Highlighted
New Contributor

Hello everyone,

 

I'm trying to extract exceptions within our logs using regular expression. And it happens that I need to perform a negative lookahead to ignore a specific string. The query looks like below:

 

 

 

 

let pattern = @'(?!Exception: System.Web.HttpUnhandledException)Exception: (.+)\s+Message: ([\S\s]+)\s+Source: ([\S\s]+)';
let standardize = (msg:string) {
    let msg2 = replace(@'"(\S+)"', '"xxx"', msg);
    replace(@"'(\S+)'", '"xxx"', msg2)
};
WebsiteLogs
| where ExceptionMessage contains "System.Web.HttpUnhandledException" or ExceptionMessage contains "[Extra Exception from config]"
| where  TimeGenerated > ago(7d) 
| project   URL,
            Exception=extract(pattern, 1, ExceptionMessage ), 
            Message = standardize(extract(pattern, 2, ExceptionMessage )),
            StackTrace = substring(extract(pattern, 3, ExceptionMessage ), 0, 500)
| summarize Errors_Count = count() by Message, URL, StackTrace
| sort by Errors_Count desc  nulls last 
| limit 1000

 

 

 
A sample of exception below is like below:

 

 

Exception: System.Web.HttpUnhandledException
Message: An unhandled exception occurred.
Source: Sitecore.Mvc
at Sitecore.Mvc.Pipelines.MvcEvents.Exception.ShowAspNetErrorMessage.ShowErrorMessage(ExceptionContext exceptionContext, ExceptionArgs args)
at Sitecore.Mvc.Pipelines.MvcEvents.Exception.ShowAspNetErrorMessage.Process(ExceptionArgs args)
at (Object , Object[] )
at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
at Sitecore.Pipelines.DefaultCorePipelineManager.Run(String pipelineName, PipelineArgs args, String pipelineDomain)
at Sitecore.Mvc.Pipelines.PipelineService.RunPipeline[TArgs](String pipelineName, TArgs args)
at Sitecore.Mvc.Filters.PipelineBasedRequestFilter.OnException(ExceptionContext exceptionContext)
at System.Web.Mvc.ControllerActionInvoker.InvokeExceptionFilters(ControllerContext controllerContext, IList`1 filters, Exception exception)
at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
at System.Web.Mvc.Controller.ExecuteCore()
at System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext)
at Sitecore.Mvc.Controllers.ControllerRunner.ExecuteController(Controller controller)
at Sitecore.Mvc.Controllers.ControllerRunner.Execute()
at Sitecore.Mvc.Presentation.ControllerRenderer.Render(TextWriter writer)
at Sitecore.Mvc.Pipelines.Response.RenderRendering.ExecuteRenderer.Render(Renderer renderer, TextWriter writer, RenderRenderingArgs args)

Nested Exception

Exception: System.ArgumentNullException
Message: Value cannot be null.
Parameter name: item
Source: Website.Module.Product

 

 

As you can see, I want to ignore the System.Web.HttpUnhandledException as it Is not very informative for my case. The information that I want to extract is found below the Nested Exception. As such, I'm using regex negative lookahead for this, and it match very well when tested on a regex tester. But the thing is it seems that Log Analytics doesn't support this feature. Is it the case or I missed something in the Kusto syntax for regular expressions?
 
Thank you in advance for your precious help :smile:
3 Replies
Highlighted

Well, I managed to get over it without using regex negative lookhead by using another custom function to skip the non-relevant information. My solution looks like below in case someone else is facing similar case :smile:

let pattern = @'Exception: (.+)\s+Message: ([\S\s]+)\s+Source: ([\S\s]+)';
let standardize = (msg:string) {
    let msg2 = replace(@'"(\S+)"', '"xxx"', msg);
    replace(@"'(\S+)'", '"xxx"', msg2)
};
let getException = (msg: string) {
    case(msg contains "System.Web.HttpUnhandledException", substring(msg, indexof(msg, "Nested Exception") + 17), msg)
};
WebsiteLogs
| where ExceptionMessage contains "System.Web.HttpUnhandledException" or ExceptionMessage contains "[Extra Exception from config]"
| where  TimeGenerated > ago(7d) 
| project   URL,
            Exception=extract(pattern, 1, ExceptionMessage ), 
            Message = standardize(extract(pattern, 2, getException(ExceptionMessage) )),
            StackTrace = substring(extract(pattern, 3, getException(ExceptionMessage )), 0, 500)
| summarize Errors_Count = count() by Message, URL, StackTrace
| sort by Errors_Count desc  nulls last 
| limit 1000

Here, the getException() function just skip the ExceptionMessage till the first Nested Exception for logs containing the System.Web.HttpUnhandledException.

 

Nevertheless, I'm still wondering if regex lookahead is supported or not :smile:

 

 

Highlighted
Thanks for sharing Sami. Meanwhile I checked with the Kusto group and that's indeed not supported.
Highlighted

Apparently the full explanation is here. Quoting from it:

 

"Kusto uses the re2 library: https://github.com/google/re2/wiki/Syntax, as mentioned here: https://docs.microsoft.com/en-us/azure/kusto/query/re2

What you're trying to achieve isn't supported by that library - see https://github.com/google/re2/wiki/WhyRE2:

'As a matter of principle, RE2 does not support constructs for which only backtracking solutions are known to exist. Thus, backreferences and look-around assertions are not supported.'"