예제 #1
0
        public void DiagnosticUnhandledException([Property] HttpContext httpContext, [Property] Exception exception)
        {
            var span = _tracer.Tracer.GetEntrySpan();

            if (span == null)
            {
                return;
            }
            span.Log(LogField.CreateNew().Event("AspNetCore UnhandledException"));
            span.Exception(exception);
        }
예제 #2
0
 //stops the stream from being saved
 private void StopSaving_Click(object sender, RoutedEventArgs e)
 {
     StreamSavingHeader.IsEnabled     = true;
     StopStreamSavingHeader.IsEnabled = false;
     if (_saveStreamEnabled == true)
     {
         LogField.AppendText(DateTime.Now + ":\tStream will no longer be saved to a file\n");
         LogField.ScrollToEnd();
     }
     _saveStreamEnabled = false;
 }
예제 #3
0
        public void OnException(HttpContext httpContext, Exception exception, string @event)
        {
            var span = httpContext.GetSpan();

            if (span == null)
            {
                return;
            }
            span.Log(LogField.CreateNew().Event(@event));
            span.Exception(exception);
        }
예제 #4
0
 public void Log(LogField logField, string msg)
 {
     if (logField == LogField.web)
     {
         File.AppendAllText(webFileName, msg);
     }
     if (logField == LogField.server)
     {
         File.AppendAllText(serverFileName, msg);
     }
 }
예제 #5
0
 /**
  * Clear the image that was displayed by the stream
  */
 public void clearStreamImage()
 {
     try
     {
         synchronizationContext.Post(o => StreamImage.Source = (ImageSource)o, null);
     }
     catch (Exception e)
     {
         LogField.AppendText($"{DateTime.Now}:\tError clearing stream image: {e}\n");
     }
 }
예제 #6
0
        private void _OnLog(IntPtr ptr1)
        {
            if (OnLog_ == null)
            {
                return;
            }

            LogField obj = PInvokeUtility.GetObjectFromIntPtr <LogField>(ptr1);

            OnLog_(this, ref obj);
        }
예제 #7
0
        /**
         * Method that runs when the main window launches
         */
        public MainWindow()
        {
            InitializeComponent();

            //Setup sync context
            synchronizationContext = SynchronizationContext.Current;

            Title = "Welcome " + Environment.UserName;

            //Adds shortcut to open the registration window with Ctrl + R
            var newKeybind = new RoutedCommand();

            newKeybind.InputGestures.Add(new KeyGesture(Key.R, ModifierKeys.Control));
            CommandBindings.Add(new CommandBinding(newKeybind, Register_Click));

            _controlMode = true;

            _saveStreamEnabled = false;

            //Adds shortut Ctrl + S for stream saving and Ctrl + D for disabling stream saving
            var streamKeybind = new RoutedCommand();

            streamKeybind.InputGestures.Add(new KeyGesture(Key.S, ModifierKeys.Control));
            CommandBindings.Add(new CommandBinding(streamKeybind, ImageSaving_Click));

            var dStreamKeybind = new RoutedCommand();

            dStreamKeybind.InputGestures.Add(new KeyGesture(Key.D, ModifierKeys.Control));
            CommandBindings.Add(new CommandBinding(dStreamKeybind, StopSaving_Click));



            //Checks if a controller is plugged into the current OS
            _controller = new Controller(UserIndex.One);
            if (!_controller.IsConnected)
            {
                LogField.AppendText(DateTime.Now + ":\tNo controller found!\n");
            }
            else
            {
                //Uses a timer to loop a method that checks the status of the controller
                LogField.AppendText(DateTime.Now + ":\tController detected!\n");
                _timer = new DispatcherTimer {
                    Interval = TimeSpan.FromSeconds(1 / 30)
                };
                _timer.Tick += _timer_Tick;
                _timer.Start();
                _directionController = 0.0;
                _throttleController  = 0.0;
            }
            //sets initial connection configuration specified by .ini file
            initializeUI();
        }
예제 #8
0
        private void SetFollowerModelPID_Click(object sender, RoutedEventArgs e)
        {
            var picar = SelectedPiCar();

            if (picar is null)
            {
                return;
            }
            LogField.AppendText(DateTime.Now + ":\tSetting " + picar + "to legacy PID follower model\n");
            LogField.ScrollToEnd();
            picar.SetFollowerModel(1);
        }
