Skip to content

Commit d951d0c

Browse files
committed
Adds settings for OpenTelemetry
1 parent eaa04fb commit d951d0c

6 files changed

Lines changed: 113 additions & 52 deletions

File tree

src/FsAutoComplete.Core/Utils.fs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -884,17 +884,17 @@ module Tracing =
884884
interface IActivityTracingStrategy with
885885
member this.ApplyInboundActivity(request: Protocol.JsonRpcRequest) : IDisposable =
886886
let tags =
887-
[
888-
"rpc.system", box "jsonrpc"
887+
[ "rpc.system", box "jsonrpc"
889888
"rpc.jsonrpc.is_notification", box request.IsNotification
890889
"rpc.jsonrpc.is_response_expected", box request.IsResponseExpected
891890
"rpc.jsonrpc.version", box request.Version
892891
"rpc.jsonrpc.request_id", box request.RequestId
893-
"rpc.method", box request.Method
894-
]
892+
"rpc.method", box request.Method ]
895893
|> Seq.map KeyValuePair
896894

897-
let activity = activitySource.StartActivity(ActivityKind.Server, name = request.Method, tags = tags)
895+
let activity =
896+
activitySource.StartActivity(ActivityKind.Server, name = request.Method, tags = tags)
897+
898898
if activity <> null then
899899
activity.TraceStateString <- request.TraceState
900900

src/FsAutoComplete/LspHelpers.fs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,10 @@ type InlineValueDto =
600600
{ Enabled: bool option
601601
Prefix: string option }
602602

603+
type NotificationsDto =
604+
{ Trace: bool option
605+
TraceNamespaces: string array option }
606+
603607
type DebugDto =
604608
{ DontCheckRelatedFiles: bool option
605609
CheckFileDebouncerTimeout: int option
@@ -643,6 +647,7 @@ type FSharpConfigDto =
643647
CodeLenses: CodeLensConfigDto option
644648
PipelineHints: InlineValueDto option
645649
InlayHints: InlayHintDto option
650+
Notifications: NotificationsDto option
646651
Debug: DebugDto option }
647652

648653
type FSharpConfigRequest = { FSharp: FSharpConfigDto }
@@ -673,6 +678,23 @@ type InlineValuesConfig =
673678
{ Enabled = Some true
674679
Prefix = Some "//" }
675680

681+
type NotificationsConfig =
682+
{ Trace: bool
683+
TraceNamespaces: string array }
684+
685+
static member Default =
686+
{ Trace = false
687+
TraceNamespaces = [||] }
688+
689+
static member FromDto(dto: NotificationsDto) : NotificationsConfig =
690+
{ Trace = defaultArg dto.Trace NotificationsConfig.Default.Trace
691+
TraceNamespaces = defaultArg dto.TraceNamespaces NotificationsConfig.Default.TraceNamespaces }
692+
693+
694+
member this.AddDto(dto: NotificationsDto) : NotificationsConfig =
695+
{ Trace = defaultArg dto.Trace this.Trace
696+
TraceNamespaces = defaultArg dto.TraceNamespaces this.TraceNamespaces }
697+
676698
type DebugConfig =
677699
{ DontCheckRelatedFiles: bool
678700
CheckFileDebouncerTimeout: int
@@ -722,6 +744,7 @@ type FSharpConfig =
722744
CodeLenses: CodeLensConfig
723745
InlayHints: InlayHintsConfig
724746
InlineValues: InlineValuesConfig
747+
Notifications: NotificationsConfig
725748
Debug: DebugConfig }
726749

727750
static member Default: FSharpConfig =
@@ -761,6 +784,7 @@ type FSharpConfig =
761784
CodeLenses = CodeLensConfig.Default
762785
InlayHints = InlayHintsConfig.Default
763786
InlineValues = InlineValuesConfig.Default
787+
Notifications = NotificationsConfig.Default
764788
Debug = DebugConfig.Default }
765789

766790
static member FromDto(dto: FSharpConfigDto) : FSharpConfig =
@@ -825,7 +849,10 @@ type FSharpConfig =
825849
| Some ivDto ->
826850
{ Enabled = ivDto.Enabled |> Option.defaultValue true |> Some
827851
Prefix = ivDto.Prefix |> Option.defaultValue "//" |> Some }
828-
852+
Notifications =
853+
dto.Notifications
854+
|> Option.map NotificationsConfig.FromDto
855+
|> Option.defaultValue NotificationsConfig.Default
829856
Debug =
830857
match dto.Debug with
831858
| None -> DebugConfig.Default
@@ -908,6 +935,10 @@ type FSharpConfig =
908935
InlineValues =
909936
{ Enabled = defaultArg (dto.PipelineHints |> Option.map (fun n -> n.Enabled)) x.InlineValues.Enabled
910937
Prefix = defaultArg (dto.PipelineHints |> Option.map (fun n -> n.Prefix)) x.InlineValues.Prefix }
938+
Notifications =
939+
dto.Notifications
940+
|> Option.map x.Notifications.AddDto
941+
|> Option.defaultValue NotificationsConfig.Default
911942
Debug =
912943
match dto.Debug with
913944
| None -> DebugConfig.Default

