Serilog Exceptionless Sink in .NET Core 1.1 - serilog

How can the Serilog Exceptionless Sink be used with .NET Core 1.1?
The Serilog.Sinks.Exceptionless README isn't clear and doesn't work for .NET Core 1.1 where I have put the configuration in the appsettings.json file.
{
"Serilog": {
"Using": ["Serilog.Sinks.Literate"],
"MinimumLevel": ["Debug"],
"WriteTo": [{
"Name": "LiterateConsole"
}],
"Enrich": ["FromLogContext"],
"Properties": {
"Application": "MyAppServer"
}
}
}
Program.cs
public class Program
{
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(config)
.CreateLogger();
}
}
I obviously need to set up the API key somewhere, too.
Can anyone provide a clear description of how this can be configured, please?

In JSON you can add additional sinks to the "WriteTo" list and add arguments like apiKey in the "Args" block:
{
"Serilog": {
"Using": ["Serilog.Sinks.Literate"],
"MinimumLevel": ["Debug"],
"WriteTo": [{
"Name": "LiterateConsole"
}, {
"Name": "Exceptionless",
"Args": { apiKey: "12345" }
}],
"Enrich": ["FromLogContext"],
"Properties": {
"Application": "MyAppServer"
}
}
}

I think it's
Log.Logger = new LoggerConfiguration()
.WriteTo.Exceptionless(
apiKey: "yourApiKey",
additionalOperation: b => b.AddTags("ASP.NET Core Example Logger"))
.CreateLogger();

Related

Serilog not creating log file on production server

I've created a C# .net5.0 console application and during testing Serilog has been working without incident, logging to Console and File (same folder; path="log.txt"). However, when I run on the application on our server, neither Console nor File logging sinks are working! I assume now that the issue is not the sinks themselves but Serilog not actually working.
I've tried enabling the self log:
Serilog.Debugging.SelfLog.Enable(msg =>
Console.WriteLine(msg)
);
but even running in the debugger in my dev environment, the Console.WriteLine(msg) line is never called!
My appsettings.json is as follows:
{
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Information",
"System": "Information"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console",
"outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "log.txt",
"rollingInterval": "Infinite",
"outputTemplate": "{Timestamp:HH:mm:ss.fff} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
"shared": false
}
}
],
"Enrich": [ "FromLogContext" ]
},
"Database": {
"Server": "(local)",
"Database": "ActivbaseLive"
},
"Email": {
"SmtpHost": "localhost",
"SmtpPort": 25,
"SmtpSecurityOption": "None",
"SmtpUsername": null,
"SmtpPassword": null,
"SmtpSender": "\"Activbase Learning Platform\" <noreply#activbase.net>"
}
}
I've tried absolute paths (using double backslashes in appsettings.json).
I've tried pre-creating the log file (e.g. log.txt and log200428.txt) and setting permissions to Everyone Full Control but neither of these changes fix the problem and they don't explain why the Console sink doesn't write either.
Here is how Serilog is being configured during start-up which is where I suspect the problem is (even through it works in dev environment):
return Host.CreateDefaultBuilder()
.ConfigureLogging(logging =>
{
logging.ClearProviders();
})
.UseSerilog((hostContext, loggerConfiguration) =>
{
loggerConfiguration.ReadFrom.Configuration(hostContext.Configuration);
})
.ConfigureAppConfiguration((hostContext, builder) =>
{
builder.AddEnvironmentVariables();
})
.ConfigureServices(services =>
{
services.AddHostedService<Worker>();
...
});
}
Any ideas why Serilog isn't working in production?
The Path you provide should be absolute.
Some thing like this:
"path": "E:/wwwroot/QA/BackgroundWorkerService/Logs/logFile_.log"
Even I had the same issue, the above fix worked fine for me...
For my api application running in IIS: I had to assign the following permissions to the log folder for the IIS_IUSRS. I didn't need an absolute path!

CDK Stepfunction Fargate step that takes all json key