예제 #9
0
        //tries to connect to cars specified in .ini file
        private async Task IPConnect(string selectedIP, string selectedName)
        {
            //Handle the dummy connection
            if (selectedIP == "DummyIP")
            {
                var dummyConnection = new DummyConnection(selectedName, selectedIP);
                deviceListMain.Add(dummyConnection);
                LogField.AppendText(DateTime.Now + ":\t" + "Added " + selectedName + " for testing\n");
                //LogFieldReg.AppendText("Added " + selectedName + " for testing\n");
            }

            else if (!CheckIfValidIP(selectedIP))
            {
                //LogFieldReg.AppendText("Invalid IP used, try again!\n");
                LogField.AppendText(DateTime.Now + ":\tInvalid IP used, try again!\n");
            }

            else
            {
                PiCarConnection newConnection = null;
                var             canConnect    = false;
                try
                {
                    newConnection = new PiCarConnection(selectedName, selectedIP);
                    var connectResponse = newConnection.RequestConnect();
                    Console.Write(connectResponse.Item2);
                    //LogFieldReg.AppendText(connectResponse.Item2);
                    LogField.AppendText(DateTime.Now + ":\t" + connectResponse.Item2);
                    canConnect = connectResponse.Item1;
                }
                catch (RpcException rpcE)
                {
                    LogField.AppendText(DateTime.Now + ":\tRPC error: " + rpcE.Message + "\n");
                }
                catch (Exception exception)
                {
                    LogField.AppendText(DateTime.Now + ":\tError! " + exception + "\n");
                }

                if (canConnect)
                {
                    LogField.AppendText(DateTime.Now + ":\t" + "Connected to " + selectedName + " with IP: " + selectedIP + "\n");
                    //LogFieldReg.AppendText("Connected to " + selectedName + " with IP: " + selectedIP + "\n");
                    deviceListMain.Add(newConnection);
                }
                else
                {
                    LogField.AppendText(DateTime.Now + ":\t" + "Failed to connect to " + selectedName + " with IP: " + selectedIP + "\n");
                    //LogFieldReg.AppendText("Failed to connect to " + selectedName + " with IP: " + selectedIP + "\n");
                }
            }
        }
예제 #10
0
        private void DisconnectCar(PiCarConnection picar)
        {
            if (picar.GetType() == typeof(DummyConnection))
            {
                return;
            }

            LogField.AppendText(DateTime.Now + ":\t" + picar + " stopped responding, disconnecting.\n");
            LogField.ScrollToEnd();
            deviceListMain.Remove(picar);
            DeviceListMn.ItemsSource = null;
            DeviceListMn.ItemsSource = deviceListMain;
        }
예제 #11
0
 /**
  * Timer method that calls the method that checks the controller status
  */
 private void _timer_Tick(object sender, EventArgs e)
 {
     try
     {
         ControllerMovement();
     }
     catch (Exception exception)
     {
         Console.WriteLine(exception);
         LogField.AppendText(DateTime.Now + ":\tController disconnected\n");
         _timer.Stop();
     }
 }
예제 #12
0
        //opens up window for user to specify directory they want to save file to
        //and allows them to specify the session prefix name
        private void ImageSaving_Click(object sender, RoutedEventArgs e)
        {
            if (SaveStreamSetup == null)
            {
                SaveStreamSetup = new SaveStreamSetup();
                SaveStreamSetup.Show();
            }
            else if (SaveStreamSetup != null)
            {
                SaveStreamSetup.Focus();
            }

            LogField.ScrollToEnd();
        }
