Serilog, one file sink writing, one is leaving a blank file - serilog

So I have a simple method to make logger instances for me.
It is as follows
protected ILogger GetIndividualLogger(ILogger parentLogger, LogEventLevel minimumLevel, string RootDir, string Type, string Name, bool shouldBuffer, bool shouldBeShared, TimeSpan flushToDiskInterval)
{
var LogAllFile = $"{RootDir}{Path.DirectorySeparatorChar}{Name}{Path.DirectorySeparatorChar}RAL-{Type}-{Name}-.log";
var LogWarningFile = $"{RootDir}{Path.DirectorySeparatorChar}{Name}{Path.DirectorySeparatorChar}Warnings{Path.DirectorySeparatorChar}RAL-{Type}-{Name}-.log";
ILogger logger = new LoggerConfiguration()
.MinimumLevel.Is(minimumLevel)
.Enrich.WithDemystifiedStackTraces()
.WriteTo.Async(a => a.Logger(parentLogger))
.WriteTo.Async(a => a.File(LogAllFile, outputTemplate: SerilogHereHelper.TemplateForHere, rollingInterval: RollingInterval.Day, buffered: shouldBuffer, shared: shouldBeShared))
.WriteTo.Async(a => a.File(LogWarningFile, restrictedToMinimumLevel: LogEventLevel.Warning, outputTemplate: SerilogHereHelper.TemplateForHere, rollingInterval: RollingInterval.Day, buffered: shouldBuffer, shared: shouldBeShared, flushToDiskInterval: flushToDiskInterval))
.CreateLogger();
return logger;
}
Here is an example call to GetIndividualLogger
GetIndividualLogger(parentLogger: mainLogger, minimumLevel: LogEventLevel.Information, RootDir: _stackLightLogPath, Type: "Stack Light", Name: "Stack Light 1", shouldBuffer: true, shouldBeShared: false, flushToDiskInterval: TimeSpan.FromSecond(2))
The warning level sink will write, but then the other sink, which is usually set to debug or information will create an empty file but never add any entries to it.
I would expect both files to have all warning level entries or above.
I would expect the "LogAllFile" to have all entries at or above the minimum level, but it is blank.
Is there something wrong with my logger config? or is my problem elsewhere?

So the answer to the problem was silly. The warning log was being flushed to disk every 2 seconds, but the main log file was not so all I needed to do was to just pass a value in for flushToDiskInterval
.WriteTo.Async(a => a.File(LogAllFile, outputTemplate: SerilogHereHelper.TemplateForHere, rollingInterval: RollingInterval.Day, buffered: shouldBuffer, shared: shouldBeShared, flushToDiskInterval: flushToDiskInterval))

Related

Single log for each file Serilog - FileSink class Obsolete Error

I want to create a seperate log file for each HTTP request made to the application. When ever a request is made to the application, it has to generate a log file in the following format
debug20220713.log
debug20220713_001.log
debug20220713_002.log
Here in each log file there should be only one log available.
Log.Logger = new LoggerConfiguration()
.Enrich.WithExceptionDetails()
.Enrich.FromLogContext()
.WriteTo.Async(y =>
y.Logger(m =>
{
m.WriteTo.File(
new ExpressionTemplate(jsonErrorTemplate),
"error.log", LogEventLevel.Warning,
rollingInterval: RollingInterval.Day);
m.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Warning || e.Level == LogEventLevel.Error);
})
)
.WriteTo.Async(x =>
x.Logger(l =>
{
l.WriteTo.File(new ExpressionTemplate(jsonLogTemplate),
"debug.log", LogEventLevel.Information,
rollingInterval: RollingInterval.Day);
l.Filter.ByIncludingOnly(e => e.Level == LogEventLevel.Information);
}))
.CreateLogger();
I ended up creating own verision of RollingFileSink which matches my requirement. but internally I still use FileSink class. When I call constructor of FileSink I get this error
"This type and constructor will be removed from the public API in a future version; use WriteTo.File() instead."

Serilog logs on Console below minimum level

I defined a Logger this way with LogLevel FATAL for Console log:
LoggerConfiguration logCfg = new LoggerConfiguration();
logCfg
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Error)
.Enrich.FromLogContext()
.Enrich.With(new UtcTimestampEnricher())
.Enrich.WithProperty("SENDER", applicationName)
//ToDo, extend the Logger for DB to log an active GUID
//.Enrich.WithProperty("GUID", guid)
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Fatal)
.WriteTo.File(applicationLogPath,
restrictedToMinimumLevel: logEventLvlFile,
outputTemplate: fileOutputTemplate,
rollOnFileSizeLimit: changeOnFileSizeLimit,
fileSizeLimitBytes: fileSize,
retainedFileCountLimit: retainedFileCount);
But this will be displayed on Console:
_logger.LogInformation("Worker pulling config at: {time}", DateTimeOffset.Now);
This was the solution:
foreach (ServiceDescriptor serviceDescriptor in logging.Services)
{
if (serviceDescriptor.ImplementationType == typeof(Microsoft.Extensions.Logging.Console.ConsoleLoggerProvider))
{
// remove ConsoleLoggerProvider service only
logging.Services.Remove(serviceDescriptor);
break;
}
}
logging.AddSerilog();

Write this serilog filter in config file

Usually, I set the configuration of .NET applications inside the config file (appsettings.json or *.config file, it depends if it's .NET Core or .NET Full Framework).
Now for the first time, I had to use a filter, and I'm not able to write such logic inside the config file.
Here's the logic I wish to bring to the config file
var logConfiguration = new LoggerConfiguration()
//.ReadFrom.AppSettings()
.WriteTo.Logger(lc => lc.WriteTo.EventLog(environmentSettings.ServiceNameInstanceForMonitor, manageEventSource: true)
.Filter.ByIncludingOnly(pred =>
{
if (!pred.Properties.ContainsKey("Destination")) return false;
return pred.Properties["Destination"].ToString().Contains("EventLog");
}))
.Enrich.WithExceptionDetails()
.Enrich.WithAssemblyVersion(true)
.WriteTo.Console()
.WriteTo.Logger(lc2 => lc2.WriteTo
.File($"{AppDomain.CurrentDomain.BaseDirectory}\\logs\\{environmentSettings.ServiceNameInstanceForMonitor}-.log",
rollingInterval: RollingInterval.Day)
.Filter.ByExcluding((pred =>
{
var res = pred.Properties.ContainsKey("Destination") &&
pred.Properties["Destination"].ToString().Contains("EventLog");
return res;
})));
Is it possible?

Jenkins gives error on configuring Amazon EC2 cloud

I'm trying to setup a Jenkins server with EC2 plugin such that all builds are executed by the EC2 instances, which act as agents for the master server.
While trying to save the cloud configuration for 'Amazon EC2' cloud in the Jenkins master, it fails with an exception. Checking in the Jenkins logs, I see this exception:
Caught unhandled exception with ID f6d45d51-fb00-4d1c-a474-0a55dd5ee710
org.kohsuke.stapler.WrongTypeException: Got type array but no lister class found for type class java.lang.String
at org.kohsuke.stapler.RequestImpl$TypePair.convertJSON(RequestImpl.java:724)
at org.kohsuke.stapler.RequestImpl.bindJSON(RequestImpl.java:478)
at org.kohsuke.stapler.RequestImpl.instantiate(RequestImpl.java:787)
Caused: java.lang.IllegalArgumentException: Failed to convert the instanceCapStr parameter of
the constructor public hudson.plugins.ec2.AmazonEC2Cloud
(java.lang.String,boolean,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.util.List,java.lang.String,java.lang.String)
at org.kohsuke.stapler.RequestImpl.instantiate(RequestImpl.java:789)
at org.kohsuke.stapler.RequestImpl.access$200(RequestImpl.java:83)
at org.kohsuke.stapler.RequestImpl$TypePair.convertJSON(RequestImpl.java:678)
Caused: java.lang.IllegalArgumentException: Failed to instantiate class hudson.plugins.ec2.AmazonEC2Cloud from
{
"cloudName":"ec2-cloud",
"includeUser":["false","false"],
"credentialsId":"",
"useInstanceProfileForCredentials":true,
"altEC2Endpoint":"",
"region":"eu-west-1",
"sshKeysCredentialsId":"jenkins-slave-ssh-key",
"instanceCapStr":["",""],
"noDelayProvisioning":false,
"roleArn":"",
"roleSessionName":"",
"templates":{
"description":"Amazon Linux 2 AMI",
"ami":"ami-0bb3fad3c0286ebd5",
"type":"T2Micro",
"ebsOptimized":true,
"monitoring":true,
"t2Unlimited":false,
"zone":"",
"securityGroups":"",
"remoteFS":"/var/lib/jenkins",
"remoteAdmin":"ec2-user",
"":"0",
"amiType":{
"rootCommandPrefix":"",
"slaveCommandPrefix":"",
"slaveCommandSuffix":"",
"sshPort":"22",
"stapler-class":"hudson.plugins.ec2.UnixData",
"$class":"hudson.plugins.ec2.UnixData"
},
"labelString":"ec2",
"mode":"EXCLUSIVE",
"idleTerminationMinutes":"30",
"initScript":"",
"tmpDir":"",
"userData":"",
"numExecutors":"",
"jvmopts":"",
"stopOnTerminate":false,
"subnetId":"",
"useDedicatedTenancy":false,
"name":"","value":""
},
"minimumNumberOfInstances":"0",
"minimumNumberOfSpareInstances":"0",
"iamInstanceProfile":"arn:aws:iam::xxxxxxxxxxxx:instance-profile/jenkins_server_role",
"deleteRootOnTermination":true,
"useEphemeralDevices":true,
"customDeviceMapping":"",
"launchTimeoutStr":"",
"associatePublicIp":false,
"connectionStrategy":"PRIVATE_IP",
"connectBySSHProcess":false,
"hostKeyVerificationStrategy":"CHECK_NEW_HARD",
"maxTotalUses":"-1",
"nodeProperties":{"stapler-class-bag":"true"}
},"stapler-class":"hudson.plugins.ec2.AmazonEC2Cloud","$class":"hudson.plugins.ec2.AmazonEC2Cloud"}
at org.kohsuke.stapler.RequestImpl$TypePair.convertJSON(RequestImpl.java:681)
at org.kohsuke.stapler.RequestImpl.bindJSON(RequestImpl.java:478)
at org.kohsuke.stapler.RequestImpl.bindJSON(RequestImpl.java:474)
at hudson.model.Descriptor.newInstance(Descriptor.java:598)
I do see the property 'Instance cap' in two different locations in the Jenkins UI. My understanding is that one is for configuring a max limit on the total number of instances allowed in the entire cloud,
and the other property describes a max limit on the number of instances for the particular AMI.
Is this a Jenkins issue? Or is it something wrong with the configuration I've provided?
NOTE: I'm okay with providing the configuration as code rather than via the Jenkins UI. If anyone is able to provide the same configuration through code, that is also fine.
I eventually ended up configuring this using a groovy script run in the Script Console in the Jenkins UI. The groovy script I used is:
import hudson.model.*
import jenkins.model.*
import hudson.plugins.ec2.*
import com.amazonaws.services.ec2.model.InstanceType
def instance = Jenkins.getInstance()
def ec2_cloud_name = 'ec2-cloud'
def ec2_instance_cap = 5
def worker_description = 'jenkins-slave running in ec2 instance'
def worker_label_string = 'ec2-slave'
def ami_id = 'ami-xxxxxxxxxxxxxxxxx'
def security_groups = 'sg-xxxxxxxxxxxxxxxxxx'
def subnet_id = 'subnet-xxxxxxxx'
def instance_type = 't2.micro'
def instance_profile_arn = 'arn:aws:iam::xxxxxxxxxxxx:instance-profile/jenkins_server_role'
def number_of_executors = 2
def ec2_tags = [
new EC2Tag('Name', 'jenkins-slave-instance')
]
def priv_key_txt = '''
-----BEGIN RSA PRIVATE KEY-----
<My Private key>
-----END RSA PRIVATE KEY-----
'''
def worker_ami = new SlaveTemplate(
// String ami
ami_id,
// String zone
'',
// SpotConfiguration spotConfig
null,
// String securityGroups
security_groups,
// String remoteFS
'',
// InstanceType type
InstanceType.fromValue(instance_type),
// boolean ebsOptimized
false,
// String labelString
worker_label_string,
// Node.Mode mode
Node.Mode.NORMAL,
// String description
worker_description,
// String initScript
'',
// String tmpDir
'',
// String userData
'',
// String numExecutors
"${number_of_executors}",
// String remoteAdmin
'',
// AMITypeData amiType
new UnixData(null, null, null, null),
// String jvmopts
'',
// boolean stopOnTerminate
false,
// String subnetId
subnet_id,
// List<EC2Tag> tags
ec2_tags,
// String idleTerminationMinutes
'30',
// int minimumNumberOfInstances
0,
// int minimumNumberOfSpareInstances
0,
// string instanceCapStr
'3',
// string iamInstanceProfile
'arn:aws:iam::xxxxxxxxxxxx:instance-profile/jenkins_server_role',
// boolean deleteRootOnTermination
true,
// boolean useEphemeralDevices
true,
// boolean useDedicatedTenancy
false,
// String launchTimeoutStr
'1800',
// boolean associatePublicIp
false,
// String customDeviceMapping
'',
// boolean connectBySSHProcess
false,
// boolean monitoring
false,
// boolean t2Unlimited
false,
// Enum connectionStrategy
ConnectionStrategy.PRIVATE_IP,
// int maxTotalUses
3,
// List<? extends NodeProperty<?>> nodeProperties
[],
// HostKeyVerificationStrategyEnum
HostKeyVerificationStrategyEnum.CHECK_NEW_HARD
)
def new_cloud = new AmazonEC2Cloud(
// String cloudName
ec2_cloud_name,
// boolean useInstanceProfileForCredentials
true,
// String credentialsId
'',
// String region
'eu-west-1',
// String privateKey
priv_key_txt,
// String sshKeysCredentialsId
'jenkins-slave-ssh-key',
// String instanceCapStr
"3",
// List<? extends SlaveTemplate> templates
[worker_ami],
// String roleArn
null,
// String roleSessionName
null
)
instance.clouds.add(new_cloud)
Strange thing is, after creating the config by running this script, now I am able to edit and save the created config via the Jenkins UI.

Uncaught TypeError "is not a function" in js interop callback function

I have created this sample project: https://github.com/mfMeds/jsdart
to reproduce my error.
The error:
main.dart.js:5036 Uncaught TypeError: J.ab(...).ge5 is not a function
at Object.J.fm (main.dart.js:5036)
at cH.dart.cH.eu (main.dart.js:4962)
at Object.eval (eval at di (main.dart.js:786), <anonymous>:3:36)
at Object.ir (main.dart.js:628)
at dart.kZ (main.dart.js:4005)
at ChartElement.<anonymous> (main.dart.js:3998)
at ChartElement.update (Chart.js:8803)
at ChartElement.handleEvent (Chart.js:9100)
at Chart.eventHandler (Chart.js:4521)
at listener (Chart.js:4455)
Only when I am using an attribute of the variable a I am getting this error. With window.console.log(a) it is logging the object without error.
My error happens here: https://github.com/mfMeds/jsdart/blob/master/lib/src/zgraph/zgraph.dart#L80
#override
ngAfterViewInit() {
List<String> myDays = new List();
List<double> myData = new List();
myDays.add('Monday');
myData.add(12.0);
var data = new LinearChartData(labels: myDays, datasets: <ChartDataSets>[
new ChartDataSets(label: 'My Label', steppedLine: true, data: myData),
]);
var aOptions = new ChartAnimationOptions();
var config = new ChartConfiguration(
type: 'bar',
data: data,
options: new ChartOptions(
responsive: true,
maintainAspectRatio: false,
legend: new ChartLegendOptions(display: false),
//scales: new ChartScales(yAxes: [new ChartYAxe(ticks: new TickOptions(max:20))]),
animation: aOptions,
tooltips: new ChartTooltipOptions(
enabled: false,
custom: allowInterop(customTooltip), // <-- binding the method here
)));
new Chart(mycanvas, config);
}
void customTooltip(dynamic a) {
window.console.log(a);
if (a.opacity == 0) { // <-- The error happens here
//tooltipEl.style.opacity = '0';
return;
}
}
When I am serving the application like that everything works:
pub global run webdev serve web:xxxx.
Only when building the application like that I get this error:
pub global run webdev build --output=web:build
In the docs they write:
The properties of the JavaScript object are accessible via the [] and []= operators. Methods are callable via callMethod.
I tried this also, but it does not work...
I found a other solution. dynamic a is a js object. You can access js objects with js.getProperty I made a class for this:
import 'package:js/js_util.dart' as js;
class JsObject {
final dynamic _object;
const JsObject(this._object);
dynamic operator[](String name) => js.getProperty(_object, name);
operator[]=(String name, dynamic value) => js.setProperty(_object, name, value);
}
Then you can access with
// a is your js object
var jsA = new JsObject(a);
jsA['YOUR_PROPERTY']

Resources