I wanted to create ECS task that takes all json as its environment input. But my cdk code won't deploy because of following error message, the error message is so vague and it is difficult for me to figure out why my code is wrong.
Failed to call Step Functions for request: 'com.amazonaws.services.stepfunctions.model.CreateStateMachineRequest'. (Service: null; Status Code: 500; Error Code: null; Request ID: null)
new StateMachine (/local/home/miae/Explanation/src/ForecastingDeepLearningExplanationInfrastructure/node_modules/#aws-cdk/aws-stepfunctions/lib/state-machine.ts:101:26)
My cdk code
...
const ecsFargateTask = new sfn.Task(this, 'myEcs', {
inputPath: "$",
resultPath: "$.ecs",
task: new class implements sfn.IStepFunctionsTask {
bind(): sfn.StepFunctionsTaskConfig {
return {
resourceArn: "arn:aws:states:::ecs:runTask.sync",
parameters: {
"LaunchType": "FARGATE",
"Cluster": props.cluster.clusterArn,
"TaskDefinition": taskDefinition.taskDefinitionArn,
"Overrides": {
"ContainerOverrides": [{
"Name": "myContainer",
"Environment.$": "$.envs"
}]
}
}
};
}
}
});
}
const chain = sfn.Chain.start(ecsFargateTask);
new sfn.StateMachine(this, `StateMachineCopy${props.stage}`, {
definition: chain,
timeout: cdk.Duration.seconds(3000)
});
This is the Step function I want, and I could manually create this without problem.
{
"StartAt": "ExplanationEcs",
"States": {
"ExplanationEcs": {
"End": true,
"InputPath": "$",
"Parameters": {
"LaunchType": "FARGATE",
"Cluster": "arn:aws:ecs:us-west-2:123456789:cluster/myCluster482E02CC-1VWQ5XRG4II88",
"TaskDefinition": "arn:aws:ecs:us-west-2:123456789:task-definition/myTaskDefinitionE3E6548C:3",
"Overrides": {
"ContainerOverrides": [
{
"Name": "myContainer",
"Environment.$": "$.envs"
}
]
}
},
"Type": "Task",
"Resource": "arn:aws:states:::ecs:runTask.sync",
"ResultPath": "$.ecs"
}
},
"TimeoutSeconds": 3000
}

'parseHasMany - Model type for relationship x not found' - How do I map nested JSON to models with Angular2-jsonapi