예제 #13
0
        /**
         * Update method which gets called by PiCarConnection when sending image frames and car actions.
         */
        public void HandleStream(byte[] imageBytes, SetMotion action)
        {
            if (imageBytes == null)
            {
                return;
            }

            var  save_dir_path  = getPathName();
            var  session_prefix = getSessionName();
            bool save_to_disk   = getSaveEnabled();

            //Convert bytes to ImageSource type for GUI
            var imgSource = (ImageSource) new ImageSourceConverter().ConvertFrom(imageBytes);

            // Update the GUI
            try
            {
                synchronizationContext.Post(o => StreamImage.Source = (ImageSource)o, imgSource);
            }
            catch (Exception e)
            {
                LogField.AppendText($"{DateTime.Now}: Error updating the GUI with image received from car: {e}\n");
            }

            if (save_to_disk)
            {
                try
                {
                    var csv_path        = $"{save_dir_path}\\{session_prefix}.csv";
                    var image_file_name = $"{session_prefix}_{saved_frame_count.ToString("D5")}.jpg";

                    saved_frame_count += 1;
                    using (var fileStream = new FileStream($"{save_dir_path}\\train\\{image_file_name}", FileMode.Create))
                    {
                        //Console.WriteLine($"Writing image of length {imageBytes.Length}");
                        fileStream.Write(imageBytes, 0, imageBytes.Length);
                        fileStream.Flush();
                    }

                    using (var streamWriter = new StreamWriter(csv_path, true))
                    {
                        streamWriter.WriteLineAsync($"train/{image_file_name},{action.Throttle},{action.Direction}");
                    }
                }
                catch (IOException e)
                {
                    LogField.AppendText($"{DateTime.Now}:\tError writing stream data to disk: {e.Message}\n");
                }
            }
        }
        public void EndRequest([Property] HttpContext httpContext)
        {
            var span = _tracer.Tracer.GetEntrySpan();

            if (span == null)
            {
                return;
            }
            span.Tags.HttpStatusCode(httpContext.Response.StatusCode);

            span.Log(LogField.CreateNew().Event("AspNetCore EndRequest"));
            span.Log(LogField.CreateNew().ServerSend());
            span.Finish();
            _tracer.Tracer.SetEntrySpan(null);
        }
예제 #15
0
 private void SetVehicleMode(PiCarConnection picar, ModeRequest.Types.Mode mode)
 {
     try
     {
         picar.SetMode(mode);
         DeviceStatus.Text = picar.Mode.ToString();
         LogField.AppendText(DateTime.Now + ":\tSetting " + picar + "to " + picar.Mode.ToString() + "\n");
         LogField.ScrollToEnd();
     }
     catch (Exception e)
     {
         DisconnectCar(picar);
         Console.WriteLine(e);
     }
 }
예제 #16
0
        public static ISpan Exception(this ISpan span, Exception exception)
        {
            if (span == null)
            {
                return(span);
            }

            if (exception == null)
            {
                throw new ArgumentNullException(nameof(exception));
            }
            span.ErrorOccurred();
            span.Log(LogField.CreateNew().EventError().ErrorKind(exception).Message(exception.Message).Stack(exception.StackTrace));
            return(span);
        }
예제 #17
0
 public void Log(LogField logField, string msg)
 {
     if (logField == LogField.web)
     {
         webSlackBotClient.Send(FormatMessage(msg));
     }
     if (logField == LogField.server)
     {
         serverSlackBotClient.Send(FormatMessage(msg));
     }
     if (logField == LogField.userArticles)
     {
         userArticlesSlackBotClient.Send(FormatMessage(msg));
     }
 }
예제 #18
0
        public ISpan OnBeginRequest(HttpContext httpContext)
        {
            var spanBuilder = new SpanBuilder($"server {httpContext.Request.Method} {httpContext.Request.Path}");

            if (_tracer.Tracer.TryExtract(out var spanContext, httpContext.Request.Headers, (c, k) => c[k],
                                          c => c.Select(x => new KeyValuePair <string, string>(x.Key, x.Value)).GetEnumerator()))
            {
                spanBuilder.AsChildOf(spanContext);
            }
            var span = _tracer.Start(spanBuilder);

            httpContext.SetSpan(span);
            span.Log(LogField.CreateNew().ServerReceive());
            span.Log(LogField.CreateNew().Event("Microsoft.AspNetCore.Hosting.BeginRequest"));
            _tracer.Tracer.SetCurrentSpan(span);
            return(span);
        }
예제 #19
0
        public void writeStreamCsvHeader()
        {
            var save_dir_path  = getPathName();
            var session_prefix = getSessionName();
            var csv_path       = $"{save_dir_path}\\{session_prefix}.csv";

            if (!File.Exists(csv_path))
            {
                try {
                    using (var streamWriter = new StreamWriter(csv_path, true)) {
                        streamWriter.WriteLineAsync($"image_file,throttle,direction");
                    }
                }
                catch (IOException e) {
                    LogField.AppendText($"{DateTime.Now}:\tError opening csv: {e.Message}\n");
                }
            }
        }
