diff --git a/appinsights/client.go b/appinsights/client.go index 64b443b..77f9b69 100644 --- a/appinsights/client.go +++ b/appinsights/client.go @@ -73,14 +73,9 @@ func NewTelemetryClient(iKey string) TelemetryClient { // Creates a new telemetry client instance configured by the specified // TelemetryConfiguration object. func NewTelemetryClientFromConfig(config *TelemetryConfiguration) TelemetryClient { - channel := NewInMemoryChannel(config) - context := NewTelemetryContext() - - config.setupContext(context) - return &telemetryClient{ - channel: channel, - context: context, + channel: NewInMemoryChannel(config), + context: config.setupContext(), isEnabled: true, } } diff --git a/appinsights/client_test.go b/appinsights/client_test.go index b1e3357..05e064f 100644 --- a/appinsights/client_test.go +++ b/appinsights/client_test.go @@ -110,18 +110,18 @@ func TestEndToEnd(t *testing.T) { } j[0].assertPath(t, "iKey", test_ikey) - j[0].assertPath(t, "name", "Microsoft.ApplicationInsights.Event") + j[0].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Event") j[0].assertPath(t, "time", "2017-11-18T10:35:21Z") j[1].assertPath(t, "iKey", test_ikey) - j[1].assertPath(t, "name", "Microsoft.ApplicationInsights.Metric") + j[1].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Metric") j[1].assertPath(t, "time", "2017-11-18T10:35:21Z") j[2].assertPath(t, "iKey", test_ikey) - j[2].assertPath(t, "name", "Microsoft.ApplicationInsights.Message") + j[2].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Message") j[2].assertPath(t, "time", "2017-11-18T10:35:21Z") j[3].assertPath(t, "iKey", test_ikey) - j[3].assertPath(t, "name", "Microsoft.ApplicationInsights.Request") + j[3].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Request") j[3].assertPath(t, "time", "2017-11-18T10:34:21Z") } diff --git a/appinsights/configuration.go b/appinsights/configuration.go index ec14ee5..f7fa76b 100644 --- a/appinsights/configuration.go +++ b/appinsights/configuration.go @@ -34,8 +34,8 @@ func NewTelemetryConfiguration(instrumentationKey string) *TelemetryConfiguratio } } -func (config *TelemetryConfiguration) setupContext(context *TelemetryContext) { - context.iKey = config.InstrumentationKey +func (config *TelemetryConfiguration) setupContext() *TelemetryContext { + context := NewTelemetryContext(config.InstrumentationKey) context.Tags.Internal().SetSdkVersion(sdkName + ":" + Version) context.Tags.Device().SetOsVersion(runtime.GOOS) @@ -43,4 +43,6 @@ func (config *TelemetryConfiguration) setupContext(context *TelemetryContext) { context.Tags.Device().SetId(hostname) context.Tags.Cloud().SetRoleInstance(hostname) } + + return context } diff --git a/appinsights/contracts/availabilitydata.go b/appinsights/contracts/availabilitydata.go index abf7311..4f0d709 100644 --- a/appinsights/contracts/availabilitydata.go +++ b/appinsights/contracts/availabilitydata.go @@ -37,8 +37,12 @@ type AvailabilityData struct { } // Returns the name used when this is embedded within an Envelope container. -func (data *AvailabilityData) EnvelopeName() string { - return "Microsoft.ApplicationInsights.Availability" +func (data *AvailabilityData) EnvelopeName(key string) string { + if key != "" { + return "Microsoft.ApplicationInsights." + key + ".Availability" + } else { + return "Microsoft.ApplicationInsights.Availability" + } } // Returns the base type when placed within a Data object container. diff --git a/appinsights/contracts/eventdata.go b/appinsights/contracts/eventdata.go index 43db95e..2093c74 100644 --- a/appinsights/contracts/eventdata.go +++ b/appinsights/contracts/eventdata.go @@ -23,8 +23,12 @@ type EventData struct { } // Returns the name used when this is embedded within an Envelope container. -func (data *EventData) EnvelopeName() string { - return "Microsoft.ApplicationInsights.Event" +func (data *EventData) EnvelopeName(key string) string { + if key != "" { + return "Microsoft.ApplicationInsights." + key + ".Event" + } else { + return "Microsoft.ApplicationInsights.Event" + } } // Returns the base type when placed within a Data object container. diff --git a/appinsights/contracts/exceptiondata.go b/appinsights/contracts/exceptiondata.go index 8abae58..fe1c2f2 100644 --- a/appinsights/contracts/exceptiondata.go +++ b/appinsights/contracts/exceptiondata.go @@ -30,8 +30,12 @@ type ExceptionData struct { } // Returns the name used when this is embedded within an Envelope container. -func (data *ExceptionData) EnvelopeName() string { - return "Microsoft.ApplicationInsights.Exception" +func (data *ExceptionData) EnvelopeName(key string) string { + if key != "" { + return "Microsoft.ApplicationInsights." + key + ".Exception" + } else { + return "Microsoft.ApplicationInsights.Exception" + } } // Returns the base type when placed within a Data object container. diff --git a/appinsights/contracts/messagedata.go b/appinsights/contracts/messagedata.go index 1544d04..c067643 100644 --- a/appinsights/contracts/messagedata.go +++ b/appinsights/contracts/messagedata.go @@ -23,8 +23,12 @@ type MessageData struct { } // Returns the name used when this is embedded within an Envelope container. -func (data *MessageData) EnvelopeName() string { - return "Microsoft.ApplicationInsights.Message" +func (data *MessageData) EnvelopeName(key string) string { + if key != "" { + return "Microsoft.ApplicationInsights." + key + ".Message" + } else { + return "Microsoft.ApplicationInsights.Message" + } } // Returns the base type when placed within a Data object container. diff --git a/appinsights/contracts/metricdata.go b/appinsights/contracts/metricdata.go index 11b587e..106576f 100644 --- a/appinsights/contracts/metricdata.go +++ b/appinsights/contracts/metricdata.go @@ -20,8 +20,12 @@ type MetricData struct { } // Returns the name used when this is embedded within an Envelope container. -func (data *MetricData) EnvelopeName() string { - return "Microsoft.ApplicationInsights.Metric" +func (data *MetricData) EnvelopeName(key string) string { + if key != "" { + return "Microsoft.ApplicationInsights." + key + ".Metric" + } else { + return "Microsoft.ApplicationInsights.Metric" + } } // Returns the base type when placed within a Data object container. diff --git a/appinsights/contracts/pageviewdata.go b/appinsights/contracts/pageviewdata.go index 33f786a..15e1d0a 100644 --- a/appinsights/contracts/pageviewdata.go +++ b/appinsights/contracts/pageviewdata.go @@ -19,8 +19,12 @@ type PageViewData struct { } // Returns the name used when this is embedded within an Envelope container. -func (data *PageViewData) EnvelopeName() string { - return "Microsoft.ApplicationInsights.PageView" +func (data *PageViewData) EnvelopeName(key string) string { + if key != "" { + return "Microsoft.ApplicationInsights." + key + ".PageView" + } else { + return "Microsoft.ApplicationInsights.PageView" + } } // Returns the base type when placed within a Data object container. diff --git a/appinsights/contracts/remotedependencydata.go b/appinsights/contracts/remotedependencydata.go index 2ae52f7..f078243 100644 --- a/appinsights/contracts/remotedependencydata.go +++ b/appinsights/contracts/remotedependencydata.go @@ -49,8 +49,12 @@ type RemoteDependencyData struct { } // Returns the name used when this is embedded within an Envelope container. -func (data *RemoteDependencyData) EnvelopeName() string { - return "Microsoft.ApplicationInsights.RemoteDependency" +func (data *RemoteDependencyData) EnvelopeName(key string) string { + if key != "" { + return "Microsoft.ApplicationInsights." + key + ".RemoteDependency" + } else { + return "Microsoft.ApplicationInsights.RemoteDependency" + } } // Returns the base type when placed within a Data object container. diff --git a/appinsights/contracts/requestdata.go b/appinsights/contracts/requestdata.go index 097a82a..7db3b0a 100644 --- a/appinsights/contracts/requestdata.go +++ b/appinsights/contracts/requestdata.go @@ -46,8 +46,12 @@ type RequestData struct { } // Returns the name used when this is embedded within an Envelope container. -func (data *RequestData) EnvelopeName() string { - return "Microsoft.ApplicationInsights.Request" +func (data *RequestData) EnvelopeName(key string) string { + if key != "" { + return "Microsoft.ApplicationInsights." + key + ".Request" + } else { + return "Microsoft.ApplicationInsights.Request" + } } // Returns the base type when placed within a Data object container. diff --git a/appinsights/jsonserializer_test.go b/appinsights/jsonserializer_test.go index 66ecc1a..015b61d 100644 --- a/appinsights/jsonserializer_test.go +++ b/appinsights/jsonserializer_test.go @@ -63,7 +63,7 @@ func TestJsonSerializerEvents(t *testing.T) { // Trace j[0].assertPath(t, "iKey", test_ikey) - j[0].assertPath(t, "name", "Microsoft.ApplicationInsights.Message") + j[0].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Message") j[0].assertPath(t, "time", "2017-11-18T10:35:21Z") j[0].assertPath(t, "sampleRate", 100.0) j[0].assertPath(t, "data.baseType", "MessageData") @@ -73,7 +73,7 @@ func TestJsonSerializerEvents(t *testing.T) { // Event j[1].assertPath(t, "iKey", test_ikey) - j[1].assertPath(t, "name", "Microsoft.ApplicationInsights.Event") + j[1].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Event") j[1].assertPath(t, "time", "2017-11-18T10:35:21Z") j[1].assertPath(t, "sampleRate", 100.0) j[1].assertPath(t, "data.baseType", "EventData") @@ -82,7 +82,7 @@ func TestJsonSerializerEvents(t *testing.T) { // Metric j[2].assertPath(t, "iKey", test_ikey) - j[2].assertPath(t, "name", "Microsoft.ApplicationInsights.Metric") + j[2].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Metric") j[2].assertPath(t, "time", "2017-11-18T10:35:21Z") j[2].assertPath(t, "sampleRate", 100.0) j[2].assertPath(t, "data.baseType", "MetricData") @@ -95,7 +95,7 @@ func TestJsonSerializerEvents(t *testing.T) { // Request j[3].assertPath(t, "iKey", test_ikey) - j[3].assertPath(t, "name", "Microsoft.ApplicationInsights.Request") + j[3].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Request") j[3].assertPath(t, "time", "2017-11-18T10:34:21Z") // Constructor subtracts duration j[3].assertPath(t, "sampleRate", 100.0) j[3].assertPath(t, "data.baseType", "RequestData") @@ -109,7 +109,7 @@ func TestJsonSerializerEvents(t *testing.T) { // Aggregate metric j[4].assertPath(t, "iKey", test_ikey) - j[4].assertPath(t, "name", "Microsoft.ApplicationInsights.Metric") + j[4].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Metric") j[4].assertPath(t, "time", "2017-11-18T10:35:21Z") j[4].assertPath(t, "sampleRate", 100.0) j[4].assertPath(t, "data.baseType", "MetricData") @@ -125,7 +125,7 @@ func TestJsonSerializerEvents(t *testing.T) { // Remote dependency j[5].assertPath(t, "iKey", test_ikey) - j[5].assertPath(t, "name", "Microsoft.ApplicationInsights.RemoteDependency") + j[5].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.RemoteDependency") j[5].assertPath(t, "time", "2017-11-18T10:35:21Z") j[5].assertPath(t, "sampleRate", 100.0) j[5].assertPath(t, "data.baseType", "RemoteDependencyData") @@ -142,7 +142,7 @@ func TestJsonSerializerEvents(t *testing.T) { // Availability j[6].assertPath(t, "iKey", test_ikey) - j[6].assertPath(t, "name", "Microsoft.ApplicationInsights.Availability") + j[6].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Availability") j[6].assertPath(t, "time", "2017-11-18T10:35:21Z") j[6].assertPath(t, "sampleRate", 100.0) j[6].assertPath(t, "data.baseType", "AvailabilityData") @@ -157,7 +157,7 @@ func TestJsonSerializerEvents(t *testing.T) { // Page view j[7].assertPath(t, "iKey", test_ikey) - j[7].assertPath(t, "name", "Microsoft.ApplicationInsights.PageView") + j[7].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.PageView") j[7].assertPath(t, "time", "2017-11-18T10:35:21Z") j[7].assertPath(t, "sampleRate", 100.0) j[7].assertPath(t, "data.baseType", "PageViewData") @@ -235,7 +235,7 @@ func TestJsonSerializerNakedEvents(t *testing.T) { // Trace j[0].assertPath(t, "iKey", test_ikey) - j[0].assertPath(t, "name", "Microsoft.ApplicationInsights.Message") + j[0].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Message") j[0].assertPath(t, "time", "2017-11-18T10:35:21Z") j[0].assertPath(t, "sampleRate", 100) j[0].assertPath(t, "data.baseType", "MessageData") @@ -245,7 +245,7 @@ func TestJsonSerializerNakedEvents(t *testing.T) { // Event j[1].assertPath(t, "iKey", test_ikey) - j[1].assertPath(t, "name", "Microsoft.ApplicationInsights.Event") + j[1].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Event") j[1].assertPath(t, "time", "2017-11-18T10:35:21Z") j[1].assertPath(t, "sampleRate", 100) j[1].assertPath(t, "data.baseType", "EventData") @@ -254,7 +254,7 @@ func TestJsonSerializerNakedEvents(t *testing.T) { // Metric j[2].assertPath(t, "iKey", test_ikey) - j[2].assertPath(t, "name", "Microsoft.ApplicationInsights.Metric") + j[2].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Metric") j[2].assertPath(t, "time", "2017-11-18T10:35:21Z") j[2].assertPath(t, "sampleRate", 100) j[2].assertPath(t, "data.baseType", "MetricData") @@ -267,7 +267,7 @@ func TestJsonSerializerNakedEvents(t *testing.T) { // Aggregate metric j[3].assertPath(t, "iKey", test_ikey) - j[3].assertPath(t, "name", "Microsoft.ApplicationInsights.Metric") + j[3].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Metric") j[3].assertPath(t, "time", "2017-11-18T10:35:21Z") j[3].assertPath(t, "sampleRate", 100.0) j[3].assertPath(t, "data.baseType", "MetricData") @@ -283,7 +283,7 @@ func TestJsonSerializerNakedEvents(t *testing.T) { // Request j[4].assertPath(t, "iKey", test_ikey) - j[4].assertPath(t, "name", "Microsoft.ApplicationInsights.Request") + j[4].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Request") j[4].assertPath(t, "time", "2017-11-18T10:35:21Z") // Context takes current time since it's not supplied j[4].assertPath(t, "sampleRate", 100.0) j[4].assertPath(t, "data.baseType", "RequestData") @@ -303,7 +303,7 @@ func TestJsonSerializerNakedEvents(t *testing.T) { // Remote dependency j[5].assertPath(t, "iKey", test_ikey) - j[5].assertPath(t, "name", "Microsoft.ApplicationInsights.RemoteDependency") + j[5].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.RemoteDependency") j[5].assertPath(t, "time", "2017-11-18T10:35:21Z") j[5].assertPath(t, "sampleRate", 100.0) j[5].assertPath(t, "data.baseType", "RemoteDependencyData") @@ -319,7 +319,7 @@ func TestJsonSerializerNakedEvents(t *testing.T) { // Availability j[6].assertPath(t, "iKey", test_ikey) - j[6].assertPath(t, "name", "Microsoft.ApplicationInsights.Availability") + j[6].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.Availability") j[6].assertPath(t, "time", "2017-11-18T10:35:21Z") j[6].assertPath(t, "sampleRate", 100.0) j[6].assertPath(t, "data.baseType", "AvailabilityData") @@ -333,7 +333,7 @@ func TestJsonSerializerNakedEvents(t *testing.T) { // Page view j[7].assertPath(t, "iKey", test_ikey) - j[7].assertPath(t, "name", "Microsoft.ApplicationInsights.PageView") + j[7].assertPath(t, "name", "Microsoft.ApplicationInsights.01234567000089abcdef000000000000.PageView") j[7].assertPath(t, "time", "2017-11-18T10:35:21Z") j[7].assertPath(t, "sampleRate", 100.0) j[7].assertPath(t, "data.baseType", "PageViewData") @@ -346,7 +346,7 @@ func TestJsonSerializerNakedEvents(t *testing.T) { // Test helpers... func telemetryBuffer(items ...Telemetry) telemetryBufferItems { - ctx := NewTelemetryContext() + ctx := NewTelemetryContext(test_ikey) ctx.iKey = test_ikey var result telemetryBufferItems diff --git a/appinsights/telemetry.go b/appinsights/telemetry.go index 08378d5..940eeff 100644 --- a/appinsights/telemetry.go +++ b/appinsights/telemetry.go @@ -13,7 +13,7 @@ import ( // Common interface implemented by telemetry data contracts type TelemetryData interface { - EnvelopeName() string + EnvelopeName(string) string BaseType() string Sanitize() []string } diff --git a/appinsights/telemetrycontext.go b/appinsights/telemetrycontext.go index 9172ba3..0a5c1f6 100644 --- a/appinsights/telemetrycontext.go +++ b/appinsights/telemetrycontext.go @@ -1,6 +1,7 @@ package appinsights import ( + "strings" "time" "github.com/Microsoft/ApplicationInsights-Go/appinsights/contracts" @@ -14,6 +15,9 @@ type TelemetryContext struct { // Instrumentation key iKey string + // Stripped-down instrumentation key used in envelope name + nameIKey string + // Collection of tag data to attach to the telemetry item. Tags contracts.ContextTags @@ -24,8 +28,10 @@ type TelemetryContext struct { } // Creates a new, empty TelemetryContext -func NewTelemetryContext() *TelemetryContext { +func NewTelemetryContext(ikey string) *TelemetryContext { return &TelemetryContext{ + iKey: ikey, + nameIKey: strings.Replace(ikey, "-", "", -1), Tags: make(contracts.ContextTags), CommonProperties: make(map[string]string), } @@ -55,7 +61,7 @@ func (context *TelemetryContext) envelop(item Telemetry) *contracts.Envelope { data.BaseData = tdata envelope := contracts.NewEnvelope() - envelope.Name = tdata.EnvelopeName() + envelope.Name = tdata.EnvelopeName(context.nameIKey) envelope.Data = data envelope.IKey = context.iKey diff --git a/appinsights/telemetrycontext_test.go b/appinsights/telemetrycontext_test.go index 44e9a49..9ed24fc 100644 --- a/appinsights/telemetrycontext_test.go +++ b/appinsights/telemetrycontext_test.go @@ -9,7 +9,7 @@ import ( ) func TestDefaultTags(t *testing.T) { - context := NewTelemetryContext() + context := NewTelemetryContext(test_ikey) context.Tags["test"] = "OK" context.Tags["no-write"] = "Fail" @@ -28,7 +28,7 @@ func TestDefaultTags(t *testing.T) { } func TestCommonProperties(t *testing.T) { - context := NewTelemetryContext() + context := NewTelemetryContext(test_ikey) context.CommonProperties = map[string]string{ "test": "OK", "no-write": "Fail", @@ -79,7 +79,7 @@ func TestSanitize(t *testing.T) { ev.Properties[name] = val ev.Measurements[name] = 55.0 - ctx := NewTelemetryContext() + ctx := NewTelemetryContext(test_ikey) ctx.Tags.Session().SetId(name) // We'll be looking for messages with these values: @@ -138,7 +138,7 @@ func TestTimestamp(t *testing.T) { ev := NewEventTelemetry("event") ev.Timestamp = time.Unix(1523667421, 500000000) - envelope := NewTelemetryContext().envelop(ev) + envelope := NewTelemetryContext(test_ikey).envelop(ev) if envelope.Time != "2018-04-14T00:57:01.5Z" { t.Errorf("Unexpected timestamp: %s", envelope.Time) } diff --git a/generateschema.ps1 b/generateschema.ps1 new file mode 100644 index 0000000..1263d95 --- /dev/null +++ b/generateschema.ps1 @@ -0,0 +1,92 @@ +<# + +.SYNOPSIS + +Generate data contracts for Application Insights Go SDK from bond schema. + +.DESCRIPTION + +This is a convenience tool for generating the AI data contracts from the latest +bond schema. It requires BondSchemaGenerator.exe in order to operate. It also +requires the latest bond schema, but will check it out from github if it is not +present in the current directory. + +.PARAMETER BondSchemaGenerator + +The full path to BondSchemaGenerator.exe + +.PARAMETER SchemasDir + +The path to the directory that contains all of the input .bond files. + +.LINK https://github.com/Microsoft/ApplicationInsights-Home + +#> + +[cmdletbinding()] +Param( + [Parameter(Mandatory=$true)] + [string] $BondSchemaGenerator, + [string] $SchemasDir +) + +function RunBondSchemaGenerator +{ + [cmdletbinding()] + Param( + [string] $Language, + [string[]] $Files, + [string] $Layout, + [string[]] $Omissions + ) + + $args = @("-v") + $args += @("-o", ".") + $args += @("-e", $Language) + $args += @("-t", $Layout) + + foreach ($file in $Files) { + $args += @("-i", $file) + } + + foreach ($omission in $Omissions) { + $args += @("--omit", $omission) + } + + & "$BondSchemaGenerator" $args 2>&1 +} + +$origpath = Get-Location + +try { + $scriptpath = $MyInvocation.MyCommand.Path + $dir = Split-Path $scriptpath + cd $dir + + if (-not (Test-Path $BondSchemaGenerator -PathType Leaf)) { + Write-Host "Could not find BondSchemaGenerator at $BondSchemaGenerator" + Write-Host "Please specify the full path" + Exit 1 + } + + if (-not $schemasDir) { + $schemasDir = ".\ApplicationInsights-Home\EndpointSpecs\Schemas\Bond" + + # Check locally. + if (-not (Test-Path .\ApplicationInsights-Home -PathType Container)) { + # Clone into it! + git clone https://github.com/Microsoft/ApplicationInsights-Home.git + } + } + + $files = Get-ChildItem $schemasDir | % { "$schemasDir\$_" } + $omissions = @("Microsoft.Telemetry.Domain", "Microsoft.Telemetry.Base", "AI.AjaxCallData", "AI.PageViewPerfData") + + RunBondSchemaGenerator -Files $files -Language GoBondTemplateLanguage -Layout GoTemplateLayout -Omissions $omissions + RunBondSchemaGenerator -Files $files -Language GoContextTagsLanguage -Layout GoTemplateLayout -Omissions $omissions + + cd appinsights\contracts + go fmt +} finally { + cd $origpath +}