<commit_before>import { Injectable, Injector } from '@angular/core';
import { Response } from '@angular/http';
import { AIMonthlySummary, AIInvocationTrace, AIInvocationTraceHistory, AIQueryResult } from '../models/application-insights';
import { Observable } from 'rxjs/Observable';
import { ConditionalHttpClient } from '../conditional-http-client';
import { UserService } from './user.service';
import { HttpResult } from './../models/http-result';
import { CacheService } from './cache.service';
import { LogService } from './log.service';
import { LogCategories, Constants } from '../models/constants';
import { ArmSiteDescriptor } from '../resourceDescriptors';
import * as pako from 'pako';
import { LocalStorageService } from './local-storage.service';
import { MonitorViewItem } from '../models/localStorage/local-storage';
import * as moment from 'moment-mini-ts';

@Injectable()
export class ApplicationInsightsService {
  private readonly _client: ConditionalHttpClient;

  private readonly _apiVersion = '2015-05-01';
  private readonly _directUrl = 'https://analytics.applicationinsights.io/';

  constructor(
    private _logService: LogService,
    private _cacheService: CacheService,
    private _localStorage: LocalStorageService,
    userService: UserService,
    injector: Injector
  ) {
    this._client = new ConditionalHttpClient(injector, _ => userService.getStartupInfo().map(i => i.token));
  }

  public getLast30DaysSummary(aiResourceId: string, functionAppName: string, functionName: string): Observable<AIMonthlySummary> {
    this._validateAiResourceid(aiResourceId);

    const body = {
      query: this._getQueryForLast30DaysSummary(functionAppName, functionName),
    };

    const armResponse = this._cacheService.postArm(
      `/${aiResourceId}/api/query`,
      true,
      this._apiVersion,
      body,
      'applicationInsights_30DaysSummary'
    );

    return this._client.execute({ resourceId: aiResourceId }, t => armResponse).map(response => this._extractSummaryFromResponse(response));
  }

  public getInvocationTraces(
    aiResourceId: string,
    functionAppName: string,
    functionName: string,
    top: number = 20
  ): Observable<AIInvocationTrace[]> {
    this._validateAiResourceid(aiResourceId);

    const body = {
      query: this._getQueryForInvocationTraces(functionAppName, functionName, top),
    };

    const armResponse = this._cacheService.postArm(
      `/${aiResourceId}/api/query`,
      true,
      this._apiVersion,
      body,
      'applicationInsights_invocationTraces'
    );

    return this._client
      .execute({ resourceId: aiResourceId }, t => armResponse)
      .map(response => this._extractInvocationTracesFromResponse(response));
  }

  public getInvocationTraceHistory(
    aiResourceId: string,
    operationId: string,
    invocationId: string
  ): Observable<AIInvocationTraceHistory[]> {
    this._validateAiResourceid(aiResourceId);

    const body = {
      query: this._getQueryForInvocationTraceHistory(operationId, invocationId),
    };

    const armResponse = this._cacheService.postArm(
      `/${aiResourceId}/api/query`,
      true,
      this._apiVersion,
      body,
      'applicationInsights_invocationTraceHistory'
    );

    return this._client
      .execute({ resourceId: aiResourceId }, t => armResponse)
      .map(response => this._extractInvocationTraceHistoryFromResponse(response));
  }

  public getInvocationTracesDirectUrl(aiDirectResourceId: string, functionAppName: string, functionName: string, top: number = 20): string {
    const baseUrl = this._directUrl + aiDirectResourceId + '?q=';
    const query = ApplicationInsightsQueryUtil.compressAndEncodeBase64AndUri(
      this._getQueryForInvocationTraces(functionAppName, functionName, top)
    );
    return baseUrl + query;
  }

  public getInvocationTraceHistoryDirectUrl(aiDirectResourceId: string, operationId: string, invocationId: string): string {
    const baseUrl = this._directUrl + aiDirectResourceId + '?q=';
    const query = ApplicationInsightsQueryUtil.compressAndEncodeBase64AndUri(
      this._getQueryForInvocationTraceHistory(operationId, invocationId)
    );
    return baseUrl + query;
  }