예제 #20
0
 private void ModeChanger_Click(object sender, RoutedEventArgs e)
 {
     if (_controlMode)
     {
         _controlMode                = false;
         DefaultHeader.IsEnabled     = true;
         AlternativeHeader.IsEnabled = false;
         LogField.AppendText(DateTime.Now + ":\tUsing RC control mode\n");
     }
     else
     {
         _controlMode                = true;
         DefaultHeader.IsEnabled     = false;
         AlternativeHeader.IsEnabled = true;
         LogField.AppendText(DateTime.Now + ":\tUsing simulator control mode\n");
     }
     LogField.ScrollToEnd();
 }
예제 #21
0
        public async override Task Invoke(AspectContext context, AspectDelegate next)
        {
            var serviceType = context.ServiceMethod.DeclaringType;

            if (excepts.Any(x => serviceType.Name.Matches(x)) || excepts.Any(x => serviceType.Namespace.Matches(x)) || context.Implementation is IServiceTracer)
            {
                await context.Invoke(next);

                return;
            }
            await ServiceTracer?.ChildTraceAsync(context.ServiceMethod.GetReflector().DisplayName, DateTimeOffset.UtcNow, async span =>
            {
                span.Log(LogField.CreateNew().MethodExecuting());
                span.Tags.Set("ServiceType", context.ServiceMethod.DeclaringType.GetReflector().FullDisplayName);
                span.Tags.Set("ImplementationType", context.ImplementationMethod.DeclaringType.GetReflector().FullDisplayName);
                await context.Invoke(next);
                span.Log(LogField.CreateNew().MethodExecuted());
            });
        }
예제 #22
0
        /**
         * Method that handles when one or more key is pressed down (Vehicle is moving in one or more directions)
         */
        private void Key_down(object sender, KeyEventArgs e)
        {
            //var picar = (PiCarConnection)DeviceListMn.SelectedItem;
            //if (picar == null || picar.Mode != ModeRequest.Types.Mode.Lead) return;
            if (e.IsRepeat)
            {
                return;
            }

            var directionMotor = 0.0;
            var throttleMotor  = 0.0;

            string[] throttleStrings  = { "Moving backwards", "In Neutral", "Moving forwards" };
            string[] directionStrings = { "and left", "", "and right" };


            if (Keyboard.IsKeyDown(Key.W) || Keyboard.IsKeyDown(Key.Up))
            {
                throttleMotor++;
            }

            if (Keyboard.IsKeyDown(Key.S) || Keyboard.IsKeyDown(Key.Down))
            {
                throttleMotor--;
            }

            if (Keyboard.IsKeyDown(Key.A) || Keyboard.IsKeyDown(Key.Left))
            {
                directionMotor--;
            }

            if (Keyboard.IsKeyDown(Key.D) || Keyboard.IsKeyDown(Key.Right))
            {
                directionMotor++;
            }

            string output = Direction.EncodeDirection(DateTime.Now, throttleMotor, directionMotor);

            LogField.AppendText(output);
            MoveVehicle(throttleMotor, directionMotor);
            LogField.ScrollToEnd();
        }
        void ReleaseDesignerOutlets()
        {
            if (SearchLevelSelector != null)
            {
                SearchLevelSelector.Dispose();
                SearchLevelSelector = null;
            }

            if (TargetImageView != null)
            {
                TargetImageView.Dispose();
                TargetImageView = null;
            }

            if (LogField != null)
            {
                LogField.Dispose();
                LogField = null;
            }
        }