I am new to API's and Angular and I'm running into an issue I can't seem to resolve.
For a project I am currently working on I have set up a simple Rails API with the fast_jsonapi. This formats my JSON responses to be in line with JSON:API. I then have an Angular app which should take in that response and map it with the Angular2-jsonapi module.
For this issue imagine we have roles and accountabilities. One role can has 0 to many accountabilities. An accountability belongs to a single role.
When I sent a request to return all the roles, I get a JSON response which then gets properly mapped to models by the module. The issue arises when I try to include relationships.
According to the readme I have to define which relationship to include in the .findAll method like so:
{ include: 'accountabilities' }
The correct data is requested from the rails API, as it is the same request which I tested with Postman earlier. However the error that appears in my browser console is as follows:
{message: "parseHasMany - Model type for relationship accountability not found."}
I have tried other relationships and went through the setup proces a couple of times now, but I fail to see where things are going wrong. Searches on Google, Github and Stackoverflow haven't helped me in this case. Any help is very much appreciated.
Here is the relevant code. If any other information or code is needed, let me know and I'll happily update this post.
Example JSON response:
{
"data": [
{
"id": "1",
"type": "role",
"attributes": {
"name": "Farming Engineer",
"purpose": "Iure voluptatum rem dolores.",
"created_at": "2020-01-16T18:38:26.151Z",
"updated_at": "2020-01-16T18:38:26.151Z"
},
"relationships": {
"accountabilities": {
"data": [
{
"id": "6",
"type": "accountability"
},
{
"id": "12",
"type": "accountability"
}
]
}
}
},
{
"id": "2",
"type": "role",
"attributes": {
"name": "IT Supervisor",
"purpose": "Iusto fuga fugiat qui.",
"created_at": "2020-01-16T18:38:26.161Z",
"updated_at": "2020-01-16T18:38:26.161Z"
},
"relationships": {
"accountabilities": {
"data": []
}
}
}
],
"included": [
{
"id": "6",
"type": "accountability",
"attributes": {
"description": "penetrate the market",
"created_at": "2020-01-16T18:38:26.480Z",
"updated_at": "2020-01-16T18:38:26.480Z"
},
"relationships": {
"role": {
"data": {
"id": "1",
"type": "role"
}
}
}
},
{
"id": "12",
"type": "accountability",
"attributes": {
"description": "immersive experience",
"created_at": "2020-01-16T18:38:26.507Z",
"updated_at": "2020-01-16T18:38:26.507Z"
},
"relationships": {
"role": {
"data": {
"id": "1",
"type": "role"
}
}
}
}
]
}
role.model.ts
import {
JsonApiModelConfig,
JsonApiModel,
Attribute,
HasMany,
BelongsTo
} from 'angular2-jsonapi';
import { Accountability } from '#app/shared/models/accountability.model';
#JsonApiModelConfig({
type: 'roles'
})
export class Role extends JsonApiModel {
#Attribute()
name: string;
#Attribute()
purpose: string;
#Attribute({ serializedName: 'created_at' })
createdAt: Date;
#Attribute({ serializedName: 'updated_at' })
updatedAt: Date;
#HasMany()
accountabilities: Accountability[];
}
accountability.model.ts
import {
JsonApiModelConfig,
JsonApiModel,
Attribute,
BelongsTo
} from 'angular2-jsonapi';
import { Role } from '#app/shared/models/role.model';
#JsonApiModelConfig({
type: 'accountabilities'
})
export class Accountability extends JsonApiModel {
#Attribute()
description: string;
#Attribute({ serializedName: 'created_at' })
createdAt: Date;
#Attribute({ serializedName: 'updated_at' })
updatedAt: Date;
#BelongsTo()
role: Role;
}
datastore.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import {
JsonApiDatastoreConfig,
JsonApiDatastore,
DatastoreConfig
} from 'angular2-jsonapi';
import { Role } from '#app/shared/models/role.model';
import { Accountability } from '#app/shared/models/accountability.model';
const config: DatastoreConfig = {
baseUrl: 'http://localhost:3000/api',
apiVersion: 'v1',
models: {
roles: Role,
accountabilities: Accountability
}
};
#Injectable()
#JsonApiDatastoreConfig(config)
export class Datastore extends JsonApiDatastore {
constructor(http: HttpClient) {
super(http);
}
}
role.component.ts
import { Component, OnInit } from '#angular/core';
import { Datastore } from '#app/datastore';
import { Role } from '#app/shared/models/role.model';
import { JsonApiQueryData } from "angular2-jsonapi";
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.sass']
})
export class HomeComponent implements OnInit {
roles: Role[];
constructor(private datastore: Datastore) { }
ngOnInit() {
this.datastore
.findAll(Role, { include: 'accountabilities' })
.subscribe((roles: JsonApiQueryData<Role>) => {
console.log('>>>>>>>>>>>>>', roles);
console.log('>>>>>>>>>>>>>', roles.getModels());
this.roles = roles.getModels();
});
}
}
With a lot of help over on this Github topic I finally managed to get this resolved.
What initially caused the issue is that the response that I got from my API listed the type in relationships and included in singular whereas they needed to be plural.
Adding record_type: :accountabilities to the has_many relationship in my serializer changed this and successfully mapped the response to objects.

The service configuration is `nil` when instantiating AWSLambdaInvoker on Swift

