add spacing parameter to Column and Row

Wrap has two  wonderful parameters runSpacing for vertical spacing and spacing for horizontal spacing. I'd like to see a spacing parameter on both Column and Row.

Hi @lukepighetti
Does this workaround suit to you https://github.com/flutter/flutter/issues/16957#issuecomment-558878770?
Do you have some case where it's not applicable?

This is how we currently doing it, I'm asking to unify the spacing API across Wrap, Column, Row. This isn't a question of if there is another solution, it's a question of providing more unified "color" to the commonly used layout APIs.

Inspired in other solutions & workarounds I've published this gist that adds support for this FR: https://gist.github.com/henry2man/28595050f09633e16641d5f30f1a32ae

@Hixie
This is the same issue as https://github.com/flutter/flutter/issues/16957, which was closed by you.
There is a lot of interest in getting this feature implemented. I'm wondering if this is still current consensus before i attempt to fix this issue.
cc: @Piinks

+1 to this issue.
I use a list extension today and it works but it's not great because:
A. I have to write the list extension, there's no built in
This is especially painful for standardization across projects and for new Flutter devs who won't quickly discover the extension approach-everyone is reinventing the wheel.
B. I find having the method call on the end of a list, while semantically sane, feels a little out of place in Flutter code and hard to parse.
C. It's inconsistent with Wrap which does provide spacing attributes
Another thing to consider is the ListView.separated approach which has the advantage of allowing any widget-not just a space-to be injected, but that feels a bit overkill in the Row/Column case.

I think one of the main reasons we have not done this (and closed the other issue) is because we have the Padding widget.
If we add padding as a property to Column and Row, what about all the other widgets we could add padding to? Should we add padding to all of them? If we don't, what is the clear path for the user - some widgets have padding... others don't.. there's also the Padding widget... When should folks use the widget or the property? Often having more than one way to do something increases cognitive load for users, and makes the decision path in development harder.
Adding padding to every widget also increases the API surface, which is unnecessary when folks can just use Padding when they want it.
This is just some context I could recall from the original issue. I don't know if this is something we should or should not do, I do think re-evaluating past decisions is always ok to do. 👍
Wrap is a special case since it positions items in more that one axis as compared to row and column, and is difficult to affect the padding when the layout can be so different based on the constraints.

Wrap is a special case since it positions items in more that one axis as compared to row and column, and is difficult to affect the padding when the layout can be so different based on the constraints.

I just made of rough implementation in https://github.com/flutter/flutter/issues/55378#issuecomment-2250001798. Yes, the spacing or padding cannot be applied in every main axis configuration. For example, spaceBetween or spaceEvenly configuration doesn't make sense for custom spacing. In such cases custom spacing should be ignored.  For case it make sense would start, center, end  where currently you find workaround to provide spacing between items in a Row and Column.

I think one of the main reasons we have not done this (and closed the other issue) is because we have the Padding widget.

If you want to add spacing by adding a padding around the children, you...

need to use indices to prevent spacing before the first and the last item
need to divide your desired padding by 2 if you want to apply it evenly
can't easily switch the direction with a single line / property change
theoretically add more overhead by increasing the number of widgets (vs the spacing being resolved directly in the layout of the Flex)
constantly recreate your children list if you want to animate the spacing

I think these alone are compelling reasons, but there is also a semantic difference between a gap/spacing that belongs to the column/row and a padding that belongs to an element.
even if it boils down to the exact same drawing instructions, it's still a difference in how we think about things.

If we add padding as a property to Column and Row, what about all the other widgets we could add padding to?

There are already quite a few Widgets in Flutter that have these conveniences or superflous arguments built in, such as the padding parameter on ListView[^2]. So it's a bit weird to shoot down this proposal where there are actually people asking for it vs all the other instances where it went through design and code review and was ok.
The root issue with composition is actually that nesting things is very annoying and people are to lazy to do it. So in lieu of an extensions / Jetpack Compose / SwiftUI type API, they're advocating for adding these parameters into their most used Widgets.

Often having more than one way to do something increases cognitive load for users, and makes the decision path in development harder.

That this is being discussed for the 3rd time in 4 years indicates that whatever mental load might be saved by the conceptual elegance of composition is clearly being squandered in Github issue discussions.
[^2]: What's the problem? Just wrap the first and the last child in a padding!

I'm going to close this as a duplicate of https://github.com/flutter/flutter/issues/16957, where the reasons for not adding this to Row and Column are discussed in detail, as are numerous alternatives for people who are running into this.

I'm going to close this as a duplicate of https://github.com/flutter/flutter/issues/16957, where the reasons for not adding this to Row and Column are discussed in detail, as are numerous alternatives for people who are running into this.

