I have built a python library that uses C# code(which is built and stored as a dll), using pythonnet. In that library, I generate logs using the python logger.
mylibrary.py
logger = logging.getLogger('mylibrary')
logger.info('logging from my library')
The root logger is configured from the user code. For example, the handlers for the root logger is set by the user using logger's "addhandler()" method specifying the format, output file etc. Inside my library, I just log (logger.info()...) without configuring anything and the root handler set by the user takes care of writing this to the file.
usercode.py
root_logger = getLogger()
root_logger.addHandler(FileHandler('abc.log'))
root_handler.setFormat(...)
The user can control what my library can log by setting the level of the logger used by my library. The line below in usercode.py sets the logging level of my library's logger to critical so that the library can't log anything below it (logger.info() won't get into abc.log).
getLogger('mylibrary').setLevel(CRITICAL)
The problem comes now. Since I am using C# code in my library,
I want to capture the C# logs into abc.log
I also want to configure the C# log just like I did for python logs
So the the line
getLogger('mylibrary').setLevel(CRITICAL)
in usercode.py should now make sure that only the critical logs in both the python as well as C# get into abc.log
Is there a way to achieve this?
No, you cannot log from both Python and C# at the same time to the same file. The reason for this is that Python's logging (and likely the C# logging too) is not equipped for concurrent logging - even if the log file is not 'locked' by one of them, there is a chance of getting different logs mixed together due to multiple writers.
If you do not own the C# dll you're probably out of luck - unless it would allow you to configure the log file/level from a C# program, there is no magic that Python can do to fix it. However, if you control the source and can build a new dll, consider changing the C# class to allow you to pass in a delegate/lambda (assuming this is implemented in PythonNet), which will simply call back into Python's logger function.
Example:
c# code:
public class CoolImportedFeature
{
private readonly Action<string> LogCallback;
public CoolImportedFeature(string inputA, int inputB, Action<string, string> logCallback)
{
LogCallback = logCallback;
// do other constructor stuff
}
public void SomeMethod()
{
// do something
LogCallback("critical", "An error occurred");
}
}
python code:
def log_callback(log_level, message):
getattr(logger, log_level)(message)
import CoolImportedFeature
feat = CoolImportedFeature("hello", 1, log_callback)
feat.SomeMethod()
Something like that - there is no magic translation between Python's log levels and C#'s, so you will need to do some translation there (or the getattr reflection I used above).
Related
I'm making an app and need to be able to check if settings like : Bluetooth/Phone Rotation/Flashlight/Plane Mode/GPS/Phone Brightness/Silent Mode, are activated on an android phone.
I haven't found any way to do it within Unity, using C#. I found ways to do it using Xamarin but none of them work with Unity (or maybe I haven't done it right), the only way I found is using Java and making it into a plugin and call it in a C# script. But I can't find a clear way to make this work. If this is the only solution could you please explain how to do it, all the documentation I find is from old versions from 2014.
I think there is a simple solution for this but I simply can't find it. And the manifest part is not a problem, I'll add the permissions needed.
In Java the methods you want to call should be public or static, you must build your java source as a library (in build.gradle: apply plugin: 'com.android.library'), and add the .aar to Unity's Assets/Plugins/Android/ folder.
Then you can instantiate your plugin in Unity like so:
// this class string is the package at the top of your Java class extended with the class name, e.g.:
// package com.yourcompany.you.package;
string classString = "com.yourcompany.you.package.className";
// Get the class
var tempAjc = new AndroidJavaClass(classString);
// Here you can call a static method on the class that returns an instance of the class if you want to pass some parameters upon creation
_androidObject = tempAjc.CallStatic<AndroidJavaObject>("CreateInstance",
new object[] {arg1, arg2});
// non static call on your new instance
_androidObject.Call("PassingMoreStuff", initParam);
// if you want to return something from Java to Unity:
int javaVal = _androidObject.Call<int>(methodName, parameters);
I know it is possible to call C# code from the PowerShell script by loading an assembly. But is there any way to pass and receive a value in between both C# code and PowerShell script.
Let's say I have a $path variable in my power script. I want to pass it to my c# code. And C# code will use the $path. After doing some stuff in the c# code it will return some value to the script. Is this possible? If it is, how can I do it? I must load a third party dll in my power shell and all one or two public methods on that dll to complete some task.
My PowerShell script code:
$scriptpath = $MyInvocation.MyCommand.Path;
$cureentDir = Split-Path $scriptpath;
$isSasDir = $cureentDir -match "mydir";
$requiredFile = "Core.dll";
$myPowersehllVal = "has value for c# code";
My C# code:
$Source = #"
using System.Net;
public class ExtendedWebClient : WebClient
{
String myPowersehllVal;
public int Timeout;
protected override WebRequest GetWebRequest(System.Uri address)
{
}
}
"#;
For getting PS values into C#
https://stackoverflow.com/a/22384009/3546415
In a more general sense, System.Management.Automation (Nuget Required) looks promising, in particular, Runspace and Pipeline.
Here are some good examples of usage:
https://msdn.microsoft.com/en-us/library/ee706576(v=vs.85).aspx
Something like this one seems similar to what you want.
Or maybe just use the PowerShell Class to execute PS commands from your C# module to set PS variable values.
Alternatively, without worrying about interop, you can kind of hack this by working through the file system and/or environmental variables. Following this paradigm, you could even use a memory mapped file and share variables with a broader set of applications. Powershell side would be something like this. For objects, serialization.
I'm just having a play with Roslyn but unsure on how to do the following.
To keep this simple, lets say I have a host program which has a method like so
public void DisplayMessage(string message)
{
MessageBox.Show(message);
}
Can I then have a script file called MyScript.csx and then somewhere in the script have something like
void Main()
{
Host.DisplayMessage("I am a script");
}
Then I have the host load the file and execute it.
If this sort of thing can't be done, is there a scripting system/engine based on c# that can do it?
These are the requirements
Host application can load script from a file.
Script file is written in c# and so can be written using VS2010 with syntax etc
Script file can access host public methods, properties etc
I wrote an Introduction to the Roslyn scripting API that covers most of what you're asking. The ScriptEngine type also has a ExecuteFile method that would be useful for what you're trying to do.
Disclaimer: I work for Microsoft on the Roslyn project.
Yes, you can do what you want using Roslyn.
First, create a public Host class that has a public DisplayMessage method (or use a existing class). Then create ScriptEngine, specifying the assembly that contains Host as a reference. After that, you can call ExecuteFile() on your file, with the Host object as another parameter:
var engine = new ScriptEngine(references: new[] { typeof(Host).Assembly });
engine.ExecuteFile("MyScript.csx", new Host());
The script files doesn't need any Main() method, and you call the method on the host object directly:
DisplayMessage("I am a script");
I have a class in c# to help me log errors (ErrorClass).
The class has 3 methods. Log Error to: File System, Windows Event,
Email.
2 of the 3 methods require settings like "to email", or "directory path".
Settings are stored in the registry
I use dependency injection to instantiate the RegistryClass inside the ErrorClass
.
This is how I instantiate the ErrorHandle Class inside the Registry Class
ErrorHandle _ErrorHandle = new ErrorHandle();
And here is how I instantiate the Registry Class inside the ErrorHandle Class
RegistryTools _GetRegistry = new RegistryTools();
I have a class to help me retrieve values from the registry (RegistryClass)
The registry class needs to handle errors
I use dependency injection to instantiate the errorClass inside the RegistryClass
When I use dependency injection in both classes, an Endless LOOP is created when there is an error.
What is the suggested way or best practice of handling this situation:
Should I access the registry inside the ErrorClass?
Should I not ErrorHandle the RegistryClass?
Should I create a separate ErroHandle procedure for the
RegistryClass?
Don't re-invent this wheel. There is a tried and tested open source logging framework for .NET available, log4net. If you feel the need to use DI with it, you can do that too. log4net uses an XML file for configuration, which is much more accessible and less fraught with peril than dealing with the registry. It also swallows its own errors and makes them accessible via a debugging trace.
What mechanism are you using for DI? If you use setter injection there should be nothing to stop you doing something like:
var logger = new ErrorClass();
var registry = new RegistryClass();
logger.Registry = registry;
registry.Logger = logger;
I was recently studying documentation on TraceSource. Microsift says that TraceSource is a new way and should be used instead of old Trace class.
// create single TraceSource instance to be used for logging
static TraceSource ts = new TraceSource("TraceTest");
// somewhere in the code
ts.TraceEvent(TraceEventType.Warning, 2, "File Test not found");
Now my question. You have large project with several assemblies where you have lots of classes. Say you wanna trace specific bit of functionality that is spread across classes. Obvious idea is that you need to create one specific TraceSource .
1) To work with Tracesource I need to create instance first. What is MS thinking about sharing this instance across various classes or assemblies? Should I create one dummy class with static singleton property? What are you doing in that case.
2) Why do I need TraceSource instance? Every propery is described in the configuration file. The old logic based on Trace class did not require some instance and provided the way to work with static methods only.
*1. Just define the TraceSource in each class where you want to use it. You can make the TraceSource static so that it shared among all instances of the class you define it in. No need to share the instance among all classes (types) that need the "same" TraceSource. Each time you decleare a new TraceSource (TraceSource ts = new TraceSource("somename"); instance, you get a new TraceSource object, but it references the same config information. So, if you create a new TraceSource in each of several classes and you use the same name for each one, you will get different instances of TraceSource, but they will all be configured the same. In short, there is no need to try to share the TraceSource instances among classes. There is also no need to create a dummy class with a static singleton. See my examples below. I have also included several more links from here on SO that describe how to work with TraceSources.
//
// In this example, tracing in classes A and B is controlled by the "TraceTest" TraceSource
// in the app.config file. Tracing in class C is controlled by the "TraceTestTwo"
// TraceSource in the app.config.
//
// In addition to using different TraceSource names, you can also use SourceSwitches
// (in the app.config). See some examples of app.config in the
// "turning-tracing-off-via-app-config" link below.
//
public class A
{
private static readonly TraceSource ts = new TraceSource("TraceTest");
public void DoSomething()
{
ts.TraceEvent(TraceEventType.Warning, 2, "File Test not found");
}
}
public class B
{
//
//Use the same config info for TraceTest in this class
//It's ok to use a different instance of TraceSource, but with the same name,
//in this class, the new instance will be configured based on the params in the
//app.config file.
//
private static readonly TraceSource ts = new TraceSource("TraceTest");
public void DoSomething()
{
ts.TraceEvent(TraceEventType.Warning, 2, "File Test not found");
}
}
public class C
{
//
//Use a different TraceSource in this class.
//
private static readonly TraceSource ts = new TraceSource("TraceTestTwo");
public void DoSomething()
{
ts.TraceEvent(TraceEventType.Warning, 2, "File Test not found");
}
}
*2. One benefit to using multiple TraceSources is that you have more granular control over your tracing. You can trace via "TraceTest" at one level (or not at all) and via "TraceTestTwo" at a different level (or, again, not at all). You can send each TraceSource to its own TraceListener or send all to the same TraceListener, or mix and match. Compare the ability to tailor the configuration of individual TraceSources to the limitation of only using the static methods on the Trace class. You can configure where the "trace" information goes (which TraceListener(s)) or the level of the "trace" information, but you cannot control the level per class or per functional area like you can when using TraceSources. Finally, one more benefit to multiple TraceSources is the "free" context information that you can get in your output. By default (or optionally, I can't remember), the TraceListener will log the name of the TraceSource that logged a message. So, you can look at that line in your output and get some idea of the class or functional area where it came from without having to put a log of contextual information in the call site. In the code examples above, the trace output from classes A and B will be tagged with "TraceTest" and the trace output from class B will be tagged with "TraceTestTwo".
Please forgive the link bombardment below, but I have posted some pretty good information (if I do say so myself!) about TraceSource and System.Diagnostics in the past.
If you are going to use TraceSource, consider using the library mentioned in this SO post for formatting your output like log4net/NLog:
Does the .Net TraceSource/TraceListener framework have something similar to log4net's Formatters?
See my answer in this post for more info on using TraceSource and some ideas on how you can improve your "TraceSource experience".
More info on TraceSource: Add Trace methods to System.Diagnostics.TraceListener
More info on TraceSource: System.Diagnostics.Debug namespace vs Other logging solutions (log4net, MS Enterprise Library, etc.)
More info on TraceSource: Turning tracing off via app.config