Simple example for logging text in expecto test - f#

I'm trying to write some logs in an Expecto test, however I can't figure out how to get anything to be logged. Is there a very simple example of this somewhere? Currently I have:
module Test
open Expecto
open Expecto.Logging
open Expecto.Logging.Message
open Hopac
open Logary.Configuration
open Logary.Adapters.Facade
open Logary.Targets
[<Tests>]
let tests =
test "A simple test" {
let logger = Log.create "asdf.qwer"
let one = 1
ignore (logger.logWithAck Debug (eventX "asdf"))
Expect.equal one 1 "Should equals 1"
}
[<EntryPoint>]
let main argv =
let logary =
Config.create "MyProject.Tests" "localhost"
|> Config.targets [ LiterateConsole.create LiterateConsole.empty "console" ]
|> Config.processing (Events.events |> Events.sink ["console";])
|> Config.build
|> run
LogaryFacadeAdapter.initialise<Expecto.Logging.Logger> logary
// Invoke Expecto:
runTestsInAssemblyWithCLIArgs [] argv

Related

Minimal F# example to watch the Windows security Event Log

This never prints any events to the console (after "listening for new security events..."), though when I fire up the Event Viewer app it shows security events coming in. Thoughts on what I could be doing wrong?
open System
open System.Diagnostics
open System.Security.Principal
open System.Threading
let logName = "security"
let DumpEventLog desc =
use log = new System.Diagnostics.EventLog (logName, desc)
log.EnableRaisingEvents <- true;
printfn "listening for new security events...";
log.EntryWritten.Add (fun ent ->
let ent = ent.Entry in
printfn "entry written: %d %s %s" ent.InstanceId (ent.TimeGenerated.ToString())
ent.Message);
[<EntryPoint>]
let main _argv =
let isAdministrator =
let id = WindowsIdentity.GetCurrent () in
let p = WindowsPrincipal id in
p.IsInRole WindowsBuiltInRole.Administrator
in
let () =
if not isAdministrator
then printfn "need admin privs to run!"
else DumpEventLog "."
in
while true do
Thread.Sleep 5000
done;
0
I think it has something to do with the way your program is written. For example, when DumpEventLog() exits, the log is disposed - but then the program sleeps for five seconds. I don't see how it would catch an event in that state.
This works for me:
open System.Diagnostics
open System.Threading
[<EntryPoint>]
let main _argv =
use log = new EventLog ("security", ".")
log.EnableRaisingEvents <- true
printfn "listening for new security events..."
log.EntryWritten.Add (fun e ->
printfn "Entry written: %d %O %s" e.Entry.InstanceId e.Entry.TimeGenerated e.Entry.Message)
Thread.Sleep Timeout.Infinite
0

Can't get WebSharper Javascript Client to run hosted on Suave