src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,16 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar
196196
/// in the future
197197
let selectProject projs = projs |> List.tryHead
198198

199+
let mutable traceNotifications: ProgressListener option = None
200+
201+
let replaceTraceNotification shouldTrace traceNamespaces =
202+
traceNotifications |> Option.iter dispose
203+
204+
if shouldTrace then
205+
traceNotifications <- Some(new ProgressListener(lspClient, traceNamespaces))
206+
else
207+
traceNotifications <- None
208+
199209
let mutableConfigChanges =
200210
let toCompilerToolArgument (path: string) = sprintf "--compilertool:%s" path
201211

@@ -204,6 +214,8 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar
204214
and! checker = checker
205215
and! rootPath = rootPath
206216

217+
replaceTraceNotification config.Notifications.Trace config.Notifications.TraceNamespaces
218+
207219
checker.SetFSIAdditionalArguments
208220
[| yield! config.FSICompilerToolLocations |> Array.map toCompilerToolArgument
209221
yield! config.FSIExtraParameters |]
@@ -307,8 +319,6 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar
307319

308320
let fileChecked = Event<ParseAndCheckResults * VolatileFile * CancellationToken>()
309321

310-
do disposables.Add <| new ProgressListener(lspClient)
311-
312322
do
313323
disposables.Add
314324
<| fileParsed.Publish.Subscribe(fun (parseResults, proj, ct) ->
@@ -1703,8 +1713,9 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar
17031713
percentage = percentage 0 checksToPerform.Length
17041714
)
17051715

1706-
let maxConcurrency = 3
1707-
// Math.Max(1.0, Math.Floor((float System.Environment.ProcessorCount) * 0.75))
1716+
let maxConcurrency =
1717+
Math.Max(1.0, Math.Floor((float System.Environment.ProcessorCount) * 0.75))
1718+
17081719
do! Async.Parallel(checksToPerform, int maxConcurrency) |> Async.Ignore<unit array>
17091720

17101721
}

src/FsAutoComplete/LspServers/FSharpLspClient.fs

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -149,25 +149,30 @@ open Ionide.ProjInfo.Logging
149149

150150

151151
/// listener for the the events generated from the fsc ActivitySource
152-
type ProgressListener(lspClient: FSharpLspClient) =
152+
type ProgressListener(lspClient: FSharpLspClient, traceNamespace: string array) =
153153

154-
let isOneOf list string = list |> List.exists (fun f -> f string)
154+
let isOneOf list string =
155+
list |> Array.exists (fun f -> f string)
155156

157+
let strEquals (other: string) (this: string) =
158+
this.Equals(other, StringComparison.InvariantCultureIgnoreCase)
156159

157160
let strContains (substring: string) (str: string) = str.Contains(substring)
158161

159-
let interestingActivities =
160-
[
161-
162-
strContains "BoundModel."
163-
strContains "IncrementalBuild."
164-
strContains "CheckDeclarations."
165-
strContains "ParseAndCheckInputs."
166-
strContains "BackgroundCompiler."
167-
strContains "IncrementalBuildSyntaxTree."
168-
strContains "ParseAndCheckFile."
169-
strContains "ParseAndCheckInputs."
170-
strContains "CheckDeclarations." ]
162+
let interestingActivities = traceNamespace |> Array.map strContains
163+
// [
164+
// strEquals "BoundModel.TypeCheck"
165+
// strContains "BackgroundCompiler."
166+
// // strContains "BoundModel."
167+
// // strContains "IncrementalBuild."
168+
// // strContains "CheckDeclarations."
169+
// // strContains "ParseAndCheckInputs."
170+
// // strContains "BackgroundCompiler."
171+
// // strContains "IncrementalBuildSyntaxTree."
172+
// // strContains "ParseAndCheckFile."
173+
// // strContains "ParseAndCheckInputs."
174+
// // strContains "CheckDeclarations."
175+
// ]
171176

172177
let logger = LogProvider.getLoggerByName "Compiler"
173178

@@ -179,12 +184,14 @@ type ProgressListener(lspClient: FSharpLspClient) =
179184
let isStopped (activity: Activity) =
180185
#if NET6_0
181186
false
187+
||
182188
#else
183189
activity.IsStopped
190+
||
184191
#endif
185192
// giving this 1 seconds to report something, otherwise assume it's a dead activity
186-
|| ((DateTime.UtcNow - activity.StartTimeUtc) > TimeSpan.FromSeconds(1.)
187-
&& activity.Duration = TimeSpan.Zero)
193+
((DateTime.UtcNow - activity.StartTimeUtc) > TimeSpan.FromSeconds(5.)
194+
&& activity.Duration = TimeSpan.Zero)
188195

189196
let getTagItemSafe key (a: Activity) = a.GetTagItem key |> Option.ofObj
190197

@@ -200,7 +207,6 @@ type ProgressListener(lspClient: FSharpLspClient) =
200207
>> Option.map IO.Path.GetFileName
201208
>> Option.defaultValue String.Empty
202209