Pretty much every single bigger Flutter project has the solution suggested in there added as an extension which shows how this really is something missing from Flutter (see discussion at https://x.com/spydon/status/1816110827453493618?t=XQrdoi0N880cf9kpxAOc7A&s=19).
I can't think of a single thing in Flutter that is copy-pasted in different versions more than that extension.
It would greatly improve developer experience and make it easier for beginners to start using Row and Column, so now 6 years later when we have this data, I think that it is time to reconsider.
Developer experience must be worth something.

Wrap is a special case since it positions items in more that one axis as compared to row and column, and is difficult to affect the padding when the layout can be so different based on the constraints.

I just made of rough implementation in https://github.com/flutter/flutter/issues/55378#issuecomment-2250001798. Yes, the spacing or padding cannot be applied in every main axis configuration. For example, spaceBetween or spaceEvenly configuration doesn't make sense for custom spacing. In such cases custom spacing should be ignored.  For case it make sense would be start, center, end  where currently you've to find a workaround to provide spacing between items in a Row and Column.

Actually there is a point for not ignoring the spacing for space between etc - to set the minimum main axis size and "force spacing" for tight constraints.

Using the separatedBy extension of the awesome_flutter_extensions package in every single project.
Column(
    children: [
        FirstWidget(),
        SecondWidget()
        ThirdWidget(),
    ].separatedBy(SizedBox(height: 8)),
),

https://pub.dev/packages/awesome_flutter_extensions#miscellaneous

I'm going to close this as a duplicate of https://github.com/flutter/flutter/issues/16957, where the reasons for not adding this to Row and Column are discussed in detail, as are numerous alternatives for people who are running into this.

people were starting to coalesce around this as an exciting new change that has obvious dx benefits. i stand firmly opposed to closing this issue.
dx is about people and flutter/flutter should care about people.

We are making something that's very easy in pretty much all UI frameworks to exist needlessly complicated for questionable gains.
It's hard to understand why having this property is not a problem for all the following frameworks, most of which have similar composability to Flutter:

web/CSS: https://developer.mozilla.org/en-US/docs/Web/CSS/gap
SwiftUI: https://developer.apple.com/documentation/swiftui/vstack
Jetpack Compose: https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/Arrangement.HorizontalOrVertical
Figma AutoLayout: https://help.figma.com/hc/en-us/articles/360040451373-Explore-auto-layout-properties#h_01HB9Q13716VY5NF7AC5XHK9KD
React Native CSS: https://reactnative.dev/docs/flexbox#row-gap-column-gap-and-gap
QtQuick/QML: https://doc.qt.io/qt-6/qml-qtquick-column.html
Slint: https://releases.slint.dev/1.1.0/docs/slint/src/concepts/layouting#common-properties-on-layout-elements
Kivy: https://kivy.org/doc/stable/api-kivy.uix.stacklayout.html#module-kivy.uix.stacklayout
MAUI: https://learn.microsoft.com/en-us/dotnet/api/microsoft.maui.controls.verticalstacklayout?view=net-maui-8.0
Swing/AWT: https://docs.oracle.com/javase/8/docs/api/java/awt/FlowLayout.html
Godot Control Nodes: https://docs.godotengine.org/en/stable/classes/class_itemlist.html#class-itemlist-theme-constant-v-separation
Unreal Engine Slate: https://dev.epicgames.com/documentation/en-us/unreal-engine/slate-overview-for-unreal-engine
Unity UGUI<EMAIL_ADDRESS>Delphi: https://docwiki.embarcadero.com/Libraries/Athens/en/FMX.Layouts.TFlowLayout.VerticalGap

Of the frameworks I checked TKinter was the only one that doesn't have a spacing parameter on their Column/Flow primitive.

I'm going to close this as a duplicate of https://github.com/flutter/flutter/issues/16957, where the reasons for not adding this to Row and Column are discussed in detail, as are numerous alternatives for people who are running into this.

what is needed in order to get the green light on a spacing property on column/row?

is it a piece of information?
is it some form of political capital?
is it a community poll?
is it a number of likes on this issue?
is it a list of other frameworks that have this feature?
do i have to get a tattoo of your face on my lower back?

If we find the RenderObject behind Row and Column too complex for adding this feature, why not doing it at the widget level?
For example we could add this constructor to Row (and Column) (or we could also do it in Flex).
Row.separated({
  super.key,
  super.mainAxisAlignment,
  super.mainAxisSize,
  super.crossAxisAlignment,
  super.textDirection,
  super.verticalDirection,
  super.textBaseline, // NO DEFAULT: we don't know what the text's baseline should be
  List<Widget> children = const [],
  required double spacing,
}) : super(
        direction: Axis.horizontal,
        children: children
            .expand((item) sync* {
              yield SizedBox(height: spacing);
              yield item;
            })
            .skip(1)
            .toList(),
      );

One of the drawback it's that we would loose the const operator on this constructor.
Another idea would be to inherit from StatelessWidget instead of Flex and doing the logic inside the build method. By doing this we could have a const constructor, but maybe it's breaking (since it does not extend from Flex anymore) and for every Column/Row we would have two widgets (Column/Row + Flex) in the widget tree.
I didn't read all the comments for the other issues, so I'm sorry if this idea has already been provided.

I am reopening this issue to discuss further.
There are a couple of ideas here for solutions, including an EdgeInsets padding parameter for Row/Column, adding a double value just for spacing in the main axis, and/or a .separated constructor (this seems cool IMO since it could be more than just padding).
@TahaTesser would you still like to propose a solution for feedback?
Also, just a friendly reminder for everyone here of our code of conduct. As we continue the discussion, let's collaborate with courtesy for everyone. 💙

Thanks @Piinks! I'll take a close look at each suggested approach and their implications and get back with the results for feedback. Then we can proceed further.

Relevant note for a Flex.separated approach and/or for people using the list extension today:
It's annoying to have to keep the sized box width/height synced with the axis of the parent flex (width for row, height for column).
There's two good packages for injecting axis aligned gaps in flex widgets:
https://pub.dev/packages/gap
flutter_gutter (same as gap, but uses material breakpoints system torn default gap sizes)
^disclaimer I'm the author of the second package
While I generally like the .separated approach for it's flexibility, it is slightly annoying given that you have to pick between tedium or finding and using a package. All the same, my 2 cents is that it's the best package as it's then only one that obviates the need for the separated list extension in all cases

Once we add something to Row/Column we can't go back. This means that each thing we add increases the complexity of the framework and eventually the framework isn't simple any more. Row and Column in particular are already quite complicated and adding more features to them is both counter to our philosophy of keeping separate features in separate widgets, and likely to introduce bugs.
There were a bunch of suggestions in https://github.com/flutter/flutter/issues/16957 for how we could approach this without growing Row and Columns, for example:

we could create a stateless widget that wraps Row or Column to provide the padding without complicating the existing widgets, similar to how Container wraps a bunch of existing widgets.
we could create a new package that forks Row and Column to provide all the features people want without having to add those features to the core framework.
we could provide helper functions that would work with Row, Column, and any number of other widgets to map a list of widgets to a list of spaced widgets.

All of these seem pretty reasonable to me and are all in the spirit of the framework and consistent with what made the framework approachable and easy. The specific request in this issue, adding features to Row and Column specifically, is the opposite of that.

I believe that there are two sides to this which might not be mutually exclusive:
On the one side we have people developing apps who want to have an easy to use system which compares well to other frameworks (as described above almost all others have this spacing in their row/column primitives)
On the other side we have the framework team which for good reason try to keep the framework as simple as possible.
Looking at the proposed solutions, it seems possible to keep the internal implementation of flex and just add a widget/constructor. Or since flex is the primitive, it could be something that is added as a wrapper/layer between row/column and flex. So if someone needs the base primitive then it is still available.
And with the composition it should still be fairly lightweight

All of these seem pretty reasonable to me and are all in the spirit of the framework and consistent with what made the framework approachable and easy.

It is something that every flutter dev struggles with in the beginning, so saying that this makes it more approachable and easy is just not true, because all of these solutions already exist as separate packages.
What we want here is to make the framework behave like one would expect, as can be seen in the list above where pretty much every other framework implements this.

I have a decent implementation for Row/Column with gap property, it is probably like 10 LOC diff and you don't add hundreds of empty SizedBox in the project. If anyone want, I can share the code (but requires using my Row2 class).
But I agree it that Flutter makes it extremely hard to make extremely common things such as this that everybody wants and expects. I think not having gap makes the code worse, harder to maintain, harder to read and harder to use.

I tend to agree with @Hixie in this one, as not only we want to space children, but many times I want to avoid spacing the first or the last widget, which will add more complexity indeed.
But I must also say that having the arguments for how to distribute children around the empty space, and not having the spacing, does seem like an incomplete API.
Maybe we can have an iterable that we can use to wrap the children, and use that iterable to configure how we want the children to be spaced. This could live inside the framework, it will keep a declarative API, and still won't disturb the Flex widget code.
Here's an example of what I have in mind:
Column(
  children: Spaced(
    space: 16,
    skipFirst: true,
    children: myWidgets,
  ),
),

This is just an example, maybe a padding would be better, or worse, since the added complexity might not be necessary. Maybe we can have both? Again, this is just an example and food for thought. But I like how this decouples the spacing from the Row/Column code and still keeps a declarative API, and we won't need to add another package from a third party into our apps, in order to use it.

I tend to agree with @Hixie in this one, as not only we want to space children, but many times I want to avoid spacing the first or the last widget, which will add more complexity indeed.

all of the existing flex spacing apis im aware of only affect the space between items. as other spacing is handled by padding or margin.
any suggestion that such a spacing parameter should lead the first widget or trail the last widget is unusual and not recommended

I guess it's fair to leave the leading and trailing spacing out, as leading many times won't match the spacing from the list, but the trailing I do think it's common, so the UI doesn't hard stops at the last item. We can still add manually, it's just annoying, but I fine if the api doesn't have them.

People usually just do px-4 py-3 gap-4: padding horizontally, vertically and item spacing. We already can wrap with padding, so only gap is missing.

If it helps, 4 years ago I convinced Jetpack Compose team to add itemSpacing to Row/Column. Since then, it has been used more than 70k times in public code. As reference, MainAxisAlignment = "center" was used around 100k times.

I guess it's fair to leave the leading and trailing spacing out, as leading many times won't match the spacing from the list, but the trailing I do think it's common, so the UI doesn't hard stops at the last item. We can still add manually, it's just annoying, but I fine if the api doesn't have them.

it may be common in codebases you've run into but it's not common in these APIs

Hello @lukepighetti, your proposal sounds good! However, there’s a simple approach to do that:
Column(
  children: [
    Container(
      color: Colors.red,
      height: 100,
      width: 100,
    ),
    Container(
      color: Colors.green,
      height: 100,
      width: 100,
    ),
    Container(
      color: Colors.blue,
      height: 100,
      width: 100,
    ),
  ].expand((widget) => [widget, const SizedBox(height: 20)]).toList()..removeLast(),
)

It also allows you to inject any other widget between your children.

The issue is that if you go from Row to Column you need to change height to width, it is pretty verbose to use in every single widget (I use this everywhere in other languages) + manually adjusting width with height, and also prevents const from working.
With all the respect, but I keep thinking, if you want to simplify the framework the most, why do we even have MainAxisAlignment start / center / end? Could just be Row(children: [ Expanded(), Container(...)]) instead of MainAxisAlignment.end. One less parameter in the framework.

if you want to simplify the framework the most, why do we even have MainAxisAlignment start / center / end?

A lot of early decisions were made before we really had a solid grasp of the principles on which we should build the framework.

Do you regret having it? If you were doing it again, would you omit?

There's a lot about Row/Column that I'd do differently if we were starting over, but I haven't studied it carefully (it's a moot point, we can't break them, too many people use them) so I couldn't give you a detailed answer.

These are basic widgets that everyone uses, I think they should have the best possible api. Flutter has a philosophy of breaking things in order to keep staying relevant, and I would support a change to those widgets if we will get good benefits from this.
As an alternative we could explore creating new widgets under different names, and if the experiment is successful we can consider renaming them to Row and Column. It would take years, but better than keep the framework stuck with past decisions IMO.

I agree. Flutter deprecated material buttons (without hot fix), changed color scheme in multiple (weird) ways, changed a lot of material things for m3.. VStack, SuperFlex, Row2, ComposableRow, ExperimentalRow could be a welcome change into the future of Flutter. Bring the full jetpack compose API. Bring modifiers, allow changing background color, padding, size. All from the widget itself using a Modifier builder in a composible way without endless nesting. If it works well (it would) then bring the change to the rest of the framework and name Flutter 4.

Yes, that's essentially the options I listed in https://github.com/flutter/flutter/issues/55378#issuecomment-2253345395. The first step is for someone to actually implement one of those. :-)

I think the discussion got a little bit sidetracked.
For now, I really just want a single numeral spacing parameter like in the other frameworks.

Yes, that's essentially the options I listed in https://github.com/flutter/flutter/issues/55378#issuecomment-2253345395. The first step is for someone to actually implement one of those. :-)

@Hixie, I was basing my argument on the fact that you wanted to explore more how these widgets could have been created differently, and emphasising that many other and I would like to see breaking changes.
My point was more "please do your research, brainstorm, etc. and surprise us once more with a cool new widget" instead of "someone please send a random PR with an implementation".

Flutter is an open source project and many people contribute their time (or their employees' time) to fix code and implement features. Typically, people fix bugs and implement features that are relevant to their customers. For example, Google engineers who contribute to Flutter are going to prioritize issues that affect Flutter apps written by Google teams. Telling volunteers to "do your research, brainstorm, etc. and surprise us once more with a cool new widget" is highly presumptuous and entitled.

The issue is that if you go from Row to Column you need to change height to width, it is pretty verbose to use in every single widget (I use this everywhere in other languages) + manually adjusting width with height, and also prevents const from working.
With all the respect, but I keep thinking, if you want to simplify the framework the most, why do we even have MainAxisAlignment start / center / end? Could just be Row(children: [ Expanded(), Container(...)]) instead of MainAxisAlignment.end. One less parameter in the framework.

You're right and I can't agree more! I suggested that as a temporary way that doesn't require a third-party package. Though, it has some drawbacks as you mentioned. It can be written inside an extension on List, making it easier to use. Although it doesn't detect whether it's being used in a Row or a Column:
extension ListHelper on List<Widget> {
  List<Widget> addSpacer(Widget spacer) {
    return expand((widget) => [widget, spacer]).toList()..removeLast();
  }
}

However, having that as a parameter of the Row and Column widgets will be awesome.

Flutter is an open source project and many people contribute their time (or their employees' time) to fix code and implement features. Typically, people fix bugs and implement features that are relevant to their customers. For example, Google engineers who contribute to Flutter are going to prioritize issues that affect Flutter apps written by Google teams. Telling volunteers to "do your research, brainstorm, etc. and surprise us once more with a cool new widget" is highly presumptuous and entitled.

That's not what I meant by any means!
Correct me if I am wrong, but I believe certain core widgets and mechanism are not created by individuals out of the blue. They require meetings and brainstorms. That's at least how I do with my team when I am creating an app's architecture or a complex feature.
I wasn't mandating you to create something for me, I apologise if it sounded this way. I also can't see you @Hixie as an individual contributor, you are one of the fathers of Flutter, your decisions carry lots of weight and knowledge. I feel your input and guidance is heavily needed to set the direction of a new implementation of such a core widget, as you said you wanted time to rethink Flex. that's all.
I don't think I can rethink Flex and come up with something up to your level, and I have 5+ years of Flutter, many of those as Tech Lead. I was not meaning to be presumptuous, but rather seeking guidance from someone that has a lot more context and experience than I do.
My intent was to say that rewriting Column and Row requires a set of skills and knowledge that most don't have, it will envolve IMO a brainstorm session and a request for comment doc (like many that Flutter created).
The impact will be huge, so I see it as a feature that we need to think through together, and evaluate, and not something an individual person can just send as a PR. Let me know if you disagree, please.
In any case, if my suggestion of Spaced is something that you like, I can submit it as a PR.

I would definitely encourage you to submit a PR for something like Spaced, yes!
If you would like advice I'm happy to provide it, ping me on our Discord (invite link in the contributing guidelines).

I think there is a point which hasn't been made.
Who exactly is this helping? Who is this addition for?
Is it for the more advance Flutter developers? No.
We are smart enough to insert items in between items in a array.
Is it for those beginner programmers? No.
The inmates shouldn't run the asylum.
The Real Reason:
When Flutter is proposed as a solution to experienced developers, they immediately start comparing it to what they already know. Flutter has so many wins in this area.
However, it's the small things that matter. Being the only front-end framework without a feature is terrible for Flutter's brand.
The Real Reason we want this feature is that we want Flutter to succeed in the long term.
Everyone taking time out of their day to be here has invested hundreds of hours into the Flutter Ecosystem.
They have bet on Flutter with their careers, time, and money.
We want Flutter to be the best modern front-end framework to end all frameworks.
It's small wrinkles like this which concern us all.
I think this is enough to warrant Row.separated being added to the framework

One thing that Flutter has that many other frameworks don't have is simplicity without compromising power. One way we have done that is by minimizing the number of features in individual widgets, relying on composition instead. (This is so important it's literally the first thing Adam listed when writing https://docs.flutter.dev/resources/inside-flutter - he even used the example of Padding to illustrate this point.)
It's very easy to look at two frameworks, make a list of features in each, and add the missing features from one to the other. What's hard is adding simplicity. You can only remove it. The way you remove it is by adding those features.
You will not see "simplicity" in a list of API features.
Flutter will not succeed in the long term by being just another framework that has all the same features as the other frameworks. But it might succeed if it has something the other frameworks don't, like simplicity.
Antoine de Saint-Exupéry said perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. In API design, it is very easy to add. What is hard is not adding. Taking away is basically impossible.

Hey, so I gave implementing this myself a shot. I'll make a pull request later this week once I've written some more tests and ensured that the baseline feature still works.
For my implementation I made the following decisions:

spacing is an argument of type double on Flex, Column, Row and RenderFlex
spacing represents the minimum amount of space between items

if there's not enough size for your Flex that has spacing, the spacing will not shrink. You will get an overflow.
there can be more space than spacing between items. For example with MainAxisSize.max and MainAxisAlignment.spaceBetween. The algorithm picks the max from your provided spacing and the natural spacing.

MainAxisAlignment.spaceEvenly and MainAxisAlignment.spaceAround apply the user provided spacing before the first / after the last item, as one would expect.
You can have negative spacing / overlap. I wanted this, because Figma has it -- and it actually solves something that'd be a bit more complicated to do by just wrapping the children.

With negative spacing, MainAxisAlignment.spaceEvenly and MainAxisAlignment.spaceAround work like MainAxisAlignment.spaceBetween so that items don't extend outside the Flex(which I thought would be weird)
With negative spacing, Flexible children have a minimum main axis extent of -spacing so as to prevent [negative space, zero sized flexible child, negative space] which would essentially look like a double sized overlap.

https://github.com/user-attachments/assets/aaa8fe62-016c-4c7d-aa10-7b4b402f3eaf

@benthillerkus I'm curious to see the code; as noted in the discussions above, there is a high risk when adding a feature like this that it will increase the complexity of the layout code, which is why I recommended options that compose with Row/Column rather than being features in Row/Column directly.

The code is in my fork on the branch flex-spacing. Should I make a PR even though there's still stuff to do?
IMO the changes to support positive spacing were fairly minor and mostly contained to MainAxisAlignment._distributeSpacing  which already had the right structure to support this.
For negative spacing there are some more edge cases I introduced which I documented.
flex.dart isn't the easiest code, but I don't think my additions made it unreasonably worse :)

I will try to send a PR of Spaced in the coming days, without tests, just for initial approval. If approved I can add more time for the unit tests.

@benthillerkus yeah the logic changes in RenderFlex are exactly the kind of scary changes I was worried about. I really don't think we should apply this change directly to RenderFlex.
(I don't want to make it sound like I'm ungrateful for your contribution! If it had turned out to be something we could do with minimally invasive changes then that would have completely changed my opinion here, so doing this work is definitely valuable research!)
Pushing a forked RenderFlex/Row/Column as a separate package for people who want to use it would make sense, if you're interested in owning the maintenance of that package going forward.

Hmm, I wouldn't say the changes are scary.
The flow / structure isn't touched and it's line by line easy to reason that the previous behavior is kept intact when spacing = 0.
With more / more exhaustive tests the behavior would be nailed down further.
If you're worried about the number of LOC touched, not doing negative spacing reduces them by ⅓ or so, though I'd personally consider any solution that doesn't do negative spacing/overlap not good enough.
Overall I'd agree that the state of flex.dart isn't great, but I don't think my changes make it so much worse that it's not worth the features. With spacing done, there's also nothing missing from CSS Flexbox[^1], so how much need is there in the future to add new features to flex.dart?
And if flex.dart were then to be rewritten at some point, would maintaing support for spacing be unreasonable?
I just want the Flutter default to work to work well and solve the complicated stuff.
With regards to external packages or even a future rewrite, It'd make more sense to bind to Taffy or Yoga than to have a bespoke Dart implementation, especially if maintainance is so problematic.
[^1]: Besides relative units, I guess, though I haven't seen anyone asking for them.

As far as I can see the options we have are:

Changing the flex widgets: This has a very broad impact, everyone uses them, once it's done you can't go back, and getting the right api for everyone is hard. That's why it's scary.

Adding a function to add space: that is not how Flutter usually does things, so it will feel weird to have it in the framework.

Adding an extension: same as before. SwiftUI uses them more, but not Flutter atm.

Adding a composable mechanism to add space: that's my suggestion, it fits Flutter current mechanics and brings a very encapsulated solution that won't affect any of the current widgets.

Adding a composable mechanism to add space: that's my suggestion, it fits Flutter current mechanics and brings a very encapsulated solution that won't affect any of the current widgets.

I'm not actually sure this is that consistent with flutter. Sure it's composable but it's not a widget which is a bit visually confusing given how much it's behaving like a widget.
A bit off the rails but if there's desire for a Flutter sandbox with a lower barrier to breaking changes it'd be nice to see the Flutter team spearhead that (even if it's still mostly community contributed) as the sandbox is markedly more valuable the more visibility it gets.
More on the rails: how is the decision here going to be made? Should someone write up a proposal doc (I'd be comfortable volunteering if no one else wants to) detailing the exact proposals and tradeoffs and then distribute that and the flutter team/relevant stakeholders can sign off or reject?

There are many composable classes that are not widgets in the Framework, I considered this when I suggested this solution.
Regarding the decision making, I was trying to suggest/ask the same, so we don't get 15 PRs, most of them rejected.

This is my implementation, mimicking Figma (spacing + allow negative spacing + allow to decide which one you want on top in case of negative spacing). This is as complex as it can get!
https://gist.github.com/bernaferrari/0897eeadfd10c9f396602c7a91429127
If you run a code diff, it is basically, and that's adding two variables (firstOnTop, else you can kill that if/else):

Hello everyone!
Thanks for all the implementation comments, it certainly saved me some time.
My initial goal was to evaluate the simplest approach. Introducing double spacing parameter similar to Wrap.spacing  seems to be the simplest and familiar to anyone using Wrap.
I've a draft PR which mainly updates two aspects of Flex  widget which are between space and accumulated axis size.
Since we have multiple comments showcasing their own approach for the same parameter approach and planning to file PR. To save time for everyone, I'll put out my draft for spacing parameter, if we decide to go with it I'll update the PR to proceed further.  If we decide to go another direction we can assign someone who has a different approach so we don't end up having several PRs for this fix.

Since somebody asked about this elsewhere, posting it here everyone.
The double spacing parameter in my https://github.com/flutter/flutter/pull/152472 PR applies spacing regardless of mainAxisAlignment type.
So this means you can use any mainAxisAlignment type with a custom spacing value and expect to the Column/Row to overflow when total items size + total spacing is more than the layout size.
Resize demo
https://github.com/user-attachments/assets/74d77736-75a3-4df4-841f-b6ed9a2d70b7
Feel free to provide any feedback.

@bernaferrari Are you going to make a PR with your changes?
@TahaTesser IMO with spaceAround and spaceEvenly your spacing should be applied on the outside too, for consistency; otherwise the naming / usage of these would be pretty confusing

Technically I could, but don't think I'll. I've had that code for months and never submitted because the original issue was closed, and every subsequent trial of discussing was closed, and I still don't know if Taha will land because Hixie still seems against it. But I fully support him, and if he wants to use part of my code he is totally welcome.
As far as my understanding goes, spaceAround and spaceEvenly should just ignore this. I don't remember if on CSS it is not ignored, but on Jetpack Compose it is (their implementation is very beautiful, MainAxisAlignment is a class, not an enum, so start/center/end has different properties than spaceAround). Worth checking how swift is doing, too. But my guess is it is perfectly fine to ignore. Figma ignores it.

I think we should prefer a solution that does not increase the complexity of existing widgets, such as the possible solutions given by @Hixie in https://github.com/flutter/flutter/issues/55378#issuecomment-2253345395, or maybe something along the lines of the Spaced solution given in https://github.com/flutter/flutter/issues/55378#issuecomment-2254094894 by @feinstein.
If we are going to look at a solution that adds a parameter to Row/Column like @TahaTesser's solution in https://github.com/flutter/flutter/issues/55378#issuecomment-2255327641 and others, I think we should be certain that 1. a simpler solution is not possible and 2. the additional complexity of adding a parameter is worth changing the status quo. I'm not yet convinced of either point.
At first blush it seems like a solution that doesn't add a parameter should totally be possible... I think we should focus our attention on exploring that rather than arguing about point 2. @feinstein do you plan to try to implement Spaced?
How to proceed from here?
@caseycrogers Asked about next steps in https://github.com/flutter/flutter/issues/55378#issuecomment-2254790554.
I think a design doc would be helpful given how contentious this is. There is a lot of information in this very long thread that could be more easily consumed in a design doc format for people trying to catch up. It seems like possible solutions are still being sorted out, though, so you'll probably have to keep updating it if you do write one now.
For those that are proposing possible solutions, I think you should feel free to open draft PRs. It's easier to see exactly what you mean and comment on it, and working code speaks louder than words. A lot of people are writing code for this issue and most won't end up in the framework, but like @Hixie said above in https://github.com/flutter/flutter/issues/55378#issuecomment-2254748853, it's not wasted effort and you are helping find the best solution either way.

The issue of Spaced is that it requires knowing who the parent is (Row or Column) so it adds the appropriate SizedBox, and is is against Flutter guidelines. There was a PR that did exactly that a few months ago and got closed because you can't do without is check.
I think Taha/mine solution is only a few LOC with no side effects, while "wrapping Row with something else" is not possible, so the end result would be making a second Row which is 99% duplicate only with a few LOC of changes.
Making a package is doable (can even publish my code), but then no one would use due to the added friction for something so small. For me this feature is essential - which is how I convinced Google to put in Compose 4 years ago and they never regretted. When I got strokeAlign added on the framework, a lot of people were "I think that's a bad idea, shouldn't be on the framework, that's going to make things slow" and Google was already using in their internal apps before it reached Flutter stable. I think it is fair to make a design docs, everything, but this issue has been going for 6 years with no progress.

Yeah literally passing an instance of a non-Iterable class to children is not going to work. I'd be interested to see it as a helper function or something though.

@TahaTesser's fix is a lot simpler than @benthillerkus', which is encouraging. I still think there's a danger in continuing down the road of increasing the complexity in Row and Column but if we can keep the complexity down as in @TahaTesser's PR then that might be ok.
Every time we add something, though, we are risking adding the thing that makes Flutter no longer stand out from the other frameworks. This is a perfect example of a feature that just doesn't need to be added to the core (doing so does not add something you can't already do, it's just a convenience mechanism), and each time we add something like that, we are eroding the core of what Flutter is.

In this case the only way Flutter is standing out is in people expecting to find a common layout feature and getting frustrated when they have to do list manipulation to implement it. For that reason I'm all in favor of adding the thing and @TahaTesser's solution looks great to me. 👍

it's just a convenience mechanism ... and each time we add something like that, we are eroding the core of what Flutter is.

@Hixie what would change your mind that the convenience of a spacing parameter to Column and Row is worth the complexity? For example, could you think of a user study that - depending on the results - could help you change your mind?
FWIW, I empathize heavily with your arguments. I completely agree with you that Flutter's simplicity and composability is something we should protect. I've done enough web development to cherish this. Nonetheless, my experience building Flutter apps is that the convenience of a spacing parameter is well worth breaking our rules.

@justinmc I finished a first draft of Spaced yesterday, I was planning to test it today and submit a PR. @Piinks should I discard and stop?
@bernaferrari I am not using is to determine the parent, I wish the gap package was merged into Flutter, so I could use it instead of SizedBox, but instead I created 2 constructors Spaced.horizontal and Spaced.vertical, so no automatic choosing, the developer will need to choose accordingly.
Sorry for the delay in my messages, I am living in Australia 🇦🇺 now.

I created 2 constructors Spaced.horizontal and Spaced.vertical, so no automatic choosing, the developer will need to choose accordingly.

I'm not sure I understand what spaced is doing. Is spaced something you place between each child? Do you wrap it around it each child? If yes, what's the difference to SizedBox or Padding?

Here's the draft PR https://github.com/flutter/flutter/pull/152516

I strongly support us landing something here.
Discussing this issue with some folks internally, I think we should optimize for making common patterns in Flutter expressible with as little typing as possible. In other words, brevity is important and we should be optimizing for that.
So, I like https://github.com/flutter/flutter/pull/152516 because it doesn't require modifying Row/Column directly, but, I think I prefer TahaTesser's approach of directly adding the parameter in https://github.com/flutter/flutter/pull/152472.

I share the same feelings, when I first proposed Spaced, I thought it would be cumbersome to use, but "safer" for the framework.
I am not sure how many different ways devs want to space their lists, and we can add many mechanisms to Spaced, but not to Row/Column/Flex, that's why I continued to propose it.
Maybe we need both? I would like to see from the community how they feel and what they think that might be missing from a single spacing configuration, as we might add those to Spaced.

I am not sure how many different ways devs want to space their lists

A lot. You can go to github code search and search for "gap", "grid-gap", "space-x-", "space-y-", "spacedBy", "itemSpacing". It is really popular in every single framework.
I think I'm in with Taha's solution only for now, don't need anything else.

I checked my current app and it looks like the only way I'm separating columns/rows today is as follows:
// `Gutter` is from my `flutter_gutter` package that's like Gap but with default sizes.
return Column(
  children: <either a list literal or `list.generate`>.separated(const Gutter).toList(),
);

I do regularly inject a separator widget (eg a divider) but in the cases where I've done that it was in scrollables so I was using ListView.separated.
I think any of the proposals here are reasonable enough and would be happy with any single one. Here is a list of what I've seen mentioned so far (could be converted into a proposal/design doc) and my feelings on the tradeoffs:

A .separated list extension in the Flutter framework
Pros: composable, ultra lightweight, matches existing practice, allows for arbitrary spacers
Cons: extension methods aren't super "idiomatic" in Flutter today (doesn't have to be this way?), gap axis alignment has to be manually matched to parent

Column(
  children: [
    Foo(),
    Bar(),
    Baz(),
  ].separated(SizedBox(height: 10)),
);

Same as above but as a function and/or class that wraps a list
Pros: same as above + looks a little more Flutter idiomatic
Cons: A little weird to have a wrapping class between a widget and it's children that is not a widget, adds to nesting h*ll that already is one of the UX downsides in Flutter, axis alignment isn't automatic

Column(
  children: Spaced(
    [
      Foo(),
      Bar(),
      Baz(),
    ],
    SizedBox(height: 10),
  ),
);

A .separated constructor on Flex and/or Column/Row
Pros: (somewhat) mirrors ListView, allows for arbitrary separators
Cons:  Adds complexity to the framework widgets (seems like the magnitude isn't that high?), not composable, axis alignment is not automatic

Column.separated(
  children: [
    Foo(),
    Bar(),
    Baz(),
  ],
  // Could be a `separatorBuilder` with `context` and `index`, but that's getting complicated enough that maybe it'd
  // be better to just generate the list with separators manually.
  separator: SizedBox(height: 10),
);

A gap or spacing argument on Flex/Column/Row's constructors

Column(
  gap: 10,
  children: [
    Foo(),
    Bar(),
    Baz(),
  ],
);

pros: maximally discoverable, axis alignment is automatic, simplest external API, potentially support negative gaps???
cons: doesn't support arbitrary separators, adds complexity to Flex
Curveball proposal I'll add now:
5. Extension (or change to Dart?) to overload an operator for separating a list (maybe /?)
Pros: composable, simple,
Cons: a bit obtuse-looking but that may get better with exposure, gap isn't axis-aligned, not very discoverable
Column(
  children: [
    Foo(),
    Bar(),
    Baz(),
  ] / [SizedBox(height: 10)],
);

@Hixie what could change your mind that the convenience of a spacing parameter to Column and Row is worth the complexity and results in an overall usability improvement?

The simplicity of @TahaTesser's patch was what changed my mind.

Nonetheless, my experience building Flutter apps is that the convenience of a spacing parameter would be well worth an exception to our rules.

The problem in general is that every group of a thousand Flutter developers will have their convenient thing that would be a great exception to the rules, and we have millions of developers using Flutter, so eventually you've added thousands of convenient things and you've lost the simplicity that made the whole convenient in the first place.

Discussing this issue with some folks internally, I think we should optimize for making common patterns in Flutter expressible with as little typing as possible. In other words, brevity is important and we should be optimizing for that.

For the record, this is a change of direction for the project, away from a direction that led to a lot of decisions that made the project successful.

@Hixie

For the record, this is a change of direction for the project, away from a direction that led to a lot of decisions that made the project successful.

I think is a very pessimistic take. This shouldn't set a precedent at all.

@caseycrogers issue is that you loose the const, or you need to manually say width/height, or you end up with a completely non standard API that no one has ever seen, or the added complexity is like 10 LOC, which is what Taha is proposing. I don't think there is a better way.

@Hixie

For the record, this is a change of direction for the project, away from a direction that led to a lot of decisions that made the project successful.

I think is a very pessimistic take. This shouldn't set a precedent at all.
Good things are ahead. Onward and Upward!

@dickermoshe quite the opposite. We are changing a core widget to add a "convenience" feature. This issue can and will be used as an example for all other issues requesting many other small additions here and there, that devs find annoying or missing.
I totally agree with @Hixie, I think there's a sweet balance point in the middle, but it's hard to find, so decisions like this can't be hurried.

so eventually you've added thousands of convenient things and you've lost the simplicity that made the whole convenient in the first place

My biggest issue is (not quoting you, but an overall feeling) "I regret that we made Container", "if it were today, Row would be completely different", "this widget was made for another time". The feeling I have is that Flutter became old and there is a big difference from the theory to what we got in practice. ColorScheme now has 41 colors. Button got deprecated, re-implemented and now has maximumSize, minimumSize, fixedSize, padding, visualDensity, tapTargetSize (all doing +- similar stuff and conflicting which each other). You could argue if someone wants visualDensity with padding they can add from outside, or that tapTargetSize shouldn't belong to the widget). Or there is the FormField with like 70 properties, as well as ListTile, SwitchListTile and so on. We are in a state that things got too complex.
I'm all in for Flutter, simplicity, everything, and I understand your fears and frustrations, and the desire to avoid breaking changes. But I can't stop thinking about, well, isn't it time for Flutter 4 inspired by Compose or something else? When Flutter was created it solved many complexities, but over time other frameworks learned the lessons and built on top. Nowadays I can do wonders using shadcn/ui, developing way way faster than Flutter, with more simplicity and overall easier to maintain code. There is people constantly reminding how easy SwiftUI is, even for its flaws. I don't expect from you, but isn't it time for us to collectively think into how we can make Flutter still simple but still work for everyone, even if it is a multi-year effort with deprecations or a new semantic version?

Discussing this issue with some folks internally, I think we should optimize for making common patterns in Flutter expressible with as little typing as possible. In other words, brevity is important and we should be optimizing for that.

For the record, this is a change of direction for the project, away from a direction that led to a lot of decisions that made the project successful.

This seems like a weird way to interpret that we want to optimize for brevity.
The verbosity is one of the biggest complaints leveled at Flutter and I don't subscribe to the idea that we need to be verbose to be successful.

Correct me If I'm wrong, but I think Hixie is more concerned about package:flutter/widgets.dart than package:flutter/material.dart

I agree, but he has expressed multiple times regret over Container, Row/Column/Flex, BoxDecoration and a lot of things we have "for granted", which probably causes a cascading effect over everything else.

@bernaferrari Happy to talk about that but let's take it to the Discord since it's a bit off-topic for this issue.
@johnmccutchan A framework that is verbose and simple will garner criticism for being verbose. A framework that is terse and complicated will garner criticism for being complicated. In practice good design is a selection of trade-offs. When the trade-offs are intentional, it tells you the kind of criticism you should expect. There are many, many more axes than just verbosity and complexity, any many of the possible design choices are mutually exclusive, meaning it is impossible to design something that garners no criticism. Happy to discuss this in more detail in a more relevant venue if you like.

I find the argument for simplicity here misplaced. The only thing simpler vs the competition in Flutter is making Material apps. For everything else the competition has far outpaced what Flutter is offering. And what is being offered by others is greater focus in flexibility, get more with less convenience solutions and opinionated defaults with escape hatches. With Flutter we get a whole lot of opinionated and scant else what actually matters in day to day development.
In many ways you could argue Flutter became successful not because of the Flutter core but despite it.  It's 2024, ergonomics matter. And stagnation only works in isolation. Flutter has well outgrown the "side project for valuable talent to keep busy" phase in Google. Which means Flutter should actually acknowledge the greater UI development sphere it is part of and put more focus on adapting, competing and assimilating. Relying on the cross-platform moat is not as big of a factor as Google might imagine, especially in corporate adoption setting.
So the decision to move ahead of actually solving this very common ergonomics problem is most welcome indeed.

General conversations about Flutter's philosophy around API design are not relevant to this issue.
Please keep discussions on this issue narrowly focused on what shape of API changes would make developer's the most happy and productive.

@johnmccutchan A framework that is verbose and simple will garner criticism for being verbose. A framework that is terse and complicated will garner criticism for being complicated. In practice good design is a selection of trade-offs. When the trade-offs are intentional, it tells you the kind of criticism you should expect. There are many, many more axes than just verbosity and complexity, any many of the possible design choices are mutually exclusive, meaning it is impossible to design something that garners no criticism. Happy to discuss this in more detail in a more relevant venue if you like.

I don't really understand why we can't optimize for multiple things simultaneously.
The key to Flutter's success is not being verbose, if anything that seems like an anti-pattern that we overcame or something that wasn't felt 8 years ago but now with newer frameworks is.
But, as you said, this isn't the place to discuss general philosophy.

The complexity that would be added to the codebase by implementing this specific feature is minimal and given how cited this specific issue is, we can't just sit on our thumbs or tell people to copy and paste code or make a new pub package.

Something that's been on my mind which I believe is somewhat relevant…
MainAxisSize & MainAxisAlignment don't really cooperate—using MainAxisSize.min makes setting a MainAxisAlignment pretty useless, and vice-versa. Perhaps a few breaking changes as part of a major overhaul (Compose-esque Flutter 4 maybe?) would be an overall benefit to Flutter's longevity.

In the ideal world, MainAxisSize wouldn't even exist. In Compose it is just fillMaxWidth(), and any widget can make use of that, instead of Flutter strong defaults where you never know what to expect (like Button, need to center it first so it doesn't fill the space)

Reopening since the change was reverted, just need to address a failing integration test to resolve and get it back in. 👍

I really appreciate all the discussion here and am looking forward to using it when it's released in stable!
After reading all the comments though, I couldn't figure out what the reason was that it finally got included in the framework as a property on both Row and Column.
Would someone kindly recap what the reasons were that ultimately allowed this feature to be introduced?
I think the PR is very elegant and also caught clipBehavior not being added to the debugFillProperties 👏 Well done @TahaTesser.
It looks like this comment from @Hixie might be the reason: https://github.com/flutter/flutter/pull/152472#issuecomment-2261533778

Seems to be "too much people want this" with "the change is actually super small" with "it is super useful" with "I don't think there is a better way" with "we wish we could rewrite Row entirely but we can't".


private urls being access via amazon ips.

Please first read the documentation. Problems affecting the client, e.g. Plex or Emby should be reported there in the forum.
Describe the bug
Using a provate URL and the provider has commented as to why I am using an amazon service to access to the streams.
A clear and concise description of what the bug is.
Server (please complete the following information):
Ubuntu
<IP_ADDRESS>
To Reproduce
Add a url
Watch IPs that connect use that url
Expected behavior
Only my IP shoukd access this
Screenshots
Desktop (please complete the following information):
Additional context
Why would xteve use AMAZON to pull the same channels from a URL

Im going to research some more


CSS

CSS
User Story
As a Bootcamp Student
I want the prework notes to be structured on a webpage
So that I can easily find a read information
Acceptance Criteria
Given a prework study guide website
WHEN I view the study guide
THEN I see a dark blue header and footer, and four boxes with a shadow

Completed with flair!


pointermove => pointerstop

It will be nice to have a native event .on pointerstop in plugins.interaction ?
I don't know if is a good idea or if pixi already have it ?
It's not really a problem, just a suggest feature.
in classic listener we can do this, it tricky.
document.onmousemove = (function() {
    let onmousestop = function() {
            stopped = true;
        },
        thread;
    return function() {
        clearTimeout(thread);
        stopped = false;
        thread = setTimeout(onmousestop, 40); // setup time precision for stop
    };
})();

Since the current policy with Pixi is to try and stick closely to browser event behaviour, I think this is best handled via a plugin rather than natively within the core library itself

well i found a little tricky way with this.
https://github.com/pixijs/pixi.js/blob/22f146c932d8e9e0ec952ca64b83dd57764d3ac6/packages/interaction/src/InteractionManager.js#L840
It little hack and dirty and not cleaner like a event register but it work fine for what i need.


As a project dependency too

Just an idea I had. Instead of starting from your project, I would start by making a new project, then I would run npm install gulp-starter. This will install it in my node_modules. And now I could simply use the gulp task from your gulp-starter in node_modules in my gulpfile.js.
My gulpfile.js could look like this:
// Get the default config and tweak it with my own options
// This way, I only need to define a few options
var config = extendDeep(require('node_modules/gulp-starter/gulp/config'), {
  browserSync.port: 8081,
  images.dest: "img",
  globals: {
    debug: false,
  }
});

// Set up "default", "build" and "clean" tasks:
require('node_modules/gulp-starter/gulp/tasks/base');

// Now only load the tasks we need
require('node_modules/gulp-starter/gulp/tasks/watch');
require('node_modules/gulp-starter/gulp/tasks/jshint-early');
require('node_modules/gulp-starter/gulp/tasks/browserify');
require('node_modules/gulp-starter/gulp/tasks/jshint-full');
require('node_modules/gulp-starter/gulp/tasks/browserSync');
require('node_modules/gulp-starter/gulp/tasks/sass');
//require('node_modules/gulp-starter/gulp/tasks/images');  // <- Temporarily disabled

A few benefits:

updates to gulp-starter can be applied easily by updating the module
no need to update my own code
I get all the best gulp tasks from the community
I can simply enable or disable a task. Tasks define themselves their own dependencies

It could use something like this: https://github.com/3rd-Eden/canihaz or like that https://github.com/unfold/gulpfile-install or https://www.npmjs.com/package/install-requires to prevent having a lot of unused dependencies (nobody uses sass, less and stylus at the same time).

Interesting idea! Probably not something I'm going to undertake in the near future, but good to think about. Let me know if you end up putting something together. Another route some people have looked at is using Yeoman: https://github.com/yeoman/generator-gulp-webapp


fix: forces rendering update from new props

When updating the ranges, the pips are not updated. With this PR (which based on recommendation from the noUiSlider website) it forces a complete re-rendering of the whole component.

WFM, there's currently no other choice, thanks a lot!


Do the builder include_path stuff automatically.

This PR adds the include_path handling to the bindgen builder created by sgx_builder() so it's automatically handled.

Current dependencies on/for this PR:

main

PR #156

PR #157   👈

This comment was auto-generated by Graphite.

Codecov Report

Merging #157 (2f7f6ff) into jcape/ci-copyright (670061d) will decrease coverage by 0.24%.
The diff coverage is 0.00%.

@@                  Coverage Diff                   @@
##           jcape/ci-copyright     #157      +/-   ##
======================================================
- Coverage               84.56%   84.31%   -0.25%
======================================================
  Files                      44       44
  Lines                    2390     2397       +7
======================================================
  Hits                     2021     2021
- Misses                    369      376       +7

Impacted Files
Coverage Δ

core/build/src/lib.rs
0.64% <0.00%> (-0.04%)
:arrow_down:

:mega: We’re building smart automated test selection to slash your CI/CD build times. Learn more


Move ClientAppProfile to dependencyManager.RegisterMetadata instead of having that in DefaultPage and identity

https://github.com/bit-foundation/bit-framework/commit/a6f1c47410dd740eae28ba03f84bf033a22f2939


Problem with the order of references by the generate references script

The generate references script file is a great tool.
However, some times the order of the references is wrong. Unfortunately FSI is very picky about this. This happens when you have a project reference that references a nuget package. When the project reference appears before the nuget package an you load the references.fsx file in the FSI, the FSI cannot interpret the code in the project reference that uses the nuget package.
For example:

#r @"/.nuget/packages/mathnet.numerics/4.4.0/lib/netstandard2.0/MathNet.Numerics.dll"
#r @"l/Development/GenFormService/src/Informedica.GenUnits.Lib/bin/Debug/netstandard2.0/Informedica.GenUnits.Lib.dll"

The Informedica.GenUnits.Lib uses MathNet.Numerics, so the reference to MathNet.Numerics should appear before Informedica.GenUnits.Lib.

We're using order resolved during cracking project files which is used for F# Compiler Services. I'd expect FSI to work just fine with same order.
CC: @dsyme, any idea?

References can usually go in any order, though there are issues if there is code in between and perhaps there would be issues with intermediate ";;"

A member of my meetup group ran into this when generating references for FParsec for FSI. FParsec was put at the bottom of the list of references resulting in this error message.
error FS0193: The module/namespace 'System.Text' from compilation unit 'System.Runtime' did not contain the namespace, module or type 'NormalizationForm'

references.fsx(36,1): error FS1109: A reference to the type 'System.Text.NormalizationForm' in assembly 'System.Runtime' was found, but the type could not be found in that assembly

When they took the references to FSParsec (FParsecCS.dll and FParsec.dll) and moved them to the top they received this error.
error FS0193: internal error: Could not load file or assembly 'file:///C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Runtime.dll' or one of its dependencies. Reference assemblies should not be loaded for execution.  They can only be loaded in the Reflection-only loader context. (Exception from HRESULT: 0x80131058)

error FS0193: Could not load file or assembly 'System.Runtime, Version=<IP_ADDRESS>, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.

When they referenced the dll's explicitly everything worked perfectly fine
#r @"C:\Users\redacted\.nuget\packages\fparsec\1.0.3\lib\netstandard1.6\FParsecCS.dll"
#r @"C:\Users\redacted\.nuget\packages\fparsec\1.0.3\lib\netstandard1.6\FParsec.dll"

open FParsec

type Parser<'a> = Parser<'a, unit>
let ws = spaces
let cident:Parser<string> =
    let isValidCIdentStart (ch) = isLetter ch || (ch = '_')
    identifier (new IdentifierOptions(isAsciiIdStart=isValidCIdentStart)) .>> ws

They used dotnet add package FParsec to add the package and Generate script file from references for project.
It seems to me, and I could be wrong that this is related to this bug.


jssrc2cpg: dealing with const foo = (x,y) => { ... }

The following failing test case illustrates a problem with currently have when analyzing type script code:
https://github.com/joernio/joern/compare/master...fabs/flowconst#diff-afb5c19d03ad15d4ad7e4d95280e9b70f5e434466d8eb2f414ae4444fd35741bR600
For a function defined anonymously and assigned to a constant, we swallow the assignment to the constant and the name of the function remains unknown in the CPG, for example, for
const foo = (x,y) => { ... }

we end up with a METHOD node where the NAME and FULL_NAME fields simply tell us that this is an anonymous method. The assignment to foo is not visible in the CPG. I would propose that we either make the assignment visible, or we simply handle this as an alternative way of defining a named method. The latter is probably easier and would mean that this works without additional changes in the data flow engine.

There should be an assignment to a METHOD_REF linked to the corresponding METHOD node. Otherwise this is a serious bug. I'll have a look tomorrow.

Alright, let me take another look. I got back an empty cpg.assignment.l yesterday, but maybe I did something wrong.

You're right, there was a typo in the code I used to test this on the joern shell. So, that means, we do actually have the assignment, but the data flow engine isn't picking this up. I'm still wondering whether we shouldn't just interpret const foo = $lambda in a pass. I'll continue to investigate.


NLog LayoutRenderer

Implement a layout renderer for NLog to emit ECS compatible JSON

Why not make a custom layout that inherits from JsonLayout. Similar to this:
https://github.com/datalust/nlog-targets-seq/blob/dev/src/NLog.Targets.Seq/CompactJsonLayout.cs
Of course it is recommended to use NLog ver. 4.5.11.
This will make it easy add custom properties besides those included in the custom LogEvent. Ex. ThreadId, MachineName, ${aspnet-request}

Hi @snakefoot
Thanks for having a look at this PR and offering your suggestion. I have spent some time looking at JsonLayout and seeing if it is something we can support.
The ECS format makes heavy use of nested JSON. A short example below:
{
  "@timestamp": "2019-11-22T14:59:02.5903135+11:00",
  "log.level": "Information",
  "message": "Log message",
  "ecs": {
    "version": "1.4.0"
  },
  "event": {
    "severity": 0,
    "timezone": "AUS Eastern Standard Time",
    "created": "2019-11-22T14:59:02.5903135+11:00"
  },
  "log": {
    "logger": "Elastic.CommonSchema.Serilog"
  }
}

I've been looking for a decent way to represent this nested JSON using JsonLayout and this page https://github.com/NLog/NLog/wiki/JsonLayout#advanced-examples indicates how to achieve this.
So far, so good.
We could extend the code generator to generate a C# JsonLayout from the ECS schema, although we would need to create a map that can associate an ECS entity property with an NLog LayoutRenderer. For example:  Base.Timestamp maps to ${longdate}. This would allow us to pre-fill the JsonAttribute values with sensible defaults, and would allow us to maintain the codebase for future generated ECS versions.
We already do something similar for the NEST mapping here: https://github.com/elastic/ecs-dotnet/blob/7ca1d70425717c23937e346bd568a4c94dce5155/src/Elastic.CommonSchemaNEST/TypeMappings.Generated.cs#L83
I also found a complete(?) list of Nlog layout renderers here: https://nlog-project.org/config/?tab=layout-renderers
I am reluctant to generate an NLog XML configuration that the user can incorporate into their app.config and then edit freely. One of the challenges I can see going forward with this approach is how that user will keep their schema up-to-date for future ECS versions. It would be the users responsibility to maintain their XML configuration, and I wonder if this is a good idea for them in the long term.
Have I missed anything here, or does that sound reasonable?

I was thinking it should be a custom Jsonlayout that has prefilled attributes to match your schema. But with the option to add custom attributes besides those add with includeallproperties=true
Sent from my Sony Xperia
---- Stuart Cam wrote ----
Hi @snakefoothttps://github.com/snakefoot
Thanks for having a look at this PR and offering your suggestion. I have spent some time looking at JsonLayout and seeing if it is something we can support.
The ECS format makes heavy use of nested JSON. A short example below:
{
"@timestamp": "2019-11-22T14:59:02.5903135+11:00",
"log.level": "Information",
"message": "Log message",
"ecs": {
"version": "1.4.0"
},
"event": {
"severity": 0,
"timezone": "AUS Eastern Standard Time",
"created": "2019-11-22T14:59:02.5903135+11:00"
},
"log": {
"logger": "Elastic.CommonSchema.Serilog"
}
}
I've been looking for a decent way to represent this nested JSON using JsonLayout and this page https://github.com/NLog/NLog/wiki/JsonLayout#advanced-examples indicates how to achieve this.
So far, so good.
We could extend the code generator to generate a C# JsonLayout from the ECS schema, although we would need to create a map that can associate an ECS entity property with an NLog LayoutRenderer. For example: Base.Timestamp maps to ${longdate}. This would allow us to pre-fill the JsonAttribute values with sensible defaults, and would allow us to maintain the codebase for future generated ECS versions.
We already do something similar for the NEST mapping here: https://github.com/elastic/ecs-dotnet/blob/7ca1d70425717c23937e346bd568a4c94dce5155/src/Elastic.CommonSchemaNEST/TypeMappings.Generated.cs#L83
I also found a complete(?) list of Nlog layout renderers here: https://nlog-project.org/config/?tab=layout-renderers
I am reluctant to generate an NLog XML configuration that the user can incorporate into their app.config and then edit freely. One of the challenges I can see going forward with this approach is how that user will keep their schema up-to-date for future ECS versions. It would be the users responsibility to maintain their XML configuration, and I wonder if this is a good idea for them in the long term.
Have I missed anything here, or does that sound reasonable?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://github.com/elastic/ecs-dotnet/pull/44?email_source=notifications&email_token=ACXZ7HERKIVQWG2NU4KM5FLRBTH37A5CNFSM4KPP77S2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOELBS32I#issuecomment-583216617, or unsubscribehttps://github.com/notifications/unsubscribe-auth/ACXZ7HFLDFB3MXYZEAN5ULTRBTH37ANCNFSM4KPP77SQ.

@snakefoot - what do you think of: https://github.com/elastic/ecs-dotnet/pull/44/commits/d806eb9e75bb2f23966ca2dcf84bd00fc22a0930#diff-0ba4f1a02a13a69ccc7d4cb6f3385a6d ?

I have now looked at the Serilog with CommonSchema Logic. And now understand you want to convert to your own Base-dto-type and then serialize to json.
Then my suggestion of using Jsonlayout will probably not reach the goal. Instead it should be your own custom NLog Layout that contains NLog Layout-properties for each value that exists in your Base-dto-type.
Ex. ProcessTitle, ProcessName, ProcessId, ThreadId.
Then you can "render" each value and build the event-dto-type and then finally serialize it as json using StringWriter that writes to the StringBuilder.
Right now on vacation, but will be back on Friday where I can try and post some example code that makes use of the already available layoutrenderers like ${machinename} etc.
Ofcourse it will reduce allocations if one can skip the allocation of Base-dto-object but just write json directly using JsonLayout.
Sent from my Sony Xperia
---- Stuart Cam wrote ----
@snakefoothttps://github.com/snakefoot - what do you think of: d806eb9#diff-0ba4f1a02a13a69ccc7d4cb6f3385a6dhttps://github.com/elastic/ecs-dotnet/commit/d806eb9e75bb2f23966ca2dcf84bd00fc22a0930#diff-0ba4f1a02a13a69ccc7d4cb6f3385a6d ?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://github.com/elastic/ecs-dotnet/pull/44?email_source=notifications&email_token=ACXZ7HCJXDO2MRPRMD5DM6TRCJLFJA5CNFSM4KPP77S2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOELLP6TQ#issuecomment-584515406, or unsubscribehttps://github.com/notifications/unsubscribe-auth/ACXZ7HBSL2TDACQIHVZTEKLRCJLFJANCNFSM4KPP77SQ.

Okay now I see that the code comes from something similar to T4-TextTemplate (TT). Thus the custom JsonLayout will be in sync with your schema.
And the result is actually very nice. Just need some syntax sugar to make it easily configurable for users. But protect the schema so users do not destroy it.
Thinking something like this (Instead of dotnet-property-names, then one could also just use dashed_name)
public class EcsSchemaLayout : Layout
{
     private class EscJsonLayout : JsonLayout
     {
           public JsonLayout MetaData { get; }

           // TODO Auto-Generate these properties
           public JsonAttribute AgentVersion { get; } = new JsonAttribute("version", "", true);
           public JsonAttribute AgentName { get; } = new JsonAttribute("name", "", true);
           public JsonAttribute AgentType { get; } = new JsonAttribute("type", "", true);
           public JsonAttribute AgentId { get; } = new JsonAttribute("id", "", true);
           public JsonAttribute AgentEphemeral_id { get; } = new JsonAttribute("ephemeral_id", "", true);

           public EcsJsonLayout()
           {
              // TODO Auto-Add these attributes
              Attributes.Add(new JsonAttribute("agent", new JsonLayout
              {
                 Attributes =
                 {
                    AgentVersion,
                    AgentName,
                    AgentType,
                    AgentId,
                    AgentEphemeral_id,
                 }
              }));

              MetaData = new JsonLayout()
              {
                 IncludeAllProperties = true,
                 IncludeMdlc = false,
                 MaxRecursionLimit = 1,
                 RenderEmptyObject = false,
             }

             Attributes.Add(new JsonAttribute("_metadata", MetaData, false));
         }
     }

     private readonly EscJsonLayout _innerLayout = new EscJsonLayout();

     protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
     {
          _innerLayout.RenderFormattedMessage(logEvent, target);
     }

     public Layout SchemaLayout => _innerLayout; // Necessary for NLog config reflection/initialization

     public bool IncludeAllProperties
     {
         get => _innerLayout.MetaData.IncludeAllProperties;
         set => _innerLayout.MetaData.IncludeAllProperties = value;
     }

     public bool IncludeMdlc
     {
         get => _innerLayout.MetaData.IncludeMdlc;
         set => _innerLayout.MetaData.IncludeMdlc = value;
     }

     public int MaxRecursionLimit
     {
         get => _innerLayout.MetaData.MaxRecursionLimit;
         set => _innerLayout.MetaData.MaxRecursionLimit= value;
     }

     [ArrayParameter(typeof(JsonAttribute), "attribute")]
     public IList<JsonAttribute> Attributes
     {
         get => _innerLayout.MetaData.Attributes;
         set
         {
               _innerLayout.MetaData.Attributes.Clear();
               _innerLayout.MetaData.Attributes.AddRange(value);
         }
     }

     // TODO Auto-Generate these properties
     public Layout AgentVersion
     {
         get => _innerLayout.AgentVersion.Layout;
         set => _innerLayout.AgentVersion.Layout = value;
     }

     public Layout AgentName
     {
         get => _innerLayout.AgentName.Layout;
         set => _innerLayout.AgentName.Layout = value;
     }

     public Layout AgentType
     {
         get => _innerLayout.AgentType.Layout;
         set => _innerLayout.AgentType.Layout = value;
     }

     public Layout AgentId
     {
         get => _innerLayout.AgentId.Layout;
         set => _innerLayout.AgentId.Layout = value;
     }

     public Layout AgentEphemeral_id
     {
         get => _innerLayout.AgentEphemeral_id.Layout;
         set => _innerLayout.AgentEphemeral_id.Layout = value;
     }
}

But when the type is not "keyword" but instead "long" or "double" then the JsonAttribute.Encode = false (instead of true). NLog really loves to output strings, and will automatically add quotes for all JsonAttribute-values, unless Encode = false.

@snakefoot - thank you for your suggestion, it looks like an interesting approach. Leave it with me and let me see what I can come up with in the template and generator.

After a good night sleep and pondering. Then I think I'm back to explicit filling out the Base-Dto with the most popular properties. Just like what is done in Serilog.
Think the magic from code generation together with the injection of mapping overrides using NLog Layouts will be very confusing for many. Think it is easier for future maintainers if the logic for NLog and Serilog are very similar.
Will soon post another suggestion where the most popular Base-dto-properties are filled out by default along with support for bonus context properties in Metadata (besides those included with the logevent)
Sent from my Sony Xperia
---- Stuart Cam wrote ----
@snakefoothttps://github.com/snakefoot - thank you for your suggestion, it looks like an interesting approach. Leave it with me and let me see what I can come up with in the template and generator.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHubhttps://github.com/elastic/ecs-dotnet/pull/44?email_source=notifications&email_token=ACXZ7HDYRMS2QDJDUFXNILDRCZLXBA5CNFSM4KPP77S2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOELYBVMY#issuecomment-586160819, or unsubscribehttps://github.com/notifications/unsubscribe-auth/ACXZ7HCK4IOSJPULS324ORDRCZLXBANCNFSM4KPP77SQ.

This is pretty much pseudo-code, that probably won't compile. I have moved the mapping logic from LogEventConverter into the EscLayout.
using System;
using System.Text;
using NLog;
using NLog.Layouts;

namespace Elastic.CommonSchema.NLog
{
    public class EscLayout : Layout
    {
		[ArrayParameter(typeof(TargetPropertyWithContext), "metadata")]
		public IList<TargetPropertyWithContext> MetaData { get; private set; } = new List<TargetPropertyWithContext>();

		[ArrayParameter(typeof(TargetPropertyWithContext), "tag")]
		public IList<TargetPropertyWithContext> Tags { get; private set; } = new List<TargetPropertyWithContext>();

		[ArrayParameter(typeof(TargetPropertyWithContext), "label")]
		public IList<TargetPropertyWithContext> Labels { get; private set; } = new List<TargetPropertyWithContext>();

		public bool IncludeAllProperties { get; set; }

		public Layout EventCategory { get; set; }

		public Layout EventAction { get; set; }

		public Layout EventId { get; set; }

		public Layout EventKind { get; set; }

		public Layout EventSeverity { get; set; }

		public Layout EventSeverity { get; set; }

		public Layout AgentId { get; set; }

		public Layout AgentName { get; set; }

		public Layout AgentType { get; set; }

		public Layout AgentVersion { get; set; }

		public Layout ProcessId { get; set; }

		public Layout ProcessName { get; set; }

		public Layout ProcessTitle { get; set; }

		public Layout ProcessExecutable { get; set; }

		public Layout ProcessThreadId { get; set; }

		public Layout ServerUser { get; set; }

		public Layout ServerAddress { get; set; }

		public Layout ServerIp { get; set; }

		public Layout HostId { get; set; }
		public Layout HostName { get; set; }
		public Layout HostIp { get; set; }

		public Layout ApmTraceId { get; set; }

		public Layout ApmTransactionId { get; set; }

		public Layout UrlOriginal { get; set; }
		public Layout UrlFull { get; set; }
		public Layout UrlDomain { get; set; }
		public Layout UrlPath { get; set; }
		public Layout UrlQuery { get; set; }

		public Layout UserAgentOriginal { get; set; }
		public Layout UserAgentName { get; set; }
		public Layout UserAgentVersion { get; set; }

		public Layout ClientAddress { get; set; }
		public Layout ClientIp { get; set; }
		public Layout ClientDomain { get; set; }

		public EscLayout()
		{
			IncludeAllProperties = true;
			ProcessId = "${processid}";
			ProcessName = "${processname:FullName=false}";
			ProcessExecutable = "${processname:FullName=true}";
			ProcessTitle = "${processinfo:MainWindowTitle}";
			ProcessThreadId = "${threadid}";
			HostName = "${machinename}";
			HostIp = "${local-ip:cachedSeconds=60}";	// NLog 4.6.8
			ServerUser = "${environment-user}";         // NLog 4.6.4
			ApmTraceId = "${ElasticApmTraceId}";                // Consider placing EscLayout into the Elastic.Apm.NLog library (Maybe call it ElasticApmLayout)
			ApmTransactionId = "${ElasticApmTransactionId}";    // Consider placing EscLayout into the Elastic.Apm.NLog library (Maybe call it ElasticApmLayout)
		}

		protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
		{
			var ecsEvent = LogEventConverter.ConvertToEcs(logEvent);    // Creates basic Base + Ecs + Log + Error
			ecsEvent.Agent = GetAgent(logEvent);
			ecsEvent.Event = GetEvent(logEvent);
			ecsEvent.MetaData = GetMetaData(logEvent);
			ecsEvent.Process = GetProcess(logEvent);
			ecsEvent.Server = GetServer(logEvent);
			ecsEvent.Tags = GetTags(logEvent);
			ecsEvent.Labels = GetLabels(logEvent);
			ecsEvent.Url = GetUrl(logEvent);	// TODO
			ecsEvent.UserAgent = GetUserAgent(logEvent);    // TODO
			ecsEvent.Client = GetClient(logEvent);// TODO
			ecsEvent.Trace = GetApmTraceId(logEvent);
			ecsEvent.Transaction = GetApmTransactionId(logEvent);
			var output = ecsEvent.Serialize();
			target.Append(output);
		}

		IDictionary<string, object> GetMetaData(LogEventInfo e)
		{
			if ((IncludeAllProperties && e.HasProperties) || MetaData?.Count > 0)
			{
				IDictionary<string, object> metaData = new Dictionary<string, object>();
				if (e.HasProperties)
				{
					foreach (var prop in e.Properties)
					{
						PopulatePropertyBag(metaData, prop.Key?.ToString(), prop.Value);
					}
				}
				if (MetaData?.Count > 0)
				{
					for (int i = 0; i < MetaData?.Count; ++i)
					{
						var value = MetaData[i].Layout?.Render(e);
						if (!string.IsNullOrEmpty(value) || MetaData[i].IncludeEmptyValue)
						{
						    PopulatePropertyBag(metaData, MetaData[i].Name, value);
					}
				}
				if (metaData.Count > 0)
				       return metaData;
			}

			return null;
		}

		string[] GetTags(LogEventInfo e)
		{
			if (Tags?.Count > 0)
			{
				if (Tags.Count == 1)
				{
					string tag = Tags[0].Layout.Render(e);
					return GetTagsSplitted(tag);
				}
				else
				{
					var tags = new List<string>(Tags.Count);
					for (int i = 0; i < Tags.Count; ++i)
					{
						string tag = Tags[i].Layout.Render(e);
						tags.AddRange(GetTagsSplitted(tag));
					}
					return tags.ToArray();
				}
			}

			return null;
		}

		string[] GetTagsSplitted(string tags)
		{
			if (string.IsNullOrEmpty(tags))
				return Array.Empty<string>();
			else
				return tags.Split(new[] { ';', ',', ' ', '\t', '\n' }, StringSplitOptions.RemoveEmptyEntries);
		}

		IDictionary<string, object> GetLabels(LogEventInfo e)
		{
			if (Labels?.Count > 0)
			{
				IDictionary<string, object> labels = new Dictionary<string, object>();
				for (int i = 0; i < Labels?.Count; ++i)
				{
					var value = Labels[i].Layout?.Render(e);
					if (!string.IsNullOrEmpty(value) || Labels[i].IncludeEmptyValue)
					{
						PopulatePropertyBag(labels, Labels[i].Name, value);
					}
				}
				if (labels.Count > 0)
					return labels;
			}

			return null;
		}

		Event GetEvent(LogEventInfo e)
		{
			var eventCategory = EventCategory?.Render(logEvent);
			var eventSeverity = EventSeverity?.Render(logEvent);

			var evnt = new Event
			{
				Created = e.Timestamp,
				Category = !string.IsNullOrEmpty(eventCategory) ? new[] { eventCategory } : null,
				Action = EventAction?.Render(logEvent),
				Id = EventId?.Render(logEvent),
				Kind = EventKind?.Render(logEvent),
				Severity = !string.IsNullOrEmpty(eventSeverity) ? long.Parse(eventSeverity) : GetSysLogSeverity(e.LogLevel),
				Timezone = TimeZoneInfo.Local.StandardName,
			};

			//Why does this get overriden in full framework?
#if FULLFRAMEWORK
			evnt.Timezone = TimeZone.CurrentTimeZone.StandardName;
#endif
			return evnt;
		}

		private Agent GetAgent(LogEventInfo e)
		{
			var agentId = AgentId?.Render(e);
			var agentName = AgentName?.Render(e);
			var agentType = AgentType?.Render(e);
			var agentVersion = AgentVersion?.Render(e);
			if (string.IsNullOrEmpty(agentId) && string.IsNullOrEmpty(agentName) && string.IsNullOrEmpty(agentType) && string.IsNullOrEmpty(agentVersion))
				return null;

			var agent = new Agent
			{
				Id = agentId,
				Name = agentName,
				Type = agentType,
				Version = agentVersion,
			};

			return agent;
		}

		private Process GetProcess(LogEventInfo e)
        {
			var processId = ProcessId?.Render(e);
			var processName = ProcessName?.Render(e);
			var processTitle = ProcessTitle?.Render(e);
			var processExecutable = ProcessExecutable?.Render(e);
			var processThreadId = ProcessThreadId?.Render(e);
			if (string.IsNullOrEmpty(processId) && string.IsNullOrEmpty(processName) && string.IsNullOrEmpty(processTitle) && string.IsNullOrEmpty(processExecutable) && string.IsNullOrEmpty(processThreadId))
				return null;

			return new Process
			{
				Title = processTitle,
				Name = processName,
				Pid = !string.IsNullOrEmpty(processId) ? long.Parse(processId) : 0,
				Executable = processExecutable,
				Thread = !string.IsNullOrEmpty(processId) ? new ProcessThread { Id = long.Parse(processId) } : null,
			};
		}

		private Server GetServer(LogEventInfo e)

		{
			var serverUser = ServerUser?.Render(e);
			var serverAddress = ServerAddress?.Render(e);
			var serverIp = ServerIp?.Render(e);
			if (string.IsNullOrEmpty(serverUser) && string.IsNullOrEmpty(serverAddress) && string.IsNullOrEmpty(serverIp))
				return null;

			return new Server
			{
				User = !string.IsNullOrEmpty(serverUser) ? new User { Name = serverUser } : null,
				Address = serverAddress,
				Ip = serverIp,
			};
		}

		private Trace GetApmTraceId(LogEventInfo e)

		{
			var traceId = ApmTraceId?.Render(e);
			if (string.IsNullOrEmpty(traceId))
				return null;

			return new Trace { Id = traceId };
		}

		private Trace GetApmTransactionId(LogEventInfo e)
		{
			var transactionId = ApmTransactionId?.Render(e);
			if (string.IsNullOrEmpty(transactionId))
				return null;

			return new Transaction { Id = transactionId };
		}

		private Server GetHost(LogEventInfo e)
		{
			var hostId = HostId?.Render(e);
			var hostName = HostName?.Render(e);
			var hostIp = HostIp?.Render(e);
			if (string.IsNullOrEmpty(hostId) && string.IsNullOrEmpty(hostName) && string.IsNullOrEmpty(hostIp))
				return null;

			var host = new Host
			{
				Id = hostId,
				Name = hostName,
				Ip = hostIp,
			};

			//todo map more uptime etc
			return host;
		}

		private static long GetSysLogSeverity(LogLevel logLevel)
		{
			if (logLevel == LogLevel.Trace || logLevel == LogLevel.Debug)
				return 7;
			else if (logLevel == LogLevel.Info)
				return 6;
			else if (logLevel == LogLevel.Warn)
				return 4;
			else if (logLevel == LogLevel.Error)
				return 3;
			else
				return 2;   // LogLevel.Fatal
		}

		private static void PopulatePropertyBag(IDictionary<string, object> propertyBag, string key, object valueObj)
		{
			if (string.IsNullOrEmpty(key))
				return;

			if (propertyBag.ContainsKey(key))
			{
				if (string.Equals(value, propertyBag[key], StringComparison.Ordinal))
				{
					return;
				}

				key += "_1";
			}

			propertyBag.Add(key, value);
		}
	}
}

Many thanks for you insight here @snakefoot. I have updated the final layout (https://github.com/elastic/ecs-dotnet/blob/adb5c52692e3ff0975c12af7dad00d5d57696391/src/Elastic.CommonSchema.NLog/EcsLayout.cs) in a format similar to how you suggested. The tests seem happy, so I am going to move this to review by another member of the team.

@codebrain Happy to help. I guess if it lives up to your standards, then I might suggest adding support for IncludeMldc-property to handle MLDC. Will make an example soon.

Btw. it is important to add these attributes:
[Layout("EcsLayout")]
[ThreadSafe]
[ThreadAgnostic]

This tells NLog that the Layout has been implemented properly, and concurrency is allowed:
using NLog.Config;

[Layout("EcsLayout")]
[ThreadSafe]
[ThreadAgnostic]
public class EcsLayout : Layout
{
        private readonly Layout _disableThreadAgnostic = "${threadid:cached=true}";

        /// <summary>
        /// Special hack that allows one to dynamically disable disable <see cref="ThreadAgnosticAttribute"/> to ensure correct async context capture when necessary
        /// </summary>
        public Layout DisableThreadAgnostic => IncludeMdlc ? _disableThreadAgnostic : null;

        public bool IncludeMdlc { get; set; }

        private IDictionary<string, object> GetMetadata(LogEventInfo e)
	{
	   if ((!IncludeAllProperties || !e.HasProperties) && MetaData?.Count == 0 && !IncludeMdlc)
		return null;

	  var metaData = new Dictionary<string, object>();
	  if  (IncludeMdlc)
	  {
              foreach (string mdlcKey in NLog.MappedDiagnosticsLogicalContext.GetNames())
              {
                    if (string.IsNullOrEmpty(mdlcKey))
                        continue;

                    object propertyValue = MappedDiagnosticsLogicalContext.GetObject(key);
                    Populate(metaData, mdlcKey, propertyValue);
                }
	  }

	  if (e.HasProperties)
	  {
		foreach (var prop in e.Properties)
			Populate(metaData, prop.Key?.ToString(), prop.Value);
	  }

	  if (MetaData?.Count > 0)
	  {
		for (var i = 0; i < MetaData.Count; ++i)
		{
			var value = MetaData[i].Layout?.Render(e);
			if (!string.IsNullOrEmpty(value) || MetaData[i].IncludeEmptyValue)
				Populate(metaData, MetaData[i].Name, value);
		}
	  }

          if (metaData.Count > 0)
		return metaData;

	  return null;
	}
}

Thanks @snakefoot, I have updated the code as suggested.

cla/check

I have now merged this in @snakefoot. Thank you for your input on this feature!

Maybe try moving code used by both Serilog and NLog into the Common-project so they are in sync.
Forexample Serilog CatchErrors includes StackTrace for inner-exceptions But NLog CatchError does not.
Btw. since it is not possible to serialize directly into the StringBuilder, then you can simplify this method:
		protected override void RenderFormattedMessage(LogEventInfo logEventInfo, StringBuilder target)
                {
                        // blah blah
			var output = ecsEvent.Serialize();
                        target.Append(output);
                }

Into this:
		protected override string GetFormattedMessage(LogEventInfo logEvent)
		{
                        // blah blah
			var output = ecsEvent.Serialize();
                        return output;
		}

And remove the existing GetFormattedMessage
This you should change this:
		private static Log GetLog(LogEventInfo logEventInfo)
		{
			var log = new Log
			{
				Level = logEventInfo.Level.ToString(),
				Logger = SpecialKeys.DefaultLogger,
				Original = logEventInfo.Message
			};

			return log;
		}

Into this (Use logEventInfo.Logger instead of SpecialKeys.DefaultLogger):
		private static Log GetLog(LogEventInfo logEventInfo)
		{
			var log = new Log
			{
				Level = logEventInfo.Level.ToString(),
				Logger = logEventInfo.Logger,
				Original = logEventInfo.Message
			};

			return log;
		}

Thanks, I will raise this as a ticket so we can track it.


Be careful when using variables in path with **.

I have managed to delete a significant amount of files from my C drive, by specifying $(OutputDir)\**\*.* for a delete. It seems that  msbuild could not find $(OutputDir), so it just become \**\*.*, which tried to delete everything on the drive of the project, including half of program files, app data etc. resulting in a complete reinstall. Fortunately I had backup, but still wasted some time.
Maybe msbuild should fail in this case.

Document Details
⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

ID: 22b02536-b99d-e0f5-165c-40c041b2178d
Version Independent ID: 721b076f-0bab-642a-3754-fa7a2ad8f474
Content: Delete Task - Visual Studio
Content Source: docs/msbuild/delete-task.md
Product: visual-studio-windows
Technology: msbuild
GitHub Login: @Mikejo5000
Microsoft Alias: mikejo

I added a warning to this topic.  MSBuild is an open-source project, so someone could submit an issue or PR in the MSBuild GitHub repo https://github.com/Microsoft/msbuild to change the behavior to warn or fail in that situation.


Add a claim near to the Logo on the cover-page.

We would like to add a claim next to the logo on the cover-page. In my example:

© The H company, {YEAR}

Preview:

This is something I strongly recommend adding to the background image. One way to make that dynamic is to make the background image an SVG so that you can easily write text into it in a pre-generate step.
Another idea is to use the title logo to insert this graphic, which would be possible once #431 is implemented.
Aside from a background or title logo, I don't think design elements should be handled by the theme.

The idea to use svg for the logo and to customize it during the build is great. I have tried it (see commit 9d7bc68). The output looks like this:

I am wondering if there is any kind of limitation, because the original svg image looks like this:

The idea to use svg for the logo and to customize it during the build is great. I have tried it (see commit 9d7bc68). The output looks like this:

I am wondering if there is any kind of limitation, because the original svg image looks like this:

asciidoctor-pdf uses prawn-svg under the hood to render SVG images. it might just not support svg capabilies used in your svg image. I can suggest the following:

Look inside your svg image and try to identify what SVG elements are used for these incorrectly rendered parts (Inkscape can help you)
Replace them with SVG elements that supported by prawn-svg
If nothing helps submit an issue for prawn-svg element

The font used in the SVG has to match a font loaded in your theme. That's why it looks visually different. prawn-svg picks up any fonts loaded in Prawn (by way of the Asciidoctor PDF theme file). This is the same requirement anytime you use an SVG.


[RFC]: add @stdlib/array/base/cuevery

Description
This RFC proposes adding the package @stdlib/array/base/cuevery, which cumulatively tests whether every array element in a provided array is truthy. The function should return a new generic array. The package should also provide an #assign API for setting output values in a provided output array.
var x = [ true, true, true, false, true ];

var y1 = cuevery( x );
// returns [ true, true, true, false, false ]

var y2 = [ false, null, false, null, false, null, false, null, false, null ];
var out = cuevery.assign( x, y2, 2, 0 );
// returns [ true, null, true, null, true, null, false, null, false, null ]

where the assign API supports an offset and stride (see, e.g., @stdlib/array/base/take).
Both APIs should support accessor arrays (see, e.g., @stdlib/array/base/take).
Related Issues
No.
Questions
No.
Other
No.
Checklist

[X] I have read and understood the Code of Conduct.
[X] Searched for existing issues and pull requests.
[X] The issue name begins with RFC:.

@adityacodes30 Assigned.


[Hotfix][libinfo] Add "build*" path to dll_path to fix path issue on microtvm reference virtualbox

instead of only adding build to dll_path, this patch adds any directory starts with build to support build directories for microtvm RVM such as build-microtvm-zephyr and build-microtvm-arduino, etc.
This is currently breaking microtvm ci.
cc @areusch @leandron

the issue was due to vagrant ssh -c command which ssh doesn't source .bashrc and therefore TVM_LIBRARY_PATH was missing. Fixed it by sourcing .bashrc before each pytest command.


Water Sensors: PFF Indigo Brooke (280916)

R2B top sensor is offline.

Site is completely offline. (613)A reading -999 before offline.

no data for a while, asking to download again.

Available data downloaded at end of season.


Add explicit return types for plugins that define models, etc

I think this will help folks that want to contribute to the plugins with better type safety. I've seen a few errors go by (or almost go by) related to this.

@pavelgj friendly ping on this one