I am trying out the example snippet titled "Adding client-side functionality" from the following page :
https://developers.websharper.com/docs/v4.x/fs/overview
It looks a bit outdated and doesn't compile as is, so based on the original repository where that code was snipped from, this is what I have now.
namespace TestSuaveWs
open WebSharper
open WebSharper.Sitelets
open WebSharper.UI
open WebSharper.UI.Html
open WebSharper.UI.Client
module Server =
[<Rpc>]
let DoWork (s: string) =
async {
return System.String(List.ofSeq s |> List.rev |> Array.ofList)
}
[<JavaScript>]
module Client =
open WebSharper.JavaScript
open WebSharper.Html.Client
let Main () =
let input = Input [ Attr.Value "" ]
let output = H1 []
Div [
input
Button [ Text "Send" ]
|>! OnClick (fun _ _ ->
async {
let! data = Server.DoWork input.Value
output.Text <- data
}
|> Async.Start
)
HR []
H4 [ Class "text-muted" ] -- Text "The server responded:"
Div [ Class "jumbotron" ] -< [ output ]
]
module TheSite =
open WebSharper.UI.Server
[<Website>]
let MySite =
Application.SinglePage (fun ctx ->
Content.Page(
Body = [
h1 [] [ text "Say Hi to the server" ]
div [] [ client <# Client.Main() #> ]
]
)
)
open global.Suave
open Suave.Web
open WebSharper.Suave
let webPart = WebSharperAdapter.ToWebPart(MySite, RootDirectory="../..")
Then there's the main program.
namespace TestSuaveWs
module Main =
open System
open System.Threading
open Suave
[<EntryPoint>]
let main argv =
let cts = new CancellationTokenSource()
let conf = { defaultConfig with cancellationToken = cts.Token }
let listening, server = startWebServerAsync conf TheSite.webPart
Async.Start(server, cts.Token)
printfn "Make requests now"
Console.ReadKey true |> ignore
cts.Cancel()
0
The program runs, and I can see the text "Say Hi to the server" on localhost:8080, but there is nothing below that text. A picture on the page with the example shows what it should look like. There's supposed to be a text input field, a button, and a reply text.
When I open Developer Tools in my Chrome browser, I can see that there's a bunch of similar messages, differing only in the javascript filename, that says "Failed to load resource: the server responded with a status of 404 WebSharper.Main.min.js:1 (Not Found)"
There are no *.js files in the bin\Debug folder. I am running in VS 2019, with .NET Framework 4.7.1.
What am I missing?
I wasn't aware that this very example was available as a template named "WebSharper 4 Suave-hosted Site", which I only found after downloading and installing the WebSharper vsix. That template spun up a project doing exactly what I tried to achieve. So that's the answer. I wish this was hinted at in the documentation page.

Embedding F# Interactive throw System.Exception: 'Error creating evaluation session: StopProcessingExn None'

I'm working through the Embedding F# Interactive example from here but like this post, I'm having an issue with the following line throwing an exception:
let fsiSession = FsiEvaluationSession.Create(fsiConfig, allArgs, inStream, outStream, errStream)
The exception thrown is:
"System.Exception: 'Error creating evaluation session: StopProcessingExn None'"
My project is being run from VS2017 Enterprise, setup as a simple F# console app, with the Target Framework as .NET Core 2.0. The version of FSharp.Compiler.Service downloaded from nuget is 17.0.1 and FSharp.Core is 4.2.0.
The Program.Fs file code I'm running is here (a direct port of the example):
open System
open System.IO
open System.Text
open Microsoft.FSharp.Compiler.Interactive.Shell
[<EntryPoint>]
let main argv =
let sbOut = new StringBuilder()
let sbErr = new StringBuilder()
let inStream = new StringReader("")
let outStream = new StringWriter(sbOut)
let errStream = new StringWriter(sbErr)
// Build command line arguments & start FSI session
let argv = [| "C:\\Program Files (x86)\\Microsoft SDKs\\F#\\4.1\\Framework\\v4.0\\fsi.exe" |]
let allArgs = Array.append argv [|"--noninteractive"|]
let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration()
let fsiSession = FsiEvaluationSession.Create(fsiConfig, allArgs, inStream, outStream, errStream)
/// Evaluate expression & return the result
let evalExpression text =
match fsiSession.EvalExpression(text) with
| Some value -> printfn "%A" value.ReflectionValue
| None -> printfn "Got no result!"
evalExpression "42+1" // prints '43'
Console.ReadLine() |> ignore
0 // return integer
I already tried to add the files FSharp.Core.optdata and FSharp.Core.sigdata in my bin folder (bin\Debug\netcoreapp2.0) as mentioned here and here, but without success. By the way, my bin folder does not contain the file FSharp.Core.dll.
I also tried to publish my app and add the .optdata and .sigdata files manually in the publish folder, but without success either.
Any thoughts would be appreciated.

Insufficient permissions exception from BigQuery API

I am getting an "Insufficient Permissions" exception from BigQuery when trying to list the datasets in my project (via service.Datasets.List). What do I have to do to grant this permission? Full F# source code:
open System
open System.IO
open System.Threading
open Google.Apis.Auth.OAuth2
open Google.Apis.Bigquery.v2
open Google.Apis.Bigquery.v2.Data
open Google.Apis.Services
let private service =
let credential =
let secrets =
use stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read)
GoogleClientSecrets.Load(stream).Secrets
let task =
GoogleWebAuthorizationBroker.AuthorizeAsync(
secrets,
[| BigqueryService.Scope.Bigquery |],
"user",
CancellationToken.None)
printfn "Authenticating"
task
|> Async.AwaitTask
|> Async.RunSynchronously
let initializer = new BaseClientService.Initializer(HttpClientInitializer = credential)
new BigqueryService(initializer)
[<EntryPoint>]
let main argv =
let projectId = "{MyProjectId}"
let list = service.Datasets.List(projectId).Execute()
for dataset in list.Datasets do
printfn "%A" dataset.FriendlyName
0
It turns out that I was missing a key line of boilerplate code:
GoogleWebAuthorizationBroker.Folder <- "Tasks.Auth.Store";
I don't really understand what this does (the documentation is woefully sparse), but adding this line solved the problem.

How to handle AggregateException of a plain task (with FSharpx.Core)?

My question is a two-fold one, I believe. In the following, how to catch AggregateException and print it out when
The tasks are Task objects, not Task<void> ones?
When the tasks Task<_> ones (e.g. Task<void>?
Here's s short, somewhat fabricated snippet. The taskGenerator in the following snippet emulates some external C# library function that either returns an array of Tasks or one Task combined with Task.WhenAll.
I'm not sure how should I catch the resulting AggregateException and print it in either generic or non-generic case. Then other problem is the interaction with the non-generic one which I need to cast to satisfy FSharpx, but then Ignore throws the exception which may not be desired.The Ignore function is from here, and I believe it's a rather used way to transform a Task to Task<unit>.
open FSharpx
open System.Threading.Tasks
open System
open FSharpx.Task
[<EntryPoint>]
let main argv =
let Ignore(task:Task) =
let continuation (t: Task): unit =
if t.IsFaulted then
raise t.Exception
else
()
task.ContinueWith continuation
let taskGenerator() =
let task = TaskBuilder(scheduler = TaskScheduler.Default)
//The following just emulates an external source that returns a bunch of plain
//tasks. It could return also one plain task one would like to await for (e.g.
//this exernal, simulated source could call Task.WhenAll.)
task {
let tasks =
[|1; 2; 3;|]
|> Seq.map(fun i ->
let taskSource = new TaskCompletionSource<unit>()
taskSource.SetException(new ArgumentException("Argh!"))
taskSource.Task :> Task)
return! Task.WhenAll(tasks) |> Ignore
}
let final() =
let task = TaskBuilder(scheduler = TaskScheduler.Default)
task {
let! a = taskGenerator()
a |> ignore
}
try
let finalRes = final()
finalRes |> ignore
with :? AggregateException as aex ->
printfn "%A" aex
let x = System.Console.ReadLine()
0

Resources