I'm trying to implement a lambda function with an iOS app. I follow all the steps on this tutorial form AWS: https://docs.aws.amazon.com/aws-mobile/latest/developerguide/how-to-ios-lambda.html.
But when I add the following line:
let lambdaInvoker = AWSLambdaInvoker.default()
it throws this error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'The service configuration is `nil`. You need to configure `Info.plist` or set `defaultServiceConfiguration` before using this method.'
I added the awsconfiguration.json file to the project with this content:
{
"Version": "1.0",
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "us-east-1:05aab771-99b5-4a9b-8448-de92fe86ba56",
"Region": "us-east-1"
}
}
},
"IdentityManager" : {
"Default" : {
}
}
}
The app runs well importing AWSLambda and the mobileClient, and I'm able to validate credentials with Cognito (I get the "welcome to AWS" message)
Any ideas??
You will have to update your awsconfiguraiton.json file to have information about LambdaInvoker so that it can load the configuration for default service configuration. Your updated file should look like:
{
"Version": "1.0",
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "us-east-1:05aab771-99b5-4a9b-8448-de92fe86ba56",
"Region": "us-east-1"
}
}
},
"IdentityManager" : {
"Default" : {
}
},
"LambdaInvoker" : {
"Default" : {
"Region": "us-east-1"
}
}
}

How to import Swagger APIs into Postman?