203-
204210
let getUserOpName =
205211
getTagItemSafe Tracing.SemanticConventions.FCS.userOpName
206212
>> Option.map string
@@ -218,9 +224,10 @@ type ProgressListener(lspClient: FSharpLspClient) =
218224
inflightEvents.TryRemove(a.Id) |> ignore
219225
else
220226
// FSC doesn't start their spans with tags so we have to see if it's been added later https://github.com/dotnet/fsharp/issues/14776
221-
let fileName = getFileName a
222-
let userOpName = getUserOpName a
223-
do! p.Report(message = $"{fileName} - {userOpName}")
227+
let message = String.Join(" - ", [ getFileName a; getProject a; getUserOpName a ])
228+
229+
230+
do! p.Report(message = message)
224231

225232
match! inbox.TryReceive(250) with
226233
| None ->
@@ -233,10 +240,10 @@ type ProgressListener(lspClient: FSharpLspClient) =
233240
let fileName = getFileName activity
234241
let userOpName = getUserOpName activity
235242

236-
logger.debug (
237-
Log.setMessageI
238-
$"Started : {activity.DisplayName:DisplayName} - {userOpName:UserOpName} - {fileName:fileName}"
239-
)
243+
// logger.debug (
244+
// Log.setMessageI
245+
// $"Started : {activity.DisplayName:DisplayName} - {userOpName:UserOpName} - {fileName:fileName}"
246+
// )
240247

241248
if
242249
activity.DisplayName |> isOneOf interestingActivities
@@ -253,10 +260,10 @@ type ProgressListener(lspClient: FSharpLspClient) =
253260
let userOpName = getUserOpName activity
254261
let duration = activity.Duration.ToString()
255262

256-
logger.debug (
257-
Log.setMessageI
258-
$"Finished : {activity.DisplayName:DisplayName} - {userOpName:UserOpName} - {fileName:fileName} - took {duration:duration}"
259-
)
263+
// logger.debug (
264+
// Log.setMessageI
265+
// $"Finished : {activity.DisplayName:DisplayName} - {userOpName:UserOpName} - {fileName:fileName} - took {duration:duration}"
266+
// )
260267

261268
if activity.DisplayName |> isOneOf interestingActivities then
262269
match inflightEvents.TryRemove(activity.Id) with

src/FsAutoComplete/Parser.fs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ module Parser =
2222

2323
let mutable tracerProvider = Unchecked.defaultof<_>
2424

25+
26+
2527
[<Struct>]
2628
type Pos = { Line: int; Column: int }
2729

@@ -95,6 +97,12 @@ module Parser =
9597
"Enable LSP Server based on FSharp.Data.Adaptive. Should be more stable, but is experimental."
9698
)
9799

100+
let otelTracingOption =
101+
Option<bool>(
102+
"--otel-exporter-enabled",
103+
"Enabled OpenTelemetry exporter. See https://opentelemetry.io/docs/reference/specification/protocol/exporter/ for environment variables to configure for the exporter."
104+
)
105+
98106
let stateLocationOption =
99107
Option<DirectoryInfo>(
100108
"--state-directory",
@@ -115,6 +123,7 @@ module Parser =
115123
rootCommand.AddOption adaptiveLspServerOption
116124
rootCommand.AddOption logLevelOption
117125
rootCommand.AddOption stateLocationOption
126+
rootCommand.AddOption otelTracingOption
118127

119128

120129

@@ -178,20 +187,22 @@ module Parser =
178187

179188
let configureOTel =
180189
Invocation.InvocationMiddleware(fun ctx next ->
181-
let serviceName = FsAutoComplete.Utils.Tracing.serviceName
182-
let version = FsAutoComplete.Utils.Version.info().Version
183-
184-
tracerProvider <-
185-
Sdk
186-
.CreateTracerProviderBuilder()
187-
.AddSource(serviceName, Tracing.fscServiceName)
188-
.SetResourceBuilder(
189-
ResourceBuilder
190-
.CreateDefault()
191-
.AddService(serviceName = serviceName, serviceVersion = version)
192-
)
193-
.AddOtlpExporter()
194-
.Build()
190+
191+
if ctx.ParseResult.HasOption otelTracingOption then
192+
let serviceName = FsAutoComplete.Utils.Tracing.serviceName
193+
let version = FsAutoComplete.Utils.Version.info().Version
194+
195+
tracerProvider <-
196+
Sdk
197+
.CreateTracerProviderBuilder()
198+
.AddSource(serviceName, Tracing.fscServiceName)
199+
.SetResourceBuilder(
200+
ResourceBuilder
201+
.CreateDefault()
202+
.AddService(serviceName = serviceName, serviceVersion = version)
203+
)
204+
.AddOtlpExporter()
205+
.Build()
195206

196207
next.Invoke(ctx))
197208

test/FsAutoComplete.Tests.Lsp/Helpers.fs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ let defaultConfigDto: FSharpConfigDto =
269269
Some
270270
{ Enabled = Some true
271271
Prefix = Some "//" }
272+
Notifications = None
272273
Debug = None }
273274

274275
let clientCaps: ClientCapabilities =

0 commit comments

Comments
 (0)