예제 #24
0
        protected virtual async Task <HttpResponseMessage> TracingSendAsync(
            OpenTracing.ISpan span,
            HttpRequestMessage request,
            CancellationToken cancellationToken,
            Action <string> addTraceIdToRepo,
            Func <HttpRequestMessage, CancellationToken, Task <HttpResponseMessage> > baseSendAsync)
        {
            if (request.Headers.Contains(PrefixSpanId))
            {
                request.Headers.Remove(PrefixSpanId);
                request.Headers.TryAddWithoutValidation(PrefixSpanId, span.Context.SpanId);
            }

            addTraceIdToRepo(span.Context.TraceId);

            span.SetTag(Tags.SpanKind, Tags.SpanKindClient)
            .SetTag(Tags.HttpMethod, request.Method.Method)
            .SetTag(Tags.HttpUrl, request.RequestUri.ToString())
            //.SetTag(Tags.Host(request.RequestUri.Host)
            //.HttpPath(request.RequestUri.PathAndQuery)
            //.SetTag(Tags.PeerHostname(request.RequestUri.OriginalString)
            .SetTag(Tags.PeerHostname, request.RequestUri.Host)
            .SetTag(Tags.PeerPort, request.RequestUri.Port)
            ;

            var dictionary = new Dictionary <string, string>();

            _tracer.Inject(span.Context, BuiltinFormats.HttpHeaders, new TextMapInjectAdapter(dictionary));
            foreach (var entry in dictionary)
            {
                request.Headers.Add(entry.Key, entry.Value);
            }

            span.Log(LogField.CreateNew().ClientSend());

            var responseMessage = await baseSendAsync(request, cancellationToken);

            span.Log(LogField.CreateNew().ClientReceive());

            return(responseMessage);
        }
예제 #25
0
        protected virtual async Task <HttpResponseMessage> TracingSendAsync(ISpan span, HttpRequestMessage request, CancellationToken cancellationToken)
        {
            span.Tags.Client().Component("HttpClient")
            .HttpMethod(request.Method.Method)
            .HttpUrl(request.RequestUri.OriginalString)
            .HttpHost(request.RequestUri.Host)
            .HttpPath(request.RequestUri.PathAndQuery)
            .PeerAddress(request.RequestUri.OriginalString)
            .PeerHostName(request.RequestUri.Host)
            .PeerPort(request.RequestUri.Port);

            _tracer.Tracer.Inject(span.SpanContext, request.Headers, (c, k, v) => c.Add(k, v));

            span.Log(LogField.CreateNew().ClientSend());

            var responseMessage = await base.SendAsync(request, cancellationToken);

            span.Log(LogField.CreateNew().ClientReceive());

            return(responseMessage);
        }
예제 #26
0
        protected virtual async Task <HttpResponseMessage> TracingSendAsync(
            ISpan span,
            HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            IEnumerable <string> traceIdVals = null;

            if (request.Headers.TryGetValues(prefix_spanId, out traceIdVals))
            {
                request.Headers.Remove(prefix_spanId);
                request.Headers.TryAddWithoutValidation(prefix_spanId, span.SpanContext.SpanId);
            }

            _repo.Add("TraceId", span.SpanContext.TraceId);

            span.Tags.Client().Component("HttpClient")
            .HttpMethod(request.Method.Method)
            .HttpUrl(request.RequestUri.OriginalString)
            .HttpHost(request.RequestUri.Host)
            .HttpPath(request.RequestUri.PathAndQuery)
            .PeerAddress(request.RequestUri.OriginalString)
            .PeerHostName(request.RequestUri.Host)
            .PeerPort(request.RequestUri.Port);

            _tracer.Tracer.Inject(span.SpanContext, request.Headers, (c, k, v) =>
            {
                if (!c.Contains(k))
                {
                    c.Add(k, v);
                }
            });

            span.Log(LogField.CreateNew().ClientSend());

            var responseMessage = await base.SendAsync(request, cancellationToken);

            span.Log(LogField.CreateNew().ClientReceive());

            return(responseMessage);
        }
예제 #27
0
        protected virtual async Task <HttpResponseMessage> TracingSendAsync(
            ISpan span,
            HttpRequestMessage request,
            CancellationToken cancellationToken,
            Action <string> addTraceIdToRepo,
            Func <HttpRequestMessage, CancellationToken, Task <HttpResponseMessage> > baseSendAsync)
        {
            if (request.Headers.Contains(PrefixSpanId))
            {
                request.Headers.Remove(PrefixSpanId);
                request.Headers.TryAddWithoutValidation(PrefixSpanId, span.SpanContext.SpanId);
            }

            addTraceIdToRepo(span.SpanContext.TraceId);

            span.Tags.Client().Component("HttpClient")
            .HttpMethod(request.Method.Method)
            .HttpUrl(request.RequestUri.OriginalString)
            .HttpHost(request.RequestUri.Host)
            .HttpPath(request.RequestUri.PathAndQuery)
            .PeerAddress(request.RequestUri.OriginalString)
            .PeerHostName(request.RequestUri.Host)
            .PeerPort(request.RequestUri.Port);

            _tracer.Tracer.Inject(span.SpanContext, request.Headers, (c, k, v) =>
            {
                if (!c.Contains(k))
                {
                    c.Add(k, v);
                }
            });

            span.Log(LogField.CreateNew().ClientSend());

            var responseMessage = await baseSendAsync(request, cancellationToken);

            span.Log(LogField.CreateNew().ClientReceive());

            return(responseMessage);
        }