Recently I wrote restful APIs with SpringMvc and swagger-ui(v2). I noticed the Import function in Postman:
So my question is how to create the file which Postman needed?
I am not familiar with Swagger.
I work on PHP and have used Swagger 2.0 to document the APIs.
The Swagger Document is created on the fly (at least that is what I use in PHP). The document is generated in the JSON format.
Sample document
{
"swagger": "2.0",
"info": {
"title": "Company Admin Panel",
"description": "Converting the Magento code into core PHP and RESTful APIs for increasing the performance of the website.",
"contact": {
"email": "jaydeep1012#gmail.com"
},
"version": "1.0.0"
},
"host": "localhost/cv_admin/api",
"schemes": [
"http"
],
"paths": {
"/getCustomerByEmail.php": {
"post": {
"summary": "List the details of customer by the email.",
"consumes": [
"string",
"application/json",
"application/x-www-form-urlencoded"
],
"produces": [
"application/json"
],
"parameters": [
{
"name": "email",
"in": "body",
"description": "Customer email to ge the data",
"required": true,
"schema": {
"properties": {
"id": {
"properties": {
"abc": {
"properties": {
"inner_abc": {
"type": "number",
"default": 1,
"example": 123
}
},
"type": "object"
},
"xyz": {
"type": "string",
"default": "xyz default value",
"example": "xyz example value"
}
},
"type": "object"
}
}
}
}
],
"responses": {
"200": {
"description": "Details of the customer"
},
"400": {
"description": "Email required"
},
"404": {
"description": "Customer does not exist"
},
"default": {
"description": "an \"unexpected\" error"
}
}
}
},
"/getCustomerById.php": {
"get": {
"summary": "List the details of customer by the ID",
"parameters": [
{
"name": "id",
"in": "query",
"description": "Customer ID to get the data",
"required": true,
"type": "integer"
}
],
"responses": {
"200": {
"description": "Details of the customer"
},
"400": {
"description": "ID required"
},
"404": {
"description": "Customer does not exist"
},
"default": {
"description": "an \"unexpected\" error"
}
}
}
},
"/getShipmentById.php": {
"get": {
"summary": "List the details of shipment by the ID",
"parameters": [
{
"name": "id",
"in": "query",
"description": "Shipment ID to get the data",
"required": true,
"type": "integer"
}
],
"responses": {
"200": {
"description": "Details of the shipment"
},
"404": {
"description": "Shipment does not exist"
},
"400": {
"description": "ID required"
},
"default": {
"description": "an \"unexpected\" error"
}
}
}
}
},
"definitions": {
}
}
This can be imported into Postman as follow.
Click on the 'Import' button in the top left corner of Postman UI.
You will see multiple options to import the API doc. Click on the 'Paste Raw Text'.
Paste the JSON format in the text area and click import.
You will see all your APIs as 'Postman Collection' and can use it from the Postman.
You can also use 'Import From Link'. Here paste the URL which generates the JSON format of the APIs from the Swagger or any other API Document tool.
This is my Document (JSON) generation file. It's in PHP. I have no idea of JAVA along with Swagger.
<?php
require("vendor/autoload.php");
$swagger = \Swagger\scan('path_of_the_directory_to_scan');
header('Content-Type: application/json');
echo $swagger;
With .Net Core it is now very easy:
You go and find JSON URL on your swagger page:
Click that link and copy the URL
Now go to Postman and click Import:
Select what you need and you end up with a nice collection of endpoints:
The accepted answer is correct but I will rewrite complete steps for java.
I am currently using Swagger V2 with Spring Boot 2 and it's straightforward 3 step process.
Step 1: Add required dependencies in pom.xml file. The second dependency is optional use it only if you need Swagger UI.
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
Step 2: Add configuration class
#Configuration
#EnableSwagger2
public class SwaggerConfig {
public static final Contact DEFAULT_CONTACT = new Contact("Usama Amjad", "https://stackoverflow.com/users/4704510/usamaamjad", "hello#email.com");
public static final ApiInfo DEFAULT_API_INFO = new ApiInfo("Article API", "Article API documentation sample", "1.0", "urn:tos",
DEFAULT_CONTACT, "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", new ArrayList<VendorExtension>());
#Bean
public Docket api() {
Set<String> producesAndConsumes = new HashSet<>();
producesAndConsumes.add("application/json");
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(DEFAULT_API_INFO)
.produces(producesAndConsumes)
.consumes(producesAndConsumes);
}
}
Step 3: Setup complete and now you need to document APIs in controllers
#ApiOperation(value = "Returns a list Articles for a given Author", response = Article.class, responseContainer = "List")
#ApiResponses(value = { #ApiResponse(code = 200, message = "Success"),
#ApiResponse(code = 404, message = "The resource you were trying to reach is not found") })
#GetMapping(path = "/articles/users/{userId}")
public List<Article> getArticlesByUser() {
// Do your code
}
Usage:
You can access your Documentation from http://localhost:8080/v2/api-docs just copy it and paste in Postman to import collection.
Optional Swagger UI: You can also use standalone UI without any other rest client via http://localhost:8080/swagger-ui.html and it's pretty good, you can host your documentation without any hassle.
Recommend you to read this answer
https://stackoverflow.com/a/51072071/4712855
Refer to the https://stackoverflow.com/posts/39072519 answer, and then partially delete the returned content. Finally, it is found that swagger lacks some configuration and postmat cannot be imported.
You need to add the following configuration in swagger
#Bean
public Docket api(SwaggerProperties swaggerProperties) {
swaggerProperties.setTitle("my-project");
swaggerProperties.setDescription("my project");
swaggerProperties.setVersion("v1");
swaggerProperties.getContact().setUrl("http");
//I overlooked other configurations. Note that my swagger configuration lacks these.
}
In short, the attributes in the ApiInfoBuilder class are assigned values as much as possible
spring-boot version:2.3.10.RELEASE
springfox-swagger version: 2.9.2
You can do that: Postman -> Import -> Link -> {root_url}/v2/api-docs
This is what worked for me from the Swagger editor interface:
Method 1
Copy the YAML file contents into the Raw Text area:
Method 2 (more steps)
Step 1: Export the file as JSON
Step 2: Import the JSON file with Postman "Import"
Click on the orange button ("choose files")
Browse to the Swagger doc (swagger.yaml)
After selecting the file, a new collection gets created in POSTMAN. It will contain folders based on your endpoints.
You can also get some sample swagger files online to verify this(if you have errors in your swagger doc).

Resources