  public getApplicationInsightsId(siteId: string): Observable<string> {
    const descriptor = new ArmSiteDescriptor(siteId);
    return Observable.zip(
      this._cacheService.postArm(`${siteId}/config/appsettings/list`),
      this._cacheService.getArm(`/subscriptions/${descriptor.subscription}/providers/microsoft.insights/components`, false, '2015-05-01'),
      (as, ai) => ({ appSettings: as, appInsights: ai })
    ).map(r => {
      const ikey = r.appSettings.json().properties[Constants.instrumentationKeySettingName];
      let result = null;
      if (ikey) {
        const aiResources = r.appInsights.json();

        // AI RP has an issue where they return an array instead of a JSON response if empty
        if (aiResources && !Array.isArray(aiResources)) {
          aiResources.value.forEach(ai => {
            if (ai.properties.InstrumentationKey === ikey) {
              result = ai.id;
            }
          });
        }
      }
      return result;
    });
  }

  public setFunctionMonitorClassicViewPreference(functionAppResourceId: string, value: string) {
    const key = `${functionAppResourceId}/monitor/view`;
    const item: MonitorViewItem = {
      id: functionAppResourceId,
      value: value,
    };

    this._localStorage.setItem(key, item);
  }

  public getFunctionMonitorClassicViewPreference(functionAppResourceId: string): string {
    const key = `${functionAppResourceId}/monitor/view`;
    const item = <MonitorViewItem>this._localStorage.getItem(key);

    return item && item.value ? item.value : null;
  }

  public removeFunctionMonitorClassicViewPreference(functionAppResourceId: string): void {
    const key = `${functionAppResourceId}/monitor/view`;

    this._localStorage.removeItem(key);
  }

  private _getQueryForLast30DaysSummary(functionAppName: string, functionName: string): string {
    this._validateFunctionAppName(functionAppName);
    this._validateFunctionName(functionName);
    return (
      `requests ` +
      `| where timestamp >= ago(30d) ` +
      `| where cloud_RoleName =~ '${functionAppName}' and operation_Name == '${functionName}' ` +
      `| summarize count=count() by success`
    );
  }

  private _getQueryForInvocationTraces(functionAppName: string, functionName: string, top: number): string {
    this._validateFunctionAppName(functionAppName);
    this._validateFunctionName(functionName);
    return (
      `requests ` +
      `| project timestamp, id, operation_Name, success, resultCode, duration, operation_Id, cloud_RoleName, invocationId=customDimensions['InvocationId'] ` +
      `| where timestamp > ago(30d) ` +
      `| where cloud_RoleName =~ '${functionAppName}' and operation_Name == '${functionName}' ` +
      `| order by timestamp desc | take ${top}`
    );
  }

  private _getQueryForInvocationTraceHistory(operationId: string, invocationId: string): string {
    this._validateOperationId(operationId);

    return (
      `union traces` +
      `| union exceptions` +
      `| where timestamp > ago(30d)` +
      `| where operation_Id == '${operationId}'` +
      `| where customDimensions['InvocationId'] == '${invocationId}'` +
      `| order by timestamp asc` +
      `| project timestamp, message = iff(message != '', message, iff(innermostMessage != '', innermostMessage, customDimensions.["prop__{OriginalFormat}"])), logLevel = customDimensions.["LogLevel"]`
    );
  }

  private _validateAiResourceid(aiResourceId: string): void {
    if (!aiResourceId) {
      throw Error('aiResourceId is required.');
    }
  }

  private _validateFunctionAppName(functionAppName: string): void {
    if (!functionAppName) {
      throw Error('functionAppName is required.');
    }
  }
<commit_msg>fix the invocation id bug (#3962)<commit_after>import { Injectable, Injector } from '@angular/core';
import { Response } from '@angular/http';
import { AIMonthlySummary, AIInvocationTrace, AIInvocationTraceHistory, AIQueryResult } from '../models/application-insights';
import { Observable } from 'rxjs/Observable';
import { ConditionalHttpClient } from '../conditional-http-client';
import { UserService } from './user.service';
import { HttpResult } from './../models/http-result';
import { CacheService } from './cache.service';
import { LogService } from './log.service';
import { LogCategories, Constants } from '../models/constants';
import { ArmSiteDescriptor } from '../resourceDescriptors';
import * as pako from 'pako';
import { LocalStorageService } from './local-storage.service';
import { MonitorViewItem } from '../models/localStorage/local-storage';
import * as moment from 'moment-mini-ts';

@Injectable()
export class ApplicationInsightsService {
  private readonly _client: ConditionalHttpClient;

  private readonly _apiVersion = '2015-05-01';
  private readonly _directUrl = 'https://analytics.applicationinsights.io/';

  constructor(
    private _logService: LogService,
    private _cacheService: CacheService,
    private _localStorage: LocalStorageService,
    userService: UserService,
    injector: Injector
  ) {
    this._client = new ConditionalHttpClient(injector, _ => userService.getStartupInfo().map(i => i.token));
  }

  public getLast30DaysSummary(aiResourceId: string, functionAppName: string, functionName: string): Observable<AIMonthlySummary> {
    this._validateAiResourceid(aiResourceId);

    const body = {
      query: this._getQueryForLast30DaysSummary(functionAppName, functionName),
    };

    const armResponse = this._cacheService.postArm(
      `/${aiResourceId}/api/query`,
      true,
      this._apiVersion,
      body,
      'applicationInsights_30DaysSummary'
    );

    return this._client.execute({ resourceId: aiResourceId }, t => armResponse).map(response => this._extractSummaryFromResponse(response));
  }

  public getInvocationTraces(
    aiResourceId: string,
    functionAppName: string,
    functionName: string,
    top: number = 20
  ): Observable<AIInvocationTrace[]> {
    this._validateAiResourceid(aiResourceId);

    const body = {
      query: this._getQueryForInvocationTraces(functionAppName, functionName, top),
    };

    const armResponse = this._cacheService.postArm(
      `/${aiResourceId}/api/query`,
      true,
      this._apiVersion,
      body,
      'applicationInsights_invocationTraces'
    );

    return this._client
      .execute({ resourceId: aiResourceId }, t => armResponse)
      .map(response => this._extractInvocationTracesFromResponse(response));
  }

  public getInvocationTraceHistory(
    aiResourceId: string,
    operationId: string,
    invocationId: string
  ): Observable<AIInvocationTraceHistory[]> {
    this._validateAiResourceid(aiResourceId);

    const body = {
      query: this._getQueryForInvocationTraceHistory(operationId, invocationId),
    };

    const armResponse = this._cacheService.postArm(
      `/${aiResourceId}/api/query`,
      true,
      this._apiVersion,
      body,
      'applicationInsights_invocationTraceHistory'
    );

    return this._client
      .execute({ resourceId: aiResourceId }, t => armResponse)
      .map(response => this._extractInvocationTraceHistoryFromResponse(response));
  }

  public getInvocationTracesDirectUrl(aiDirectResourceId: string, functionAppName: string, functionName: string, top: number = 20): string {
    const baseUrl = this._directUrl + aiDirectResourceId + '?q=';
    const query = ApplicationInsightsQueryUtil.compressAndEncodeBase64AndUri(
      this._getQueryForInvocationTraces(functionAppName, functionName, top)
    );
    return baseUrl + query;
  }

  public getInvocationTraceHistoryDirectUrl(aiDirectResourceId: string, operationId: string, invocationId: string): string {
    const baseUrl = this._directUrl + aiDirectResourceId + '?q=';
    const query = ApplicationInsightsQueryUtil.compressAndEncodeBase64AndUri(
      this._getQueryForInvocationTraceHistory(operationId, invocationId)
    );
    return baseUrl + query;
  }

  public getApplicationInsightsId(siteId: string): Observable<string> {
    const descriptor = new ArmSiteDescriptor(siteId);
    return Observable.zip(
      this._cacheService.postArm(`${siteId}/config/appsettings/list`),
      this._cacheService.getArm(`/subscriptions/${descriptor.subscription}/providers/microsoft.insights/components`, false, '2015-05-01'),
      (as, ai) => ({ appSettings: as, appInsights: ai })
    ).map(r => {
      const ikey = r.appSettings.json().properties[Constants.instrumentationKeySettingName];
      let result = null;
      if (ikey) {
        const aiResources = r.appInsights.json();

        // AI RP has an issue where they return an array instead of a JSON response if empty
        if (aiResources && !Array.isArray(aiResources)) {
          aiResources.value.forEach(ai => {
            if (ai.properties.InstrumentationKey === ikey) {
              result = ai.id;
            }
          });
        }
      }
      return result;
    });
  }

  public setFunctionMonitorClassicViewPreference(functionAppResourceId: string, value: string) {
    const key = `${functionAppResourceId}/monitor/view`;
    const item: MonitorViewItem = {
      id: functionAppResourceId,
      value: value,
    };

    this._localStorage.setItem(key, item);
  }

  public getFunctionMonitorClassicViewPreference(functionAppResourceId: string): string {
    const key = `${functionAppResourceId}/monitor/view`;
    const item = <MonitorViewItem>this._localStorage.getItem(key);

    return item && item.value ? item.value : null;
  }

  public removeFunctionMonitorClassicViewPreference(functionAppResourceId: string): void {
    const key = `${functionAppResourceId}/monitor/view`;

    this._localStorage.removeItem(key);
  }

  private _getQueryForLast30DaysSummary(functionAppName: string, functionName: string): string {
    this._validateFunctionAppName(functionAppName);
    this._validateFunctionName(functionName);
    return (
      `requests ` +
      `| where timestamp >= ago(30d) ` +
      `| where cloud_RoleName =~ '${functionAppName}' and operation_Name == '${functionName}' ` +
      `| summarize count=count() by success`
    );
  }

  private _getQueryForInvocationTraces(functionAppName: string, functionName: string, top: number): string {
    this._validateFunctionAppName(functionAppName);
    this._validateFunctionName(functionName);
    return (
      `requests ` +
      `| project timestamp, id, operation_Name, success, resultCode, duration, operation_Id, cloud_RoleName, invocationId=customDimensions['InvocationId'] ` +
      `| where timestamp > ago(30d) ` +
      `| where cloud_RoleName =~ '${functionAppName}' and operation_Name == '${functionName}' ` +
      `| order by timestamp desc | take ${top}`
    );
  }

  private _getQueryForInvocationTraceHistory(operationId: string, invocationId: string): string {
    this._validateOperationId(operationId);

    const invocationIdFilter = !!invocationId ? `| where customDimensions['InvocationId'] == '${invocationId}'` : '';

    return (
      `union traces` +
      `| union exceptions` +
      `| where timestamp > ago(30d)` +
      `| where operation_Id == '${operationId}'` +
      invocationIdFilter +
      `| order by timestamp asc` +
      `| project timestamp, message = iff(message != '', message, iff(innermostMessage != '', innermostMessage, customDimensions.["prop__{OriginalFormat}"])), logLevel = customDimensions.["LogLevel"]`
    );
  }

  private _validateAiResourceid(aiResourceId: string): void {
    if (!aiResourceId) {
      throw Error('aiResourceId is required.');
    }
  }

  private _validateFunctionAppName(functionAppName: string): void {
    if (!functionAppName) {
      throw Error('functionAppName is required.');
    }
  }

{'fraction_non_alphanumeric': 0.11594111726220432, 'fraction_numerical': 0.0050327126321087065, 'mean_word_length': 3.9787034137175072, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 41, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1371247', 'n_tokens_mistral': 4565, 'n_tokens_neox': 4445, 'n_words': 929}