예제 #28
0
        public void HttpRequest([Property(Name = "Request")] HttpRequestMessage request)
        {
            var patterns = _options.IgnoredRoutesRegexPatterns;

            if (patterns == null || patterns.Any(x => Regex.IsMatch(request.RequestUri.AbsolutePath, x)))
            {
                return;
            }
            var spanBuilder = new SpanBuilder($"httpclient {request.Method} {request.RequestUri.AbsolutePath}");
            var spanContext = _tracer.Tracer.GetEntrySpan()?.SpanContext;

            if (spanContext != null)
            {
                spanBuilder.AsChildOf(spanContext);
            }
            var span = _tracer.Start(spanBuilder);

            span.Tags.Client().Component("HttpClient")
            .HttpMethod(request.Method.Method)
            .HttpUrl(request.RequestUri.OriginalString)
            .HttpHost(request.RequestUri.Host)
            .HttpPath(request.RequestUri.PathAndQuery)
            .PeerAddress(request.RequestUri.OriginalString)
            .PeerHostName(request.RequestUri.Host)
            .PeerPort(request.RequestUri.Port);

            _tracer.Tracer.Inject(span.SpanContext, request.Headers, (c, k, v) => c.Add(k, v));
            span.Log(LogField.CreateNew().ClientSend());
            if (request.Method == HttpMethod.Post && _options.TraceHttpContent && request.Content != null)
            {
                var result = request.Content.ReadAsStringAsync().Result;
                if (!string.IsNullOrWhiteSpace(result))
                {
                    span.Tags.Add("http.request", _tbbrRegex.Replace(result, ""));
                }
            }

            _tracer.Tracer.SetExitSpan(span);
        }
        public void EndRequest([Property] HttpContext httpContext)
        {
            var httpRequestSpan = ContextManager.ActiveSpan;

            if (httpRequestSpan == null)
            {
                return;
            }

            var statusCode = httpContext.Response.StatusCode;

            if (statusCode >= 400)
            {
                httpRequestSpan.ErrorOccurred();
            }

            httpRequestSpan.Tags.HttpStatusCode(statusCode);

            httpRequestSpan.Log(LogField.CreateNew().Event("AspNetCore Hosting EndRequest")
                                .Message($"Request finished {httpContext.Response.StatusCode} {httpContext.Response.ContentType}"));

            ContextManager.StopSpan(httpRequestSpan);
        }
예제 #30
0
        public void OnEndRequest(HttpContext httpContext)
        {
            var span = httpContext.GetSpan();

            if (span == null)
            {
                return;
            }

            span.Tags
            .Server().Component("AspNetCore")
            .HttpMethod(httpContext.Request.Method)
            .HttpUrl($"{httpContext.Request.Scheme}://{httpContext.Request.Host.ToUriComponent()}{httpContext.Request.Path}{httpContext.Request.QueryString}")
            .HttpHost(httpContext.Request.Host.ToUriComponent())
            .HttpPath(httpContext.Request.Path)
            .HttpStatusCode(httpContext.Response.StatusCode)
            .PeerAddress(httpContext.Connection.RemoteIpAddress.ToString())
            .PeerPort(httpContext.Connection.RemotePort);
            span.Log(LogField.CreateNew().Event("Microsoft.AspNetCore.Hosting.EndRequest"));
            span.Log(LogField.CreateNew().ServerSend());
            span.Finish();
            _tracer.Tracer.SetCurrentSpan(null);
        }
예제 #31
0
 private void OnLog_callback(object sender, ref LogField log)
 {
     if (null != OnLog)
     {
         OnLog(this, new OnLogEventArgs(ref log));
     }
 }
예제 #32
0
 public OnLogEventArgs(ref LogField log)
 {
     this.log